The DNS Check API reports errors as RFC 9457 Problem Details, with the content type application/problem+json:
{
"type": "https://www.dnscheck.co/api/errors#invalid_parameter",
"title": "Invalid parameter",
"status": 400,
"code": "invalid_parameter",
"detail": "The limit parameter is invalid.",
"errors": [
{ "field": "limit", "code": "invalid", "message": "Must be a whole number from 1 to 200." }
],
"request_id": "6a1f0c2e-3b7d-4e59-a8c4-2f9d1e7b5a30"
}
typelinks to the code's row in the error codes table.codeis one of the error codes and never changes, so match on it rather than ontitleordetail, whose wording can improve.errorslists what needs fixing, when there's something specific. Each entry has:field: the field or parameter to fix. An entry about how several fields combine has nofield, so check that it's present before using it.code: one of the field error codes, as stable as the top-levelcode.message: what to fix, in words.
request_ididentifies the request if you contact us about it. All responses carry their request ID in theX-Request-Idheader.
Error Codes
Which errors are worth retrying: idempotency_key_in_use, service_unavailable, and every 429 can succeed once you wait the Retry-After header's seconds, and internal_error can succeed later, so retry it with backoff. Every other error needs a change to the request first.
When you retry a POST, send the same Idempotency-Key so a request that went through isn't repeated (see idempotency keys).
An error without Problem Details comes from Cloudflare, which sits in front of DNS Check, and never reached DNS Check. Its Content-Type isn't application/problem+json, and its body may be an HTML page or plain text, such as error code: 521, so check the Content-Type before parsing an error as JSON. What to do depends on its status:
5xx: Cloudflare couldn't reach DNS Check or didn't get an answer in time. Retry it with backoff, waiting out itsRetry-Afterif it has one, and check the status page for an outage. After a524, DNS Check may still have finished the request, so retry aPOSTwith the sameIdempotency-Key.429: Cloudflare is limiting requests from your IP address. Wait before retrying, for at least a minute if there's noRetry-After, and spread your requests out.- Any other
4xx, such as a403: Cloudflare's firewall blocked the request, usually because part of it looked like an attack, such as a field value resembling a file path or a database command. Retrying the same request gets the same answer. If the request holds legitimate DNS data, contact us with the response'sCF-Rayheader and the time of the request, so we can find it.
| Code | Status | Meaning |
|---|---|---|
api_key_in_query |
400 | API key sent in the URL. API v2 takes the API key only in the Authorization header (Authorization: Bearer <key>) since a key in a URL ends up in logs, browser history, and Referer headers. Remove the api_key query parameter, and consider rotating the key. |
invalid_parameter |
400 | Invalid parameter. A query parameter or header has a value this endpoint doesn't accept, or the request has a query parameter the endpoint doesn't take, such as a misspelled staus. errors names each one and what it accepts. |
malformed_request |
400 | Malformed request. The request body isn't valid JSON, or isn't a JSON object, or the request takes no body: a GET, a DELETE, or an on-demand check, whose parameters, such as limit, go in the query string (an empty {} body is fine). Send the fields as one object, such as {"name": "Mail"}. Its path, query string, and body must also be valid UTF-8. |
api_key_missing |
401 | API key required. This request needs an API key, sent as Authorization: Bearer <key>. Only the example record group can be read without one. |
api_key_invalid |
401 | Invalid API key. The Authorization header doesn't hold an enabled API key. Check that it reads Bearer, a space, and the whole key, and that the key hasn't been disabled or deleted on the API Keys page. |
insufficient_scope |
403 | API key lacks access. The API key's access doesn't allow this request, and detail names the access it needs. Change the key's access on the API Keys page, or use a key that has that access. |
feature_not_in_plan |
403 | Feature not in plan. The request uses a feature the account's plan doesn't include, such as custom name servers, check frequency, invert check, or load balancer monitoring. detail names it, and upgrade_url links to the plans that have it. |
plan_limit_reached |
403 | Plan limit reached. The account already has as many record groups or DNS records as its plan allows. limit is the plan's limit, and upgrade_url links to larger plans. Deleting some frees room. |
account_expired |
403 | Account expired. The account's subscription has expired, so it can only delete record groups and DNS records until it's renewed, or until it's down to the Basic plan's limits and switched to that plan. |
example_group_read_only |
403 | Example group is read-only. Anyone can read the example record group, but never change it through the API. Create your own record group to try writes. |
not_found |
404 | Not found. Nothing your API key can read has this ID, or no endpoint matches the URL. Anything belonging to another account is also not found, so you can't probe IDs. |
method_not_allowed |
405 | Method not allowed. The endpoint exists, but doesn't take this HTTP method. The Allow header lists the methods it does take. API v2 changes resources with PATCH, never PUT. |
idempotency_key_in_use |
409 | Idempotency key in use. Another request with the same Idempotency-Key is still running. Retry after the Retry-After header's seconds to get its response. |
precondition_failed |
412 | Precondition failed. The resource was edited since the ETag sent in If-Match was read. Get it again, reapply your change, and retry with the new ETag. |
unsupported_media_type |
415 | Unsupported media type. Send request bodies as Content-Type: application/json. PATCH also accepts application/merge-patch+json. |
validation_failed |
422 | Validation failed. One or more fields are missing or invalid. errors lists each problem, with a message saying how to fix it. |
idempotency_key_reused |
422 | Idempotency key reused. The Idempotency-Key was already used within the last 24 hours for a request with a different method, path, query string, or body. Use a new key for each distinct request. |
too_many_writes |
422 | Too many writes for one request. The request needs more writes than the account's plan allows in a minute, so it can't go through as one request. limit is the most one request can use: split the work into requests that fit, such as importing a large zone file in parts. |
rate_limited |
429 | Rate limit reached. The account has used its requests, writes, or on-demand checks for this minute. Wait for the number of seconds in the Retry-After header. Every key on an account shares one budget, and paid plans have larger ones. |
daily_quota_exceeded |
429 | Daily write quota reached. The account has made as many writes today (UTC) as its plan allows, ten times its per-minute limit. Retry-After gives the seconds until midnight UTC. |
internal_error |
500 | Internal error. Something went wrong on our side. Retry later, and if it keeps happening, contact us with the request_id. |
service_unavailable |
503 | Service unavailable. DNS Check is briefly unavailable, such as during database maintenance. Wait for the number of seconds in the Retry-After header, then retry. |
The OpenAPI document lists the codes each endpoint can return.
Field Error Codes
validation_failed and invalid_parameter errors list each problem found in errors, and each entry has its own code that says what's wrong with that one field or parameter. The top-level code says what kind of error the request hit. A field error code never changes, but more can be added, so treat any you don't recognize as invalid.
| Code | Meaning |
|---|---|
required |
The field is missing or empty. |
invalid_type |
The value is the wrong JSON type, such as a string where a number belongs. |
unknown_field |
The body has a field this endpoint doesn't accept. |
unknown_parameter |
The query string has a parameter this request doesn't accept. |
too_short |
The value is too short, or the list has too few entries. |
too_long |
The value is too long, or the list has too many entries. |
unsupported |
The value isn't one this field supports, or doesn't work with the other fields sent, such as load_balancer on a TXT record. |
already_exists |
Another resource already has this value, such as a record group with the same name. |
no_records |
The zone file holds no DNS records we can read. |
nothing_imported |
The zone file added no DNS records, and the message says why. |
invalid |
The value is invalid for any other reason, and the message says how. |