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.
| Status | Code | Meaning |
|---|---|---|
| 400 | VALIDATION_FAILED | The body or query is invalid; error.details.errors lists the problems |
| 400 | INVALID_CURSOR | The cursor was not issued by this API |
| 400 | POLICY_* | A workspace policy refused the change (e.g. POLICY_PASSWORD_REQUIRED) |
| 401 | UNAUTHORIZED | Missing, unknown, rotated or revoked key |
| 401 | API_KEY_EXPIRED | The key passed its expiry date |
| 402 | PLAN_REQUIRED | The workspace plan has no API access |
| 402 | QA_QUOTA_EXCEEDED | The monthly QA report quota is used up |
| 403 | API_KEY_SCOPE | A read-only key called a write route |
| 403 | API_KEY_IP_NOT_ALLOWED | The request came from outside the key's allowed IPs |
| 403 | LINK_BLOCKED_BY_SAFETY_CHECK | DNSPeek blocked the link; it cannot be re-enabled or moved |
| 404 | LINK_NOT_FOUND | No link with that alias in the key’s workspace |
| 404 | QA_REPORT_NOT_FOUND | No QA report with that id in the key’s workspace |
| 409 | CONFLICT | The alias is taken |
| 409 | IDEMPOTENCY_KEY_IN_PROGRESS | A request with the same Idempotency-Key is still running |
| 422 | IDEMPOTENCY_KEY_REUSED | The Idempotency-Key was used for a different request |
| 429 | RATE_LIMITED | Too many requests for this key; wait Retry-After seconds |
| 502 | UPSTREAM_UNAVAILABLE | The 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).
Links
Preview links: a site on a new server, served before the DNS switch
List links
get/api/v1/linksRead-only keys allowed
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.
| Parameter | In | Description |
|---|---|---|
limit | query | Items per page (1–100). Default: 100 for links, 20 for QA reports.Example: 20 |
cursor | query | The nextCursor of the previous page; omit for the first (newest) page.Example: eyJ0IjoiMjAyNi0wOS0yOFQxMjowMDowMC4xMjM0NTZaIiwiaSI6IjNmYTg1ZjY0LTU3MTctNDU2Mi1iM2ZjLTJjOTYzZjY2YWZhNiJ9 |
space | query | 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.Example: none |
q | query | 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.Example: shop |
curl https://api.dnspeek.link/api/v1/links \
-H "Authorization: Bearer $DNSPEEK_API_KEY"| Status | Description |
|---|---|
200 | A page of links — V1LinkPage |
400 | VALIDATION_FAILED or INVALID_CURSOR — V1Error |
401 | UNAUTHORIZED (missing, unknown, rotated or revoked key) or API_KEY_EXPIRED — V1Error |
402 | PLAN_REQUIRED: the workspace plan does not include API access — V1Error |
403 | API_KEY_IP_NOT_ALLOWED / IP_NOT_ALLOWED (address not allowed) or API_KEY_SCOPE (read-only key on a write route) — V1Error |
404 | SPACE_NOT_FOUND: space is not a space of the key's workspace — V1Error |
423 | WORKSPACE_SUSPENDED — V1Error |
429 | RATE_LIMITED: too many requests for this key; wait Retry-After seconds — V1Error |
Create a link
post/api/v1/linksNeeds a read and write key
Creates a preview link of targetDomain served from targetIp. The server check and the security scan start in the background.
| Parameter | In | Description |
|---|---|---|
Idempotency-Key | header | 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. |
Request body (CreateLinkDto)
| Field | Type | Description |
|---|---|---|
spaceId | string (uuid) | One of your spaces; not available to guests |
targetDomainrequired | string | |
targetIprequired | string | |
alias | string | |
httpPort | number | |
httpsPort | number | |
sslMode | string | How the proxy connects to the target server. auto: HTTPS, falling back to plain HTTP; verify: HTTPS with a trusted certificate only; skip: HTTPS without certificate verification (self-signed); off: plain HTTP only, for an origin without SSL (visitors still get HTTPS; the origin receives X-Forwarded-Proto: https).One of: auto, skip, verify, off |
password | string | Optional password to protect preview |
expiresAt | string | ISO8601 expiry date |
visibility | string | workspace: every member of the workspace sees the link; private: only you (its creator) see it in the dashboard and API. Preview URLs work for anyone with the link either way.One of: workspace, private |
liveDomain | string | null | Old site address for Live compare, Find differences and visual compares: the domain the old server serves the site on (for example before a rebrand). Hostname only, no scheme or path. Null or absent: the old side opens targetDomain via public DNS. |
liveIp | string | null | Optional IP of the old server (public addresses only) used for liveDomain instead of public DNS. Requires liveDomain (400 LIVE_IP_REQUIRES_DOMAIN otherwise). |
interstitialDisabled | boolean | true: visitors open the preview directly, without the DNSPeek notice "Preview of <domain> on a new server". Paid plans only (402 otherwise); guest and Free links always show the notice. |
wildcard | boolean | Also preview every subdomain of targetDomain (WordPress multisite, shop. or blog. hosts) as <sub>---<alias>.<preview domain>, served from the same targetIp. Pro plan and up (402 otherwise); not available to guests. |
curl -X POST https://api.dnspeek.link/api/v1/links \
-H "Authorization: Bearer $DNSPEEK_API_KEY" \
-H "Content-Type: application/json" \
-d '{"targetDomain":"example.com","targetIp":"93.184.216.34"}'| Status | Description |
|---|---|
201 | The new link — V1CreatedLink |
400 | VALIDATION_FAILED, a private or invalid IP, a blocked target, or a POLICY_* workspace rule — V1Error |
401 | UNAUTHORIZED (missing, unknown, rotated or revoked key) or API_KEY_EXPIRED — V1Error |
402 | PLAN_REQUIRED: the workspace plan does not include API access — V1Error |
403 | API_KEY_IP_NOT_ALLOWED / IP_NOT_ALLOWED (address not allowed) or API_KEY_SCOPE (read-only key on a write route) — V1Error |
409 | CONFLICT: the alias is taken; or IDEMPOTENCY_KEY_IN_PROGRESS — V1Error |
422 | IDEMPOTENCY_KEY_REUSED — V1Error |
423 | WORKSPACE_SUSPENDED — V1Error |
429 | RATE_LIMITED: too many requests for this key; wait Retry-After seconds — V1Error |
Get a link
get/api/v1/links/{alias}Read-only keys allowed
The link with its preview URL, status, settings, latest server check and security result.
| Parameter | In | Description |
|---|---|---|
aliasrequired | path | The link alias (the subdomain of its preview URL)Example: shop-staging |
curl https://api.dnspeek.link/api/v1/links/shop-staging \
-H "Authorization: Bearer $DNSPEEK_API_KEY"| Status | Description |
|---|---|
200 | The link — V1Link |
401 | UNAUTHORIZED (missing, unknown, rotated or revoked key) or API_KEY_EXPIRED — V1Error |
402 | PLAN_REQUIRED: the workspace plan does not include API access — V1Error |
403 | API_KEY_IP_NOT_ALLOWED / IP_NOT_ALLOWED (address not allowed) or API_KEY_SCOPE (read-only key on a write route) — V1Error |
404 | LINK_NOT_FOUND (also for links of other workspaces and other members' private links) — V1Error |
423 | WORKSPACE_SUSPENDED — V1Error |
429 | RATE_LIMITED: too many requests for this key; wait Retry-After seconds — V1Error |
Update a link
patch/api/v1/links/{alias}Needs a read and write key
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.
| Parameter | In | Description |
|---|---|---|
aliasrequired | path | The link alias (the subdomain of its preview URL)Example: shop-staging |
Request body (V1UpdateLinkDto)
| Field | Type | Description |
|---|---|---|
enabled | boolean | false turns the preview off, true turns it back on (not possible for links DNSPeek blocked: 403 LINK_BLOCKED_BY_SAFETY_CHECK). |
password | string | null | New visitor password; null removes it (400 POLICY_PASSWORD_REQUIRED when a workspace policy requires one). |
expiresAt | string (date-time) | null | New expiry (ISO 8601); null removes it. Plan limits and workspace policies apply, measured from link creation. |
targetIp | string | New target server IP (public addresses only; re-runs the server check and the security scan). |
liveDomain | string | null | Old site address for Live compare, Find differences and visual compares: the domain the old server serves the site on (e.g. before a rebrand). null clears it (400 LIVE_IP_REQUIRES_DOMAIN while liveIp stays set); 400 LIVE_DOMAIN_INVALID for anything but a public hostname. |
liveIp | string | null | IP of the old server used for liveDomain instead of public DNS (public addresses only). null clears it. Requires liveDomain (400 LIVE_IP_REQUIRES_DOMAIN). |
httpPort | number | |
httpsPort | number | |
sslMode | string | How the proxy connects to the target server: auto, verify, skip (no certificate verification) or off (plain HTTP only, for an origin without SSL).One of: auto, skip, verify, off |
visibility | string | private: only the link's creator sees it in the dashboard and API; workspace: every member does. Only the creator can change it (403 otherwise). The preview URL works either way.One of: workspace, private |
wildcard | boolean | true: the link also previews every subdomain of targetDomain as <sub>---<alias>.<preview domain> (Pro plan and up; 402 PLAN_REQUIRED otherwise). false turns it off on any plan. |
spaceId | string (uuid) | null | Move the link to this space of the workspace (404 SPACE_NOT_FOUND otherwise); null takes it out of its space. |
curl -X PATCH https://api.dnspeek.link/api/v1/links/shop-staging \
-H "Authorization: Bearer $DNSPEEK_API_KEY" \
-H "Content-Type: application/json" \
-d '{"enabled":false}'| Status | Description |
|---|---|
200 | The updated link — V1Link |
400 | VALIDATION_FAILED (also for an empty body), a private or invalid IP, a blocked target, LIVE_DOMAIN_INVALID / LIVE_IP_REQUIRES_DOMAIN, or a POLICY_* workspace rule — V1Error |
401 | UNAUTHORIZED (missing, unknown, rotated or revoked key) or API_KEY_EXPIRED — V1Error |
402 | PLAN_REQUIRED: the workspace plan does not include API access — V1Error |
403 | API_KEY_IP_NOT_ALLOWED / IP_NOT_ALLOWED, API_KEY_SCOPE (read-only key), LINK_BLOCKED_BY_SAFETY_CHECK, or FORBIDDEN: changing visibility of a link someone else created — V1Error |
404 | LINK_NOT_FOUND, or SPACE_NOT_FOUND for a spaceId that is not a space of the workspace — V1Error |
423 | WORKSPACE_SUSPENDED — V1Error |
429 | RATE_LIMITED: too many requests for this key; wait Retry-After seconds — V1Error |
Delete a link
delete/api/v1/links/{alias}Needs a read and write key
Members can delete only links they created; owners and admins any link.
| Parameter | In | Description |
|---|---|---|
aliasrequired | path | The link alias (the subdomain of its preview URL)Example: shop-staging |
curl -X DELETE https://api.dnspeek.link/api/v1/links/shop-staging \
-H "Authorization: Bearer $DNSPEEK_API_KEY"| Status | Description |
|---|---|
200 | Deleted (empty body) |
401 | UNAUTHORIZED (missing, unknown, rotated or revoked key) or API_KEY_EXPIRED — V1Error |
402 | PLAN_REQUIRED: the workspace plan does not include API access — V1Error |
403 | API_KEY_IP_NOT_ALLOWED / IP_NOT_ALLOWED (address not allowed) or API_KEY_SCOPE (read-only key on a write route) — V1Error |
404 | LINK_NOT_FOUND — V1Error |
423 | WORKSPACE_SUSPENDED — V1Error |
429 | RATE_LIMITED: too many requests for this key; wait Retry-After seconds — V1Error |
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.
| Parameter | In | Description |
|---|---|---|
idrequired | path | The report id returned when the run started |
curl https://api.dnspeek.link/api/v1/qa-reports/id \
-H "Authorization: Bearer $DNSPEEK_API_KEY"| Status | Description |
|---|---|
200 | The report — V1QaReport |
401 | UNAUTHORIZED (missing, unknown, rotated or revoked key) or API_KEY_EXPIRED — V1Error |
402 | PLAN_REQUIRED: the workspace plan does not include API access — V1Error |
403 | API_KEY_IP_NOT_ALLOWED / IP_NOT_ALLOWED (address not allowed) or API_KEY_SCOPE (read-only key on a write route) — V1Error |
404 | QA_REPORT_NOT_FOUND (also for reports of other workspaces) — V1Error |
423 | WORKSPACE_SUSPENDED — V1Error |
429 | RATE_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.
| Parameter | In | Description |
|---|---|---|
aliasrequired | path | The link alias (the subdomain of its preview URL)Example: shop-staging |
limit | query | Items per page (1–100). Default: 100 for links, 20 for QA reports.Example: 20 |
cursor | query | The nextCursor of the previous page; omit for the first (newest) page.Example: eyJ0IjoiMjAyNi0wOS0yOFQxMjowMDowMC4xMjM0NTZaIiwiaSI6IjNmYTg1ZjY0LTU3MTctNDU2Mi1iM2ZjLTJjOTYzZjY2YWZhNiJ9 |
curl https://api.dnspeek.link/api/v1/links/shop-staging/qa-reports \
-H "Authorization: Bearer $DNSPEEK_API_KEY"| Status | Description |
|---|---|
200 | A page of QA reports — V1QaReportPage |
400 | VALIDATION_FAILED or INVALID_CURSOR — V1Error |
401 | UNAUTHORIZED (missing, unknown, rotated or revoked key) or API_KEY_EXPIRED — V1Error |
402 | PLAN_REQUIRED: the workspace plan does not include API access — V1Error |
403 | API_KEY_IP_NOT_ALLOWED / IP_NOT_ALLOWED (address not allowed) or API_KEY_SCOPE (read-only key on a write route) — V1Error |
404 | LINK_NOT_FOUND — V1Error |
423 | WORKSPACE_SUSPENDED — V1Error |
429 | RATE_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.
| Parameter | In | Description |
|---|---|---|
aliasrequired | path | The link alias (the subdomain of its preview URL)Example: shop-staging |
Idempotency-Key | header | 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. |
Request body (V1CreateQaReportDto)
| Field | Type | Description |
|---|---|---|
maxPages | number | null | Pages to crawl; capped by the plan (402 above it). null = the plan maximum. |
includePaths | string[] | Only crawl discovered pages matching one of these root-relative globs (* = any characters except "/", ** = anything). The start page is always crawled. |
excludePaths | string[] | Never crawl discovered pages matching one of these globs. |
viewports | string | desktop (1280×800), mobile (390×844) or both (pages are revisited on mobile).One of: desktop, mobile, both |
crawlSpeed | string | gentle: one page at a time with a pause; normal: two in parallel; fast: four in parallel (plan feature).One of: gentle, normal, fast |
respectRobotsTxt | boolean | Skip pages robots.txt disallows for the DNSPeekQA user agent (default true). Only the site owner should turn this off. |
compareWithLive | boolean | Fetch the current public site for the old vs new server comparison (default true). |
activeProbes | boolean | robots.txt, sitemap, 404, canonical redirect and TLS probes of the new server (default true). |
rerunAfterDnsSwitch | boolean | Re-check the live domain automatically once DNS points at the new server (default true). |
notifyOnComplete | boolean | Send the "QA report ready / failed" notification (default true). |
stagingAuth | object | Credentials for a password-protected staging site. Encrypted at rest, never returned, used only for the target site. |
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/**"]}'| Status | Description |
|---|---|
201 | The queued report — V1QaReport |
400 | VALIDATION_FAILED: invalid run settings (path patterns, header name, missing staging secret) — V1Error |
401 | UNAUTHORIZED (missing, unknown, rotated or revoked key) or API_KEY_EXPIRED — V1Error |
402 | QA_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 |
403 | API_KEY_IP_NOT_ALLOWED / IP_NOT_ALLOWED (address not allowed) or API_KEY_SCOPE (read-only key on a write route) — V1Error |
404 | LINK_NOT_FOUND — V1Error |
409 | IDEMPOTENCY_KEY_IN_PROGRESS — V1Error |
422 | IDEMPOTENCY_KEY_REUSED — V1Error |
423 | WORKSPACE_SUSPENDED — V1Error |
429 | RATE_LIMITED: too many requests for this key; wait Retry-After seconds — V1Error |
503 | SERVICE_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.
| Parameter | In | Description |
|---|---|---|
domainrequired | query | Public domain to check (A record for an IPv4 expected_ip, AAAA for IPv6).Example: shop.example.com |
expected_iprequired | query | The IP the domain should resolve to after the switch (public addresses only).Example: 203.0.113.10 |
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"| Status | Description |
|---|---|
200 | The current propagation snapshot — V1DnsPropagation |
400 | VALIDATION_FAILED, or a non-public domain or IP — V1Error |
401 | UNAUTHORIZED (missing, unknown, rotated or revoked key) or API_KEY_EXPIRED — V1Error |
402 | PLAN_REQUIRED: the workspace plan does not include API access — V1Error |
403 | API_KEY_IP_NOT_ALLOWED / IP_NOT_ALLOWED (address not allowed) or API_KEY_SCOPE (read-only key on a write route) — V1Error |
423 | WORKSPACE_SUSPENDED — V1Error |
429 | RATE_LIMITED: too many requests for this key; wait Retry-After seconds — V1Error |
502 | UPSTREAM_UNAVAILABLE: the DNS checker did not answer; retry later — V1Error |
Schemas
V1ErrorDetail
| Field | Type | Description |
|---|---|---|
coderequired | string | Stable, machine-readable error code (docs/api/v1.md § Errors). |
messagerequired | string | Human-readable explanation; may change, do not parse it. |
details | object | Extra fields of this error, e.g. errors (validation), required (scope), retryAfter. |
V1Error
| Field | Type | Description |
|---|---|---|
errorrequired | V1ErrorDetail | |
statusCoderequired | number | HTTP status (kept at the top level for early v1 clients). |
coderequired | string | Same as error.code (kept for early v1 clients). |
messagerequired | string | Same as error.message (kept for early v1 clients). |
V1LinkSecurity
| Field | Type | Description |
|---|---|---|
statusrequired | string | One of: clean, flagged, needs_review, suspicious, scanning, unchecked |
primaryrequired | object | null | Primary reputation lookup (Google Web Risk / Safe Browsing). |
deepScanrequired | object | null | Deep scan of the rendered site. |
V1Link
| Field | Type | Description |
|---|---|---|
idrequired | string (uuid) | |
aliasrequired | string | |
statusrequired | string | active: served; disabled: turned off by the workspace; blocked: disabled by DNSPeek (see blockedReason); expired: past expiresAt.One of: active, disabled, blocked, expired |
previewUrlrequired | string | Shareable preview of the site on the new server. |
dashboardUrlrequired | string | The link in the dashboard (sign-in required). |
targetDomainrequired | string | |
targetIprequired | string | |
liveDomainrequired | string | null | Old site address for Live compare and visual compares; null: the old side opens targetDomain via public DNS. |
liveIprequired | string | null | Old server IP pinned for liveDomain; null: public DNS. |
httpPortrequired | number | |
httpsPortrequired | number | |
sslModerequired | string | One of: auto, skip, verify, off |
hasPasswordrequired | boolean | Visitors must enter a password. |
disabledrequired | boolean | |
blockedReasonrequired | string | null | Why DNSPeek (not the workspace) disabled the link.One of: safe_browsing_phishing, safe_browsing_malware, web_risk_phishing, web_risk_malware, security_review, moderation |
expiresAtrequired | string (date-time) | null | |
spaceIdrequired | string (uuid) | null | |
commentsEnabledrequired | boolean | Client comments widget on the preview (Agency plan and up). |
wildcardrequired | boolean | Subdomains are previewed too: shop.<targetDomain> opens at https://shop---<alias>.<preview domain>/ (Pro plan and up). |
dnsTrackingEnabledrequired | boolean | |
preflightrequired | object | null | Latest server check of the target (reachability, TLS); status pending while it runs. |
securityrequired | object | null | |
userIdrequired | string (uuid) | null | Member who created the link. |
workspaceIdrequired | string (uuid) | |
visibilityrequired | string | workspace: every member sees the link; private: only its creator (the API key's creator lists and reads it, nobody else in the workspace). The preview URL works either way.One of: workspace, private |
createdAtrequired | string (date-time) | |
updatedAtrequired | string (date-time) |
V1LinkPage
| Field | Type | Description |
|---|---|---|
itemsrequired | V1Link[] | |
totalrequired | number | Links in the workspace (all pages). |
limitrequired | number | |
nextCursorrequired | string | null | Pass as cursor for the next page; null on the last page. |
CreateLinkDto
| Field | Type | Description |
|---|---|---|
spaceId | string (uuid) | One of your spaces; not available to guests |
targetDomainrequired | string | |
targetIprequired | string | |
alias | string | |
httpPort | number | |
httpsPort | number | |
sslMode | string | How the proxy connects to the target server. auto: HTTPS, falling back to plain HTTP; verify: HTTPS with a trusted certificate only; skip: HTTPS without certificate verification (self-signed); off: plain HTTP only, for an origin without SSL (visitors still get HTTPS; the origin receives X-Forwarded-Proto: https).One of: auto, skip, verify, off |
password | string | Optional password to protect preview |
expiresAt | string | ISO8601 expiry date |
visibility | string | workspace: every member of the workspace sees the link; private: only you (its creator) see it in the dashboard and API. Preview URLs work for anyone with the link either way.One of: workspace, private |
liveDomain | string | null | Old site address for Live compare, Find differences and visual compares: the domain the old server serves the site on (for example before a rebrand). Hostname only, no scheme or path. Null or absent: the old side opens targetDomain via public DNS. |
liveIp | string | null | Optional IP of the old server (public addresses only) used for liveDomain instead of public DNS. Requires liveDomain (400 LIVE_IP_REQUIRES_DOMAIN otherwise). |
interstitialDisabled | boolean | true: visitors open the preview directly, without the DNSPeek notice "Preview of <domain> on a new server". Paid plans only (402 otherwise); guest and Free links always show the notice. |
wildcard | boolean | Also preview every subdomain of targetDomain (WordPress multisite, shop. or blog. hosts) as <sub>---<alias>.<preview domain>, served from the same targetIp. Pro plan and up (402 otherwise); not available to guests. |
V1TargetHint
| Field | Type | Description |
|---|---|---|
kindrequired | string | One of: hosted-builder |
platformrequired | string | |
messagerequired | string | |
previewUrlrequired | string | |
docsUrlrequired | string |
V1CreatedLink
| Field | Type | Description |
|---|---|---|
idrequired | string (uuid) | |
aliasrequired | string | |
statusrequired | string | active: served; disabled: turned off by the workspace; blocked: disabled by DNSPeek (see blockedReason); expired: past expiresAt.One of: active, disabled, blocked, expired |
previewUrlrequired | string | Shareable preview of the site on the new server. |
dashboardUrlrequired | string | The link in the dashboard (sign-in required). |
targetDomainrequired | string | |
targetIprequired | string | |
liveDomainrequired | string | null | Old site address for Live compare and visual compares; null: the old side opens targetDomain via public DNS. |
liveIprequired | string | null | Old server IP pinned for liveDomain; null: public DNS. |
httpPortrequired | number | |
httpsPortrequired | number | |
sslModerequired | string | One of: auto, skip, verify, off |
hasPasswordrequired | boolean | Visitors must enter a password. |
disabledrequired | boolean | |
blockedReasonrequired | string | null | Why DNSPeek (not the workspace) disabled the link.One of: safe_browsing_phishing, safe_browsing_malware, web_risk_phishing, web_risk_malware, security_review, moderation |
expiresAtrequired | string (date-time) | null | |
spaceIdrequired | string (uuid) | null | |
commentsEnabledrequired | boolean | Client comments widget on the preview (Agency plan and up). |
wildcardrequired | boolean | Subdomains are previewed too: shop.<targetDomain> opens at https://shop---<alias>.<preview domain>/ (Pro plan and up). |
dnsTrackingEnabledrequired | boolean | |
preflightrequired | object | null | Latest server check of the target (reachability, TLS); status pending while it runs. |
securityrequired | object | null | |
userIdrequired | string (uuid) | null | Member who created the link. |
workspaceIdrequired | string (uuid) | |
visibilityrequired | string | workspace: every member sees the link; private: only its creator (the API key's creator lists and reads it, nobody else in the workspace). The preview URL works either way.One of: workspace, private |
createdAtrequired | string (date-time) | |
updatedAtrequired | string (date-time) | |
targetHintsrequired | V1TargetHint[] | Non-blocking warnings about the target, e.g. a hosted site builder IP. |
V1UpdateLinkDto
| Field | Type | Description |
|---|---|---|
enabled | boolean | false turns the preview off, true turns it back on (not possible for links DNSPeek blocked: 403 LINK_BLOCKED_BY_SAFETY_CHECK). |
password | string | null | New visitor password; null removes it (400 POLICY_PASSWORD_REQUIRED when a workspace policy requires one). |
expiresAt | string (date-time) | null | New expiry (ISO 8601); null removes it. Plan limits and workspace policies apply, measured from link creation. |
targetIp | string | New target server IP (public addresses only; re-runs the server check and the security scan). |
liveDomain | string | null | Old site address for Live compare, Find differences and visual compares: the domain the old server serves the site on (e.g. before a rebrand). null clears it (400 LIVE_IP_REQUIRES_DOMAIN while liveIp stays set); 400 LIVE_DOMAIN_INVALID for anything but a public hostname. |
liveIp | string | null | IP of the old server used for liveDomain instead of public DNS (public addresses only). null clears it. Requires liveDomain (400 LIVE_IP_REQUIRES_DOMAIN). |
httpPort | number | |
httpsPort | number | |
sslMode | string | How the proxy connects to the target server: auto, verify, skip (no certificate verification) or off (plain HTTP only, for an origin without SSL).One of: auto, skip, verify, off |
visibility | string | private: only the link's creator sees it in the dashboard and API; workspace: every member does. Only the creator can change it (403 otherwise). The preview URL works either way.One of: workspace, private |
wildcard | boolean | true: the link also previews every subdomain of targetDomain as <sub>---<alias>.<preview domain> (Pro plan and up; 402 PLAN_REQUIRED otherwise). false turns it off on any plan. |
spaceId | string (uuid) | null | Move the link to this space of the workspace (404 SPACE_NOT_FOUND otherwise); null takes it out of its space. |
QaStagingAuthInput
| Field | Type | Description |
|---|---|---|
typerequired | string | none 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 |
username | string | basic: the username (no ":"). |
password | string | basic: the password. Omit to keep the saved one (same username). Never returned. |
name | string | header: the header name (Host, Cookie, transport and forwarding headers are refused); cookie: the cookie name. |
value | string | header / cookie: the value. Omit to keep the saved one (same name). Never returned. |
V1CreateQaReportDto
| Field | Type | Description |
|---|---|---|
maxPages | number | null | Pages to crawl; capped by the plan (402 above it). null = the plan maximum. |
includePaths | string[] | Only crawl discovered pages matching one of these root-relative globs (* = any characters except "/", ** = anything). The start page is always crawled. |
excludePaths | string[] | Never crawl discovered pages matching one of these globs. |
viewports | string | desktop (1280×800), mobile (390×844) or both (pages are revisited on mobile).One of: desktop, mobile, both |
crawlSpeed | string | gentle: one page at a time with a pause; normal: two in parallel; fast: four in parallel (plan feature).One of: gentle, normal, fast |
respectRobotsTxt | boolean | Skip pages robots.txt disallows for the DNSPeekQA user agent (default true). Only the site owner should turn this off. |
compareWithLive | boolean | Fetch the current public site for the old vs new server comparison (default true). |
activeProbes | boolean | robots.txt, sitemap, 404, canonical redirect and TLS probes of the new server (default true). |
rerunAfterDnsSwitch | boolean | Re-check the live domain automatically once DNS points at the new server (default true). |
notifyOnComplete | boolean | Send the "QA report ready / failed" notification (default true). |
stagingAuth | object | Credentials for a password-protected staging site. Encrypted at rest, never returned, used only for the target site. |
V1QaReportLink
| Field | Type | Description |
|---|---|---|
aliasrequired | string |
V1QaCounts
| Field | Type | Description |
|---|---|---|
totalrequired | number | |
criticalrequired | number | |
warningrequired | number | |
inforequired | number | |
pagesCrawledrequired | number | |
pagesWithErrorsrequired | number | |
truncatedrequired | boolean | The crawl budget ran out before every discovered page was visited. |
V1QaStagingAuthUsed
| Field | Type | Description |
|---|---|---|
typerequired | string | One of: none, basic, header, cookie |
username | string | basic: the username (never the password). |
name | string | header / cookie: its name (never the value). |
V1QaReportSettings
| Field | Type | Description |
|---|---|---|
maxPagesrequired | number | Page budget the crawl used (after the plan cap). |
includePathsrequired | string[] | |
excludePathsrequired | string[] | |
viewportsrequired | string | One of: desktop, mobile, both |
crawlSpeedrequired | string | One of: gentle, normal, fast |
respectRobotsTxtrequired | boolean | |
compareWithLiverequired | boolean | |
activeProbesrequired | boolean | |
rerunAfterDnsSwitchrequired | boolean | |
notifyOnCompleterequired | boolean | |
stagingAuthrequired | object | Kind of staging credentials used; secrets are never returned. |
V1QaReport
| Field | Type | Description |
|---|---|---|
idrequired | string (uuid) | |
linkrequired | V1QaReportLink | |
statusrequired | string | Poll until completed or failed (a run takes about 1–5 minutes).One of: queued, running, completed, failed |
scorerequired | number | null | |
verdictrequired | string | null | Completed reports: not_ready with any critical finding, ready_with_warnings with any warning, else ready.One of: ready, ready_with_warnings, not_ready |
countsrequired | object | null | |
errorrequired | string | null | Why a failed run failed. |
createdAtrequired | string (date-time) | |
completedAtrequired | string (date-time) | null | |
reportUrlrequired | string | Full report in the dashboard (sign-in required). |
shareUrlrequired | string | Read-only report anyone with the link can open. |
settingsrequired | object | null | Run settings the crawl used (no secrets); null for reports created before run settings existed. |
V1QaReportPage
| Field | Type | Description |
|---|---|---|
itemsrequired | V1QaReport[] | |
totalrequired | number | |
limitrequired | number | |
nextCursorrequired | string | null |
V1Resolver
| Field | Type | Description |
|---|---|---|
resolverrequired | string | |
locationrequired | string | |
addressrequired | string | |
answersrequired | string[] | |
ttlrequired | number | null | |
matchedrequired | boolean | The resolver already returns expected_ip (matchMode network: only addresses of that CDN). |
cdn | string | Set when every address the resolver returned belongs to this CDN.One of: cloudflare |
error | string |
V1DnsPropagation
| Field | Type | Description |
|---|---|---|
domainrequired | string | |
expectedIprequired | string | |
recordTyperequired | string | One of: A, AAAA |
percentrequired | number | Share of answering resolvers that return expected_ip. |
matchedrequired | number | |
answeredrequired | number | Resolvers that answered without error (the percent denominator). |
totalrequired | number | |
maxTtlrequired | number | null | Highest TTL seen: caches may keep the old IP this many seconds. |
propagatedrequired | boolean | percent ≥ thresholdPercent with at least half of the resolvers answering. |
thresholdPercentrequired | number | |
matchModerequired | string | network 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 |
cdnrequired | string | null | The CDN of expected_ip, or the CDN the domain is proxied through.One of: cloudflare |
proxiedrequired | boolean | expected_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. |
checkedAtrequired | string (date-time) | |
resolversrequired | V1Resolver[] | |
cachedrequired | boolean | Served from the 60-second cache of the same domain and IP. |