Skip to main content

Error envelope

Every error is the same shape, and validation reports the full violation set in one pass — fix everything at once, not one field per retry:

Status codes

Rejected requests are never scored and never charged. 429 means wait a moment; 402 means the account needs attention. They’re deliberately distinct signals.

Rate limits

  • Limits apply per organisation: all of your organisation’s API keys share one limit.
  • They’re counted per second, on POST /v1/score only. GET /v1/explain/{score_id}, GET /v1/usage and GET /v1/health aren’t counted.
  • Your organisation’s tier (your plan’s) sets the limit, shared by all your keys whatever tier each key scores at. Every scored response carries X-RateLimit-Limit and X-RateLimit-Remaining.
  • Over the limit, a request gets 429 E_RATE_LIMITED with a Retry-After header, in seconds.
The platform in front of the API can also throttle, with a 429 that may not carry this API’s JSON body. Treat every 429 the same way.

Credits

Each scored request costs credits, set by your tier. Credits are granted each calendar month (UTC) and expire at its end; unused credits don’t carry over. When a request’s credits would take your organisation past this month’s allowance, it gets 402 E_CREDITS_EXHAUSTED. Retrying doesn’t help until credits renew on the 1st or more are granted. Test keys score only the published test subjects, with fixed answers. They are never charged and never refused for credits, but they are still rate limited. Live usage is on the portal’s Usage page, and from GET /v1/usage.

Idempotency

Send an Idempotency-Key header on POST /v1/score so you can retry without being charged twice. Use 1 to 128 characters, unique per logical request: your own request ID works well.
  • Same key, same body, within 24 hours: you get the original response, with the same score_id. It isn’t charged again.
  • The body must be byte-for-byte identical. Keep the exact bytes you sent and resend them; don’t rebuild the JSON. A different body under the same key gets 409 E_IDEMPOTENCY_REPLAY_MISMATCH.
  • If the original is still being scored, a retry waits briefly for it. If it still hasn’t finished, the retry gets 409 E_IDEMPOTENCY_IN_PROGRESS with Retry-After. Retry after that, with the same key and body.
  • A request that fails (any non-200 response) doesn’t use up its key.
  • Keys are scoped to the API key that sent them. Two of your API keys can’t collide.
  • A replay still counts towards your rate limit and passes the credit check, but isn’t charged.
A retry with a new Idempotency-Key is a new request: it’s scored and charged again.

Retrying

Correlation and timeouts

Set client_reference to your own ID. It’s echoed back in the response, so you can match our records to yours. options.max_latency_ms bounds the time spent on a request. A client timeout of around 10 seconds is a safe default.

Number formatting

E.164, digits only after +, no national trunk zero (+443444930787, never +44 (0)344…). A trunk-zero number passes validation but resolves to no numbering range — it scores as unattested, with no operator attribution in the subject block. If your responses are missing operator data, check your formatting first.