Concepts

Errors

The API returns conventional HTTP status codes. The body is always JSON in the shape { "error": "<machine_readable_code>" }. Human descriptions are intentionally not returned, as they can leak which keys exist, which IPs are allowlisted, and which credentials are valid.

Status code reference

Codeerror valueMeaning
200n/aSuccess.
400invalid_cve_idThe path didn't match CVE-YYYY-N{4,7}.
401unauthorizedCredential failure: missing, malformed, expired, or revoked key, or IP not allowed. Intentionally uniform.
402insufficient_creditsOrganisation balance below 1 credit.
404not_foundRoute doesn't exist, or the CPE vendor, product, or version isn't tracked.
405method_not_allowedOnly GET (and OPTIONS) are supported.
500internalUnexpected server error. Email support with the x-request-id.

Why all credential errors look the same

Bad token, revoked key, expired key, IP not on the allowlist: all return:

401 Unauthorized
{ "error": "unauthorized" }

…with no extra detail. This stops an attacker holding a leaked key from enumerating which credentials and IP rules you have in place.

If you're integrating and can't tell why you're getting 401s, the dashboard's Audit log shows the real reason for every authentication failure on your keys.

Always provided

Every error response also includes:

  • x-request-id header (quote this in support tickets).
  • x-credits-remaining once a charge has been attempted.

Retry strategy

CodeRetry?
402 insufficient_creditsNo: top up credits first.
401 unauthorizedNo: fix the credential or IP allowlist, then retry once.
5xx internalYes: exponential back-off, max 3 attempts.
Don't retry 4xx blindly

Retrying a 401 or 402 in a tight loop will never succeed. Fix the credential or top up credits before retrying.