Documentation
Errors
Every failure the API returns, in RFC 9457 problem+json — and which of them cost you credits.
Errors are returned as RFC 9457 problem details with the content type application/problem+json. The HTTP status tells you the class of failure; the `code` member names the specific one, and is the value to branch on in code — never the `title`, which is prose we may reword.
{
"type": "https://truepoint.in/errors/insufficient_credits",
"title": "Insufficient credits",
"status": 402,
"code": "insufficient_credits",
"detail": "This call costs 1 credit; balance is 0.",
"balance": 0,
"required": 1
}`type` is a URI: the code appended to https://truepoint.in/errors/. Some errors carry extra members beyond the standard four — insufficient_credits carries balance and required, rate_limited carries retryAfterSeconds — so you can act on the failure without a second call.
| Status | Type | What it means |
|---|---|---|
| 422 | validation_error | The request failed validation — a missing identifier, or a value we could not parse. 422 rather than 400: the request was well-formed, its contents were not. |
| 401 | invalid_token | Missing, malformed, unknown or revoked API key. All four answer identically on purpose — the endpoint must not confirm which keys exist. |
| 403 | insufficient_scope | The key is valid but was not minted with the scope this endpoint requires. |
| 402 | insufficient_credits | The balance cannot cover this call. Nothing was charged and nothing was returned. Carries `balance` and `required`. |
| 429 | rate_limited | Too many requests for this key. Carries `retryAfterSeconds`. Retries are safe and are not billed. |
| 500 | internal | Something failed on our side. Nothing was charged. Retry with backoff. |
A no-match is not an error at all
There is no error code for "we found nothing", and that is deliberate. A miss answers 200 with matched:false and charges nothing. A lookup that finds nothing is a normal outcome, not a fault, and giving it a 4xx is how integrations end up treating our coverage gaps as outages — retrying them, alerting on them, and eventually routing around a working endpoint.
So branch on the `matched` field, not on a status code. Do not retry a miss: the answer will not change until the graph does.
What to retry
- 429 rate_limited — wait the `retryAfterSeconds` the body carries, then retry. Always safe. (The interval is in the body rather than a Retry-After header; read it from there.)
- 500 internal — retry with exponential backoff and a cap. Always safe: nothing was charged.
- 5xx without a problem body — treat as 500.
- 422, 401, 403 and 402 — never retry. The request will fail identically until something on your side, or your plan, changes.
Retries are safe by construction
Send an `Idempotency-Key` header on any billable call. If a request with that key has already succeeded, we replay the original response instead of re-executing it — so a retry after a timeout cannot double-charge you. Use a fresh key per distinct call and reuse it only for retries of that same call.