Developers / Errors

Errors

One error shape for the whole API, the full code table, and what is worth retrying.

Every failure on /v1 returns the same shape, whether it came from authentication, a rate limit, a controller, or a path that does not exist. Write one handler and it covers the API.

{
  "error": {
    "code": "INVALID_VIN",
    "message": "VIN must be 17 characters.",
    "requestId": "req_2f1c8a9e4b7d4c1a9f3e2d5b6c8a0f1e",
    "details": [{ "field": "vin", "issue": "length" }]
  }
}
Branch on code. Messages are written for humans and may be reworded, and HTTP status alone does not distinguish, for example, a missing entitlement from a blocked address. details is present only when there is something specific to a field to say.

requestId

Every request and every response carries X-Request-Id, and it is repeated in the error body. Quote it when you contact us and we can find the exact call, with no need to describe what happened.

If you send your own X-Request-Id we echo it back, so you can stitch our logs to your trace. Keep it to 64 characters of letters, digits, _, . or -. Anything else is replaced with one of ours rather than rejected.

The codes

CodeHTTPWhat it meansWhat to do
INVALID_REQUEST400Malformed body, or a missing or unusable parameterFix the request. Do not retry unchanged
INVALID_VIN400Not a valid VIN by length, characters or check digitValidate before sending. Do not retry
UNAUTHORIZED401Key missing, unknown, revoked or expiredCheck the key. All four answer alike on purpose
INSUFFICIENT_CREDIT402Prepaid balance exhausted, or postpaid limit reachedTop up. Retrying will not help
USAGE_LIMIT_REACHED402The calls included in this billing period are used upTopping up will not lift this. It resets next period, or ask us to raise it
FORBIDDEN403Authenticated, but not entitled to this endpointContact us to enable it
IP_NOT_ALLOWED403Your account is restricted by address and this one is not on the listThe message names the address we saw. Call from an allowed one, or send us that address
REPORT_NOT_FOUND404No report with that id on your accountCheck the id. Ids are scoped to the account that bought them
ENDPOINT_NOT_FOUND404No endpoint at that method and pathCheck method and path against the reference
REPORT_EXPIRED410Past the access window for that reportBuy the vehicle again for a current report
RATE_LIMITED429Too many requests this minuteWait for Retry-After, then continue
INTERNAL_ERROR500Something broke on our sideRetry once. If it persists, send us the requestId
UPSTREAM_UNAVAILABLE503A source we depend on is unavailableNever billed. Safe to retry shortly

Retrying

  • Never retry 400, 401, 403, 404 or 410. The answer will not change.
  • Do not hammer 402. Either your balance is empty or this period is used up, and the two need different people: one buys more credit, the other renegotiates the allowance. Branch on the code and alert someone rather than retrying.
  • Do retry 429, 503 and 500, with backoff. Honour Retry-After on a 429.
  • Retrying a lookup for a vehicle you already bought is free if your account has free repeats, and reading the report back is free in any case. Prefer the GET over re-buying.

Rate limits

Every response carries your current allowance.

X-RateLimit-Limit: 60
X-RateLimit-Remaining: 58

On a 429 you also get Retry-After in seconds. Pace yourself against X-RateLimit-Remaining rather than discovering the ceiling by hitting it. If your limit does not fit your workload, ask. It is a setting on your account, not a platform constant.