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/scoreonly.GET /v1/explain/{score_id},GET /v1/usageandGET /v1/healtharen’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-LimitandX-RateLimit-Remaining. - Over the limit, a request gets 429
E_RATE_LIMITEDwith aRetry-Afterheader, in seconds.
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 402E_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 anIdempotency-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_PROGRESSwithRetry-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.
Retrying
Correlation and timeouts
Setclient_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.