Read an error
Branch on the status code first, then read the body. The keys in the body depend on which part of the platform refused the call:
To log a readable message, take the first of
detail, error_message, details, error and message that the body contains. If it has none of them, the body is a set of field errors.
Some bodies add a machine-readable key: resource on allowance and capacity refusals, and code on some Attack Surface refusals. Branch on those keys when they are present. When you match a message, match its start, not the whole string.
A
4xx from the service behind an endpoint is forwarded with its own keys. Do not rely on the value types inside it: numbers, true, false and null can arrive as strings such as "25", "True", "False" and "None".404.
The order of checks
The API checks each request in this order and stops at the first refusal:- Path. An unknown path returns
404with an HTML page. A path missing its trailing/returns a301redirect. - API key. A missing, unknown, revoked or expired key returns
401. - Organization. A request that names another organization returns
403. - License and plan feature.
403. - Per-second rate limit and API Calls allowance.
429. - Method. A method the endpoint does not accept returns
405. - The endpoint itself. A spent feature allowance (
429), a full capacity slot (409), request validation (400), then the service behind the endpoint: its own4xx, or502,503and504. Endpoints differ in whether they validate the body before or after the allowance and capacity checks.
Content-Type is exactly application/json, a body that does not parse is refused with 400 at step 3, before the license check and the rate limit.
Refusals at steps 1 to 4 never reach the rate limit. They carry no X-RateLimit-* headers and count toward none of your limits. From step 5 on, a response that is not a 2xx uses none of your API Calls allowance and none of any feature allowance: a unit taken for the call is refunded. A response that passed the rate limit still counts toward the per-second limit. Rate limits and Plans and quotas explain the limits.
Branch on the status code
The helper below retries only what can succeed on a retry: a per-second
429 on any method, and a 500, 502, 503 or 504 on a GET. It raises everything else with the status and the body attached, so your code can branch on them.
A
2xx can still carry refusals. Quick search answers 201, and 200 when you read the record again. Each source in it reports its own outcome, such as not_entitled or quota_exceeded. See Quick search.400 Bad Request
Request validation answers with one key per field. Each key holds a list of problems:non_field_errors:
{"detail": "JSON parse error - …"}, followed by the parser’s message.
Other 400 bodies come from parameter checks in the API, such as {"error": "filter_task_id parameter is required"}, or from the service behind the endpoint. Some of those enforce a business rule that clears with time. Attack Surface, for example, refuses a new assessment while your organization already has the maximum number running or queued, and refuses an assessment equivalent to one started for the same domain in the last 30 minutes. Both answer 400 with a details message. See Attack Surface assessments.
401 Unauthorized
A
401 with any other body comes from the service behind the endpoint, not from your key. Retry a GET later with backoff, and contact support if it repeats.
Authentication explains how to create, send and replace keys.
403 Forbidden
To tell a plan refusal from a lapsed license, call
get_api_call_usage for the current month. It has no plan feature check, so it returns Your license is not active. when the license is the cause. get_direct_org_info answers even without a license in force, which confirms the key itself works.
On monitor create and update, a service that is missing or not recognized also returns This feature is not included in your plan. See Monitors.
A 403 with any other body comes from the service behind the endpoint. The endpoint’s guide describes it.
404 Not Found
Copy each path exactly as the API reference shows it. Most paths end in
/, and a few do not. A request that drops the trailing / gets a 301 redirect to the path with it. Most HTTP clients follow the redirect and resend a POST as a GET, so the call you meant never runs.
409 Conflict
A409 with resource and limit means a capacity slot is full. Nothing is created:
limit is your organization’s slot count, packs included. A limit of 0 means your plan includes none. Retrying fails until you free a slot or add a pack. Capacity slots explains how each slot is freed.
Other 409s mean the object is not in a state that allows the call. Most come from the service behind the endpoint:
A Filtered credentials export that has expired or failed returns
410 from the same download call, with an error_message. Exports expire 24 hours after creation. Create a new one.
422 Unprocessable Entity
A422 comes from the service behind the endpoint. It refused a value that passed the API’s own validation, such as an impossible date. The API reference lists it for Credential Check and Ransomwatch endpoints.
Credential Check answers {"detail": ...}, where detail is a message or a list of field errors. See Credential Check errors. Do not retry the same value.
429 Too Many Requests
The API returns four kinds of429. Tell them apart by the body:
The two rate-limit
429s carry a Retry-After header. The other two do not. Rate limits shows both rate-limit bodies in full. A 429 with any other body comes from the service behind the endpoint, and the endpoint’s guide describes it.
A feature allowance refusal names the allowance in resource:
period is month, or year for takedowns. limit is your allowance for that window, packs included. Metered allowances lists every allowance.
The Attack Surface refusal comes from the assessment service:
perform_port_scan, active_vuln_scan or dns_typosquatting_enabled, or sets domain_mode to dual_domain or all. A full assessment enables port scanning and typosquatting by default. A targeted assessment is heavy too when its report type is domain_spoofing_risk or application_security, or infrastructure_risk with port scanning left on, which is the default. The assessment unit is refunded. See Attack Surface assessments.
500, 502, 503 and 504
A few endpoints word their
502 differently, or pass the service’s own 5xx through. Credential comparison reports, for example, answer {"message": "Please try again later..."}, and Credential Check passes the lookup service’s error through. Their guides list them. Handle every 5xx the same way.
Back off between retries: wait 2, 4, 8 and 16 seconds, add up to a second of random delay, and stop after 5 attempts. See the warning above before you retry a call that starts a job.
Statuses the reference does not list
Each operation in the API reference lists the statuses it documents. The rules on this page apply to every operation, including those whose entry leaves a status out:401applies to every endpoint that needs a key. Several entries list none, including Quick search, Paste search and report schedules.403for a license that is not in force applies to almost every endpoint. About half of the entries list no403.409for a full capacity slot applies toalert_system_alert_create_alert_rule,create_report_scheduleandupdate_report_schedule. Their entries list no409.429for the per-second rate limit applies to every endpoint that needs a key. Several entries list none, including Quick search, Telegram search, Paste search, report schedules and the usage and organization endpoints.503and504apply to every endpoint that calls a service behind it. Most entries list only502.405and415are never listed.405returns{"detail": "Method \"GET\" not allowed."}, naming the method you sent.415returns{"detail": "Unsupported media type \"text/plain\" in request."}, naming theContent-Typeyou sent. The API accepts JSON, form and multipart bodies.
402 Payment Requiredappears on four Discord search entries. There are no credits. A plan refusal is a403, and a spent allowance is a429.
429 a generic description. On a metered endpoint, it can be any of the four refusals in 429 Too Many Requests, so read the body before you retry.