Response formats
Every API response is wrapped in a consistent envelope. On success you get data; on error you get a message and sometimes a structured errors array.
Success
On success, data contains the payload and message is null:
{
"data": {
/* the requested resource */
},
"message": null
}
Errors
On error, data is null and message describes what went wrong:
{
"data": null,
"message": "JobId is invalid"
}
Always check the HTTP status code first, then read message for detail.
Machine-readable error codes
Some error responses also include an errors array, where each entry has a stable code you can switch on plus a human-readable description:
{
"data": null,
"message": "Insufficient permissions.",
"errors": [
{
"code": "operator_scope_required",
"description": "This operation requires an operator-scoped key."
}
]
}
The errors array is only populated on a subset of responses. Most errors return message only, so treat message as the baseline and use errors[].code when present rather than depending on it for every failure. Never parse the free-text message to branch logic.
HTTP status codes
| Code | Meaning |
|---|---|
200 OK | Request succeeded |
201 Created | Resource created (e.g. a new webhook subscription) |
400 Bad Request | Invalid request, including validation failures - check message for the reason |
401 Unauthorized | Missing, invalid, or expired API key - see Authentication |
403 Forbidden | Your API key is valid but lacks the required scope |
404 Not Found | The requested resource doesn't exist |
409 Conflict | The request conflicts with the current state of the resource |
429 Too Many Requests | Rate limit exceeded - see Rate limits |
Validation errors are returned as 400 (not 422).
Paginated responses
List endpoints wrap their results in the same envelope and add pagination metadata inside data. See Pagination for the fields and how to page through results.