Errors
One envelope for every failure, so you can branch on a code instead of parsing prose.
The envelope
Any non-2xx response
{
"error": {
"type": "invalid_cursor",
"message": "`cursor` is not a cursor this endpoint issued. Omit it to start from the first page.",
"docs": "https://developer.edmdb.net/docs"
}
}Branch on `type`, never on `message`
type is a stable contract and changes only with a version bump. message is written for a human reading a log and will be reworded whenever a clearer wording exists.Codes
| Status | type | What happened |
|---|---|---|
400 | invalid_parameter | A query or path parameter failed validation. The message names the parameter. |
400 | invalid_cursor | The cursor is malformed, or came from a different endpoint. Drop it to start over. |
401 | missing_api_key | No key was sent. |
401 | invalid_api_key | The key is unknown, revoked or expired. |
404 | not_found | No such record, or no such endpoint. |
429 | rate_limit_exceeded | Too many requests for this key. See rate limits. |
429 | quota_exceeded | Your account's monthly allowance is spent. Upgrade or wait for the reset. |
500 | internal_error | Our fault. Safe to retry with backoff; if it persists, tell us. |
Handling them
Treat 4xx other than 429 as terminal — retrying an invalid_api_key will not fix it. Retry 429 and 500 with exponential backoff and jitter. See rate limits for the throttling specifics.
Empty is not an error
A list with no matches returns 200 with an empty data array, not a 404. The same goes for sub-resources: an event with no lineup on record returns an empty array, because "we have no lineup for this" and "this event does not exist" are different answers and you may want to act on them differently.