Errors
The shape of an API error, the thirteen codes with their HTTP status and what they cost, and what to do with each.
Every error of the API has the same shape, whatever the route. This page describes that shape, the thirteen possible codes and what each one costs in credits.
One shape
{
"error": {
"name": "PARTNER_API",
"message": "SCOPE_MISSING",
"details": { "scope": "students:write" }
}
}name is always PARTNER_API. The code is in message: it is what your tool reads, along with the HTTP status. details exists for two codes only. SCOPE_MISSING puts the scope to add in it. VALIDATION puts a list in it, whose shape depends on where the refusal comes from:
- a parameter or a body refused on input: entries
{ field, type, message }, or{ field, reason }for an invalidcursor; - an argument that the schema of an operation refuses: entries
{ path, message }; - the refusal of the operation itself, or a 4xx error raised while it runs: a list of texts. The
webhooks.*operations are the exception: their refusal returns an object, whosecodenames the reason and whose other fields detail it (see Webhooks).
Malformed JSON or a body that is too large gives a VALIDATION with no details. The other codes never carry any.
The thirteen codes
| Code | HTTP | When | Credit |
|---|---|---|---|
UNAUTHORIZED | 401 | Key missing, unknown or revoked. | free |
PLAN_NOT_ELIGIBLE | 403 | Your plan doesn't include the API. | free |
SCOPE_MISSING | 403 | The key doesn't have the required scope. | free |
WRITE_NOT_ALLOWED | 403 | Your plan does not allow writes through API keys. | free |
CREDITS_EXHAUSTED | 402 | No credits left this month and no reserve. | free |
RATE_LIMITED | 429 | Too many calls: 10 per second, 300 per minute, 60 writes and 20 deletes per minute. | free |
IDEMPOTENCY_MISMATCH | 409 | Same Idempotency-Key, another operation or another body. | free |
CONFLICT | 409 | The same request is already in progress. | free |
OPERATION_NOT_EXPOSED | 404 | This operation isn't exposed by the API. | free |
DRY_RUN_UNSUPPORTED | 400 | No preview for this operation. | free |
VALIDATION | 400 | Invalid parameters or body (413 if the body exceeds 1 MB). | billed; never debited for a 413 or malformed JSON; refunded when the schema of an operation refuses its arguments |
NOT_FOUND | 404 | Nothing at this address. | billed, except an unknown path |
INTERNAL_ERROR | 500 | Error on our side. | refunded for a read; kept for a write or a delete |
What stays billed
The credit is debited before the call runs. Only three errors keep it:
- On a read, a refused parameter (
limit=500) gives a billed 400VALIDATION.GET /eventsis the exception: a free route never bills its errors. - On a read as on an operation, a target that cannot be found or is not yours gives a billed 404
NOT_FOUND. - On a write or a delete, a 500
INTERNAL_ERRORkeeps its credit: the change may have been saved before the failure. - On an operation, an argument that its schema refuses is refunded. The refusal of the operation itself, or a 4xx error raised while it runs, stays billed: the operation ran.
An invalid JSON body or a refused Idempotency-Key costs nothing. Keys and credits details the rest.
What to do with an error
- 400, 403, 404. Do not retry as is: the request, the key or the plan needs fixing.
detailssays what. - 401. Check the key, which may have been revoked.
- 402. Calls resume at the monthly reset, or as soon as a pack is added.
- 409.
IDEMPOTENCY_MISMATCHneeds a newIdempotency-Key. ForCONFLICT, read Writes and idempotency. - 429. Wait
Retry-Afterseconds: see Limits. - 500. Retry a little later. For a write, keep the same
Idempotency-Key.