Skip to content
DNSPeekDocs

Developers

REST API v1 reference

Version 1.0 · Base URL https://api.dnspeek.link/api/v1

Create and manage DNSPeek preview links, run pre-launch QA reports and check DNS propagation from CI pipelines, hosting panels and scripts.

New to the API? Start with the API guide (keys, first requests, the GitHub Action). Machine-readable: OpenAPI 3 spec · Postman collection.

Authentication

Send 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.

Errors

Every 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.

Error codes
StatusCodeMeaning
400VALIDATION_FAILEDThe body or query is invalid; error.details.errors lists the problems
400INVALID_CURSORThe cursor was not issued by this API
400POLICY_*A workspace policy refused the change (e.g. POLICY_PASSWORD_REQUIRED)
401UNAUTHORIZEDMissing, unknown, rotated or revoked key
401API_KEY_EXPIREDThe key passed its expiry date
402PLAN_REQUIREDThe workspace plan has no API access
402QA_QUOTA_EXCEEDEDThe monthly QA report quota is used up
403API_KEY_SCOPEA read-only key called a write route
403API_KEY_IP_NOT_ALLOWEDThe request came from outside the key's allowed IPs
403LINK_BLOCKED_BY_SAFETY_CHECKDNSPeek blocked the link; it cannot be re-enabled or moved
404LINK_NOT_FOUNDNo link with that alias in the key’s workspace
404QA_REPORT_NOT_FOUNDNo QA report with that id in the key’s workspace
409CONFLICTThe alias is taken
409IDEMPOTENCY_KEY_IN_PROGRESSA request with the same Idempotency-Key is still running
422IDEMPOTENCY_KEY_REUSEDThe Idempotency-Key was used for a different request
429RATE_LIMITEDToo many requests for this key; wait Retry-After seconds
502UPSTREAM_UNAVAILABLEThe DNS checker did not answer; retry later

Pagination

List 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.

Idempotency

POST 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.

Rate limits

Per 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).

QA reports

Pre-launch crawls of the new server: score, verdict and findings

Get a QA report

get/api/v1/qa-reports/{id}Read-only keys allowed

Status and summary: score, verdict, finding counts and links to the full report.

Parameters
ParameterInDescription
idrequiredpathThe report id returned when the run started
curl
curl https://api.dnspeek.link/api/v1/qa-reports/id \
  -H "Authorization: Bearer $DNSPEEK_API_KEY"
Responses of Get a QA report
StatusDescription
200The report — V1QaReport
401UNAUTHORIZED (missing, unknown, rotated or revoked key) or API_KEY_EXPIRED — V1Error
402PLAN_REQUIRED: the workspace plan does not include API access — V1Error
403API_KEY_IP_NOT_ALLOWED / IP_NOT_ALLOWED (address not allowed) or API_KEY_SCOPE (read-only key on a write route) — V1Error
404QA_REPORT_NOT_FOUND (also for reports of other workspaces) — V1Error
423WORKSPACE_SUSPENDED — V1Error
429RATE_LIMITED: too many requests for this key; wait Retry-After seconds — V1Error

List QA reports of a link

get/api/v1/links/{alias}/qa-reportsRead-only keys allowed

Newest first, one page at a time.

Parameters
ParameterInDescription
aliasrequiredpathThe link alias (the subdomain of its preview URL)Example: shop-staging
limitqueryItems per page (1–100). Default: 100 for links, 20 for QA reports.Example: 20
cursorqueryThe nextCursor of the previous page; omit for the first (newest) page.Example: eyJ0IjoiMjAyNi0wOS0yOFQxMjowMDowMC4xMjM0NTZaIiwiaSI6IjNmYTg1ZjY0LTU3MTctNDU2Mi1iM2ZjLTJjOTYzZjY2YWZhNiJ9
curl
curl https://api.dnspeek.link/api/v1/links/shop-staging/qa-reports \
  -H "Authorization: Bearer $DNSPEEK_API_KEY"
Responses of List QA reports of a link
StatusDescription
200A page of QA reports — V1QaReportPage
400VALIDATION_FAILED or INVALID_CURSOR — V1Error
401UNAUTHORIZED (missing, unknown, rotated or revoked key) or API_KEY_EXPIRED — V1Error
402PLAN_REQUIRED: the workspace plan does not include API access — V1Error
403API_KEY_IP_NOT_ALLOWED / IP_NOT_ALLOWED (address not allowed) or API_KEY_SCOPE (read-only key on a write route) — V1Error
404LINK_NOT_FOUND — V1Error
423WORKSPACE_SUSPENDED — V1Error
429RATE_LIMITED: too many requests for this key; wait Retry-After seconds — V1Error

Run a QA report

post/api/v1/links/{alias}/qa-reportsNeeds a read and write key

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. The 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.

Parameters
ParameterInDescription
aliasrequiredpathThe link alias (the subdomain of its preview URL)Example: shop-staging
Idempotency-KeyheaderAny 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.

Request body (V1CreateQaReportDto)

Request body of Run a QA report
FieldTypeDescription
maxPagesnumber | nullPages to crawl; capped by the plan (402 above it). null = the plan maximum.
includePathsstring[]Only crawl discovered pages matching one of these root-relative globs (* = any characters except "/", ** = anything). The start page is always crawled.
excludePathsstring[]Never crawl discovered pages matching one of these globs.
viewportsstringdesktop (1280×800), mobile (390×844) or both (pages are revisited on mobile).One of: desktop, mobile, both
crawlSpeedstringgentle: one page at a time with a pause; normal: two in parallel; fast: four in parallel (plan feature).One of: gentle, normal, fast
respectRobotsTxtbooleanSkip pages robots.txt disallows for the DNSPeekQA user agent (default true). Only the site owner should turn this off.
compareWithLivebooleanFetch the current public site for the old vs new server comparison (default true).
activeProbesbooleanrobots.txt, sitemap, 404, canonical redirect and TLS probes of the new server (default true).
rerunAfterDnsSwitchbooleanRe-check the live domain automatically once DNS points at the new server (default true).
notifyOnCompletebooleanSend the "QA report ready / failed" notification (default true).
stagingAuthobjectCredentials for a password-protected staging site. Encrypted at rest, never returned, used only for the target site.
curl
curl -X POST https://api.dnspeek.link/api/v1/links/shop-staging/qa-reports \
  -H "Authorization: Bearer $DNSPEEK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"maxPages":25,"includePaths":["/blog/**"],"excludePaths":["/cart/**","/wp-admin/**"]}'
Responses of Run a QA report
StatusDescription
201The queued report — V1QaReport
400VALIDATION_FAILED: invalid run settings (path patterns, header name, missing staging secret) — V1Error
401UNAUTHORIZED (missing, unknown, rotated or revoked key) or API_KEY_EXPIRED — V1Error
402QA_QUOTA_EXCEEDED: the monthly QA report quota of the plan is used up (or the plan has none); PLAN_LIMIT: run settings beyond the plan (more pages than the plan allows, fast crawl) — V1Error
403API_KEY_IP_NOT_ALLOWED / IP_NOT_ALLOWED (address not allowed) or API_KEY_SCOPE (read-only key on a write route) — V1Error
404LINK_NOT_FOUND — V1Error
409IDEMPOTENCY_KEY_IN_PROGRESS — V1Error
422IDEMPOTENCY_KEY_REUSED — V1Error
423WORKSPACE_SUSPENDED — V1Error
429RATE_LIMITED: too many requests for this key; wait Retry-After seconds — V1Error
503SERVICE_UNAVAILABLE: background jobs are unavailable; retry later (the quota is not used) — V1Error

DNS

Propagation of a domain towards the new server

Check DNS propagation

get/api/v1/dns/propagationRead-only keys allowed

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.

Parameters
ParameterInDescription
domainrequiredqueryPublic domain to check (A record for an IPv4 expected_ip, AAAA for IPv6).Example: shop.example.com
expected_iprequiredqueryThe IP the domain should resolve to after the switch (public addresses only).Example: 203.0.113.10
curl
curl 'https://api.dnspeek.link/api/v1/dns/propagation?domain=shop.example.com&expected_ip=203.0.113.10' \
  -H "Authorization: Bearer $DNSPEEK_API_KEY"
Responses of Check DNS propagation
StatusDescription
200The current propagation snapshot — V1DnsPropagation
400VALIDATION_FAILED, or a non-public domain or IP — V1Error
401UNAUTHORIZED (missing, unknown, rotated or revoked key) or API_KEY_EXPIRED — V1Error
402PLAN_REQUIRED: the workspace plan does not include API access — V1Error
403API_KEY_IP_NOT_ALLOWED / IP_NOT_ALLOWED (address not allowed) or API_KEY_SCOPE (read-only key on a write route) — V1Error
423WORKSPACE_SUSPENDED — V1Error
429RATE_LIMITED: too many requests for this key; wait Retry-After seconds — V1Error
502UPSTREAM_UNAVAILABLE: the DNS checker did not answer; retry later — V1Error

Schemas

V1ErrorDetail

Fields of V1ErrorDetail
FieldTypeDescription
coderequiredstringStable, machine-readable error code (docs/api/v1.md § Errors).
messagerequiredstringHuman-readable explanation; may change, do not parse it.
detailsobjectExtra fields of this error, e.g. errors (validation), required (scope), retryAfter.

V1Error

Fields of V1Error
FieldTypeDescription
errorrequiredV1ErrorDetail
statusCoderequirednumberHTTP status (kept at the top level for early v1 clients).
coderequiredstringSame as error.code (kept for early v1 clients).
messagerequiredstringSame as error.message (kept for early v1 clients).

V1TargetHint

Fields of V1TargetHint
FieldTypeDescription
kindrequiredstringOne of: hosted-builder
platformrequiredstring
messagerequiredstring
previewUrlrequiredstring
docsUrlrequiredstring

QaStagingAuthInput

Fields of QaStagingAuthInput
FieldTypeDescription
typerequiredstringnone removes the credentials; basic = HTTP Basic auth; header = one request header; cookie = one cookie. Sent only to the link's domain (and its www twin) on the new server.One of: none, basic, header, cookie
usernamestringbasic: the username (no ":").
passwordstringbasic: the password. Omit to keep the saved one (same username). Never returned.
namestringheader: the header name (Host, Cookie, transport and forwarding headers are refused); cookie: the cookie name.
valuestringheader / cookie: the value. Omit to keep the saved one (same name). Never returned.

V1CreateQaReportDto

Fields of V1CreateQaReportDto
FieldTypeDescription
maxPagesnumber | nullPages to crawl; capped by the plan (402 above it). null = the plan maximum.
includePathsstring[]Only crawl discovered pages matching one of these root-relative globs (* = any characters except "/", ** = anything). The start page is always crawled.
excludePathsstring[]Never crawl discovered pages matching one of these globs.
viewportsstringdesktop (1280×800), mobile (390×844) or both (pages are revisited on mobile).One of: desktop, mobile, both
crawlSpeedstringgentle: one page at a time with a pause; normal: two in parallel; fast: four in parallel (plan feature).One of: gentle, normal, fast
respectRobotsTxtbooleanSkip pages robots.txt disallows for the DNSPeekQA user agent (default true). Only the site owner should turn this off.
compareWithLivebooleanFetch the current public site for the old vs new server comparison (default true).
activeProbesbooleanrobots.txt, sitemap, 404, canonical redirect and TLS probes of the new server (default true).
rerunAfterDnsSwitchbooleanRe-check the live domain automatically once DNS points at the new server (default true).
notifyOnCompletebooleanSend the "QA report ready / failed" notification (default true).
stagingAuthobjectCredentials for a password-protected staging site. Encrypted at rest, never returned, used only for the target site.

V1QaCounts

Fields of V1QaCounts
FieldTypeDescription
totalrequirednumber
criticalrequirednumber
warningrequirednumber
inforequirednumber
pagesCrawledrequirednumber
pagesWithErrorsrequirednumber
truncatedrequiredbooleanThe crawl budget ran out before every discovered page was visited.

V1QaStagingAuthUsed

Fields of V1QaStagingAuthUsed
FieldTypeDescription
typerequiredstringOne of: none, basic, header, cookie
usernamestringbasic: the username (never the password).
namestringheader / cookie: its name (never the value).

V1QaReportSettings

Fields of V1QaReportSettings
FieldTypeDescription
maxPagesrequirednumberPage budget the crawl used (after the plan cap).
includePathsrequiredstring[]
excludePathsrequiredstring[]
viewportsrequiredstringOne of: desktop, mobile, both
crawlSpeedrequiredstringOne of: gentle, normal, fast
respectRobotsTxtrequiredboolean
compareWithLiverequiredboolean
activeProbesrequiredboolean
rerunAfterDnsSwitchrequiredboolean
notifyOnCompleterequiredboolean
stagingAuthrequiredobjectKind of staging credentials used; secrets are never returned.

V1QaReport

Fields of V1QaReport
FieldTypeDescription
idrequiredstring (uuid)
linkrequiredV1QaReportLink
statusrequiredstringPoll until completed or failed (a run takes about 1–5 minutes).One of: queued, running, completed, failed
scorerequirednumber | null
verdictrequiredstring | nullCompleted reports: not_ready with any critical finding, ready_with_warnings with any warning, else ready.One of: ready, ready_with_warnings, not_ready
countsrequiredobject | null
errorrequiredstring | nullWhy a failed run failed.
createdAtrequiredstring (date-time)
completedAtrequiredstring (date-time) | null
reportUrlrequiredstringFull report in the dashboard (sign-in required).
shareUrlrequiredstringRead-only report anyone with the link can open.
settingsrequiredobject | nullRun settings the crawl used (no secrets); null for reports created before run settings existed.

V1QaReportPage

Fields of V1QaReportPage
FieldTypeDescription
itemsrequiredV1QaReport[]
totalrequirednumber
limitrequirednumber
nextCursorrequiredstring | null

V1Resolver

Fields of V1Resolver
FieldTypeDescription
resolverrequiredstring
locationrequiredstring
addressrequiredstring
answersrequiredstring[]
ttlrequirednumber | null
matchedrequiredbooleanThe resolver already returns expected_ip (matchMode network: only addresses of that CDN).
cdnstringSet when every address the resolver returned belongs to this CDN.One of: cloudflare
errorstring

V1DnsPropagation

Fields of V1DnsPropagation
FieldTypeDescription
domainrequiredstring
expectedIprequiredstring
recordTyperequiredstringOne of: A, AAAA
percentrequirednumberShare of answering resolvers that return expected_ip.
matchedrequirednumber
answeredrequirednumberResolvers that answered without error (the percent denominator).
totalrequirednumber
maxTtlrequirednumber | nullHighest TTL seen: caches may keep the old IP this many seconds.
propagatedrequiredbooleanpercent ≥ thresholdPercent with at least half of the resolvers answering.
thresholdPercentrequirednumber
matchModerequiredstringnetwork when expected_ip is a CDN edge (Cloudflare): edges differ per region, so a resolver matches when every address it returns is on that CDN. exact otherwise.One of: exact, network
cdnrequiredstring | nullThe CDN of expected_ip, or the CDN the domain is proxied through.One of: cloudflare
proxiedrequiredbooleanexpected_ip is an origin server, but every resolver returns the CDN's addresses: the domain is behind the CDN proxy, so DNS cannot show a change of origin and percent stays 0.
checkedAtrequiredstring (date-time)
resolversrequiredV1Resolver[]
cachedrequiredbooleanServed from the 60-second cache of the same domain and IP.