{"info":{"name":"DNSPeek REST API v1","description":"Create and manage DNSPeek preview links, run pre-launch QA reports and check DNS propagation from CI pipelines, hosting panels and scripts.\n\n## Authentication\nSend a workspace API key as a bearer token: `Authorization: Bearer dpk_<prefix>_<secret>`. Create keys on the API Keys page of the dashboard (plans with API access). A key acts in its workspace as the member who created it. **Read-only** keys can call GET routes only; other routes answer 403 `API_KEY_SCOPE`.\n\n## Errors\nEvery error has the same body: `{ \"error\": { \"code\": \"LINK_NOT_FOUND\", \"message\": \"…\", \"details\": { … } } }`. Branch on `error.code` (stable); `error.message` is for people. The body also repeats `statusCode`, `code` and `message` at the top level for early v1 clients.\n\n## Pagination\nList routes return `{ items, total, limit, nextCursor }`, newest first. Pass `nextCursor` back as `?cursor=` for the next page; it is `null` on the last page. `limit` is 1–100.\n\n## Idempotency\nPOST routes accept an optional `Idempotency-Key` header (for example a UUID). Retrying with the same key and body within 24 hours returns the first response with `Idempotency-Replayed: true` instead of creating a second link or QA run. The same key with a different body answers 422 `IDEMPOTENCY_KEY_REUSED`.\n\n## Rate limits\nPer key and route, by the plan of the key's workspace: Pro 60, Agency 300, Provider 1,000 requests per minute (DNS propagation: 10 per minute on every plan). Every response carries `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset`; over the limit the API answers 429 `RATE_LIMITED` with `Retry-After` (seconds).","schema":"https://schema.getpostman.com/json/collection/v2.1.0/collection.json"},"auth":{"type":"bearer","bearer":[{"key":"token","value":"{{apiKey}}","type":"string"}]},"variable":[{"key":"baseUrl","value":"https://api.dnspeek.link","description":"DNSPeek API origin"},{"key":"apiKey","value":"","description":"Workspace API key (dpk_…), from the API Keys page"}],"item":[{"name":"Links","description":"Preview links: a site on a new server, served before the DNS switch","item":[{"name":"List links","request":{"method":"GET","description":"Links of the key's workspace, newest first, one page at a time: links shared with the workspace plus the private links of the key's creator. Optionally only one space (`space`) or links matching a search (`q`); `total` counts the filtered set.","header":[],"url":{"raw":"{{baseUrl}}/api/v1/links","host":["{{baseUrl}}"],"path":["api","v1","links"],"query":[{"key":"limit","value":"20","description":"Items per page (1–100). Default: 100 for links, 20 for QA reports.","disabled":true},{"key":"cursor","value":"eyJ0IjoiMjAyNi0wOS0yOFQxMjowMDowMC4xMjM0NTZaIiwiaSI6IjNmYTg1ZjY0LTU3MTctNDU2Mi1iM2ZjLTJjOTYzZjY2YWZhNiJ9","description":"The `nextCursor` of the previous page; omit for the first (newest) page.","disabled":true},{"key":"space","value":"none","description":"Only the links of this space (its id, `spaceId` on a link), or `none` for links in no space. 404 SPACE_NOT_FOUND for an id that is not a space of the key's workspace. Keep the same value while following `nextCursor`.","disabled":true},{"key":"q","value":"shop","description":"Search, case-insensitive and trimmed: links whose alias, targetDomain, targetIp or liveDomain contains this text (`%` and `_` match literally). Keep the same value while following `nextCursor`.","disabled":true}]}}},{"name":"Create a link","request":{"method":"POST","description":"Creates a preview link of `targetDomain` served from `targetIp`. The server check and the security scan start in the background.","header":[{"key":"Content-Type","value":"application/json","disabled":false},{"key":"Idempotency-Key","value":"{{$guid}}","description":"Any unique string (e.g. a UUID), 1–255 visible ASCII characters. A retry with the same key and body within 24 hours returns the first response (header `Idempotency-Replayed: true`) instead of acting twice; the same key with a different body is 422 IDEMPOTENCY_KEY_REUSED.","disabled":true}],"url":{"raw":"{{baseUrl}}/api/v1/links","host":["{{baseUrl}}"],"path":["api","v1","links"]},"body":{"mode":"raw","raw":"{\n  \"spaceId\": \"\",\n  \"targetDomain\": \"example.com\",\n  \"targetIp\": \"93.184.216.34\",\n  \"alias\": \"my-preview\",\n  \"httpPort\": 0,\n  \"httpsPort\": 0,\n  \"sslMode\": \"auto\",\n  \"password\": \"\",\n  \"expiresAt\": \"\",\n  \"visibility\": \"workspace\",\n  \"liveDomain\": \"old-domain.com\",\n  \"liveIp\": \"192.33.4.12\",\n  \"interstitialDisabled\": false,\n  \"wildcard\": false\n}","options":{"raw":{"language":"json"}}}}},{"name":"Get a link","request":{"method":"GET","description":"The link with its preview URL, status, settings, latest server check and security result.","header":[],"url":{"raw":"{{baseUrl}}/api/v1/links/:alias","host":["{{baseUrl}}"],"path":["api","v1","links",":alias"],"variable":[{"key":"alias","value":"shop-staging","description":"The link alias (the subdomain of its preview URL)"}]}}},{"name":"Update a link","request":{"method":"PATCH","description":"Turns the preview on or off, sets or removes the password and the expiry, moves it to another server or to another space. Only the fields you send change. A new target re-runs the server check.","header":[{"key":"Content-Type","value":"application/json","disabled":false}],"url":{"raw":"{{baseUrl}}/api/v1/links/:alias","host":["{{baseUrl}}"],"path":["api","v1","links",":alias"],"variable":[{"key":"alias","value":"shop-staging","description":"The link alias (the subdomain of its preview URL)"}]},"body":{"mode":"raw","raw":"{\n  \"enabled\": false\n}","options":{"raw":{"language":"json"}}}}},{"name":"Delete a link","request":{"method":"DELETE","description":"Members can delete only links they created; owners and admins any link.","header":[],"url":{"raw":"{{baseUrl}}/api/v1/links/:alias","host":["{{baseUrl}}"],"path":["api","v1","links",":alias"],"variable":[{"key":"alias","value":"shop-staging","description":"The link alias (the subdomain of its preview URL)"}]}}}]},{"name":"QA reports","description":"Pre-launch crawls of the new server: score, verdict and findings","item":[{"name":"List QA reports of a link","request":{"method":"GET","description":"Newest first, one page at a time.","header":[],"url":{"raw":"{{baseUrl}}/api/v1/links/:alias/qa-reports","host":["{{baseUrl}}"],"path":["api","v1","links",":alias","qa-reports"],"query":[{"key":"limit","value":"20","description":"Items per page (1–100). Default: 100 for links, 20 for QA reports.","disabled":true},{"key":"cursor","value":"eyJ0IjoiMjAyNi0wOS0yOFQxMjowMDowMC4xMjM0NTZaIiwiaSI6IjNmYTg1ZjY0LTU3MTctNDU2Mi1iM2ZjLTJjOTYzZjY2YWZhNiJ9","description":"The `nextCursor` of the previous page; omit for the first (newest) page.","disabled":true}],"variable":[{"key":"alias","value":"shop-staging","description":"The link alias (the subdomain of its preview URL)"}]}}},{"name":"Run a QA report","request":{"method":"POST","description":"Crawls the site on the link's new server (as the preview does) and builds a pre-launch QA report: broken pages, mixed content, redirects, SEO and security findings. Uses one QA report of the workspace's monthly quota. Poll GET /v1/qa-reports/{id} until `status` is completed or failed.\n\nThe optional body sets run settings (page budget, path filters, viewports, speed, robots.txt, live comparison, probes, notifications, staging credentials); fields left out use the link's default run settings from the dashboard. Staging credentials are encrypted at rest, never returned, and sent only to the link's domain on the new server.","header":[{"key":"Content-Type","value":"application/json","disabled":false},{"key":"Idempotency-Key","value":"{{$guid}}","description":"Any unique string (e.g. a UUID), 1–255 visible ASCII characters. A retry with the same key and body within 24 hours returns the first response (header `Idempotency-Replayed: true`) instead of acting twice; the same key with a different body is 422 IDEMPOTENCY_KEY_REUSED.","disabled":true}],"url":{"raw":"{{baseUrl}}/api/v1/links/:alias/qa-reports","host":["{{baseUrl}}"],"path":["api","v1","links",":alias","qa-reports"],"variable":[{"key":"alias","value":"shop-staging","description":"The link alias (the subdomain of its preview URL)"}]},"body":{"mode":"raw","raw":"{\n  \"maxPages\": 25,\n  \"includePaths\": [\n    \"/blog/**\"\n  ],\n  \"excludePaths\": [\n    \"/cart/**\",\n    \"/wp-admin/**\"\n  ],\n  \"viewports\": \"desktop\",\n  \"crawlSpeed\": \"gentle\",\n  \"respectRobotsTxt\": false,\n  \"compareWithLive\": false,\n  \"activeProbes\": false,\n  \"rerunAfterDnsSwitch\": false,\n  \"notifyOnComplete\": false,\n  \"stagingAuth\": {\n    \"type\": \"none\",\n    \"username\": \"staging\",\n    \"password\": \"\",\n    \"name\": \"X-Staging-Token\",\n    \"value\": \"\"\n  }\n}","options":{"raw":{"language":"json"}}}}},{"name":"Get a QA report","request":{"method":"GET","description":"Status and summary: score, verdict, finding counts and links to the full report.","header":[],"url":{"raw":"{{baseUrl}}/api/v1/qa-reports/:id","host":["{{baseUrl}}"],"path":["api","v1","qa-reports",":id"],"variable":[{"key":"id","value":"","description":"The report id returned when the run started"}]}}}]},{"name":"DNS","description":"Propagation of a domain towards the new server","item":[{"name":"Check DNS propagation","request":{"method":"GET","description":"Asks public resolvers worldwide whether `domain` already resolves to `expected_ip` right now. Results for the same domain and IP are cached for 60 seconds. Limited to 10 checks per minute per key.","header":[],"url":{"raw":"{{baseUrl}}/api/v1/dns/propagation?domain=shop.example.com&expected_ip=203.0.113.10","host":["{{baseUrl}}"],"path":["api","v1","dns","propagation"],"query":[{"key":"domain","value":"shop.example.com","description":"Public domain to check (A record for an IPv4 expected_ip, AAAA for IPv6).","disabled":false},{"key":"expected_ip","value":"203.0.113.10","description":"The IP the domain should resolve to after the switch (public addresses only).","disabled":false}]}}}]}]}