Responses and errors
Open in the interactive reference
Every successful response has the status 200 and carries its result under data. A collection also returns pagination beside data; see Pagination and querying.
A failed response carries error instead of data: a message, the failure's code where it has one, and diagnostics that say what went wrong. Two failures look different: the error of a 401 is a string, and a 429 has no body.
Diagnostics
A diagnostic has a stable code; a severity of error, warning or information; a readable message; a path to the input field it concerns, where there is one; and a details object, where its code defines one.
Branch on code, never on message. Codes are part of the contract, and each endpoint lists the codes it declares with the shape of their details. Messages can be reworded.
Diagnostics with the severity warning or information are advisories. On a successful response other than a collection's, they report something worth knowing, such as a value that was defaulted, without the request having failed. Do not treat them as failures. A failed response can carry advisories too, beside its errors.
Invalid input
A request whose body or parameters do not fit the endpoint's types is refused with 400 and the message Invalid input, before the endpoint runs. Its diagnostics name the field and what was wrong. They carry no code and no severity, and their shape varies between an object and a plain string, so read them rather than parse them.
Status codes
A failure the endpoint declares, such as a rule the input breaks, is a business failure. It normally carries the rule's code, and its status is 400 unless the endpoint maps that code to another status. Each endpoint lists the codes it declares and the status of each.
These failures are shared by every endpoint, and none carries a business code, so branch on the status:
| Status | When | Body |
|---|---|---|
400 |
The body, a path parameter or a query parameter does not match the endpoint. | { "error": { "message": "Invalid input", "diagnostics": [ { "path": ["invoiceDate"], "message": "…" } ] } } |
400 |
The Api-Version header is missing. | { "error": { "message": "The 'api-version' header is required and must name the requested API version's public identifier" } } |
400 |
The Api-Version header names a version that does not exist, or the path does not begin with a known API namespace. | { "error": { "message": "Unknown API version 'v2'" } } |
401 |
The request carries no valid access token. | { "error": "401 Unauthorized - …" } |
403 |
The access token has not been granted this endpoint. | { "error": { "message": "You are not authorized to access the requested endpoint" } } |
404 |
The path does not exist in the requested version. | { "error": { "message": "The requested endpoint could not be found" } } |
429 |
Too many requests came from your address. | (no body) |
500 |
Something failed on the server, or the API was briefly unavailable while the environment was being changed. | { "error": { "message": "An internal error occurred" } } |
Which of these to retry is covered under Rate limits and retries.
Failed writes leave nothing behind
A write that accepts an Idempotency-Key runs in a single transaction. If it fails, on a business rule or with an error while it runs, it is rolled back, so there is nothing to clean up. The rare write that does not accept the header lists IDEMPOTENCY_NOT_SUPPORTED among its errors. A rollback does not make a retry safe on its own; see Idempotency.
Examples
Success
{
"data": {
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"sku": "ABC-1"
},
"diagnostics": [
{
"code": "MISSING_RELEASE_DATE",
"severity": "warning",
"message": "No release date was provided."
}
]
}
Failure
{
"error": {
"code": "DUPLICATE_SKU",
"message": "A product with this SKU already exists.",
"diagnostics": [
{
"code": "DUPLICATE_SKU",
"severity": "error",
"message": "A product with this SKU already exists.",
"details": {
"sku": "ABC-1",
"existingId": "…"
}
}
]
}
}