Errors and limits
The failure envelope
{
"success": false,
"error": "Org does not belong to this account",
"code": "forbidden"
}
The HTTP status says the kind of failure; code says exactly which, and is stable. Match on code, not on the
error text, which is for people and may change.
Codes
| Status | code | Meaning |
|---|---|---|
400 | bad_request | The body is not a JSON object, is malformed, or is not application/json |
400 | invalid_limit | limit is not an integer from 1 to 100 |
400 | invalid_cursor | cursor is not one this API gave you |
400 | invalid_gross_area | grossArea is missing, not a number, or below 0 |
400 | invalid_create_connector | createConnector is not a boolean |
400 | invalid_building_id | buildingId does not match ^[A-Za-z0-9_.-]{1,128}$ |
400 | invalid_items | A batch's items is not an array of 1 to 1,000 |
400 | invalid_item | A batch item is malformed, or names an orgId |
400 | duplicate_item | A batch repeats a buildingId |
401 | missing_token | No Authorization: Bearer header |
401 | invalid_token | The token is not valid |
401 | token_expired | The token has expired |
403 | forbidden | Not a credential for this org and account, or not an org service-account credential |
404 | not_found | No such route or batch |
413 | bad_request | The JSON body is over 1,000,000 bytes |
429 | rate_limited | Too many requests; see Retry-After |
500 | internal | An unexpected failure on our side |
502 | jobs_unavailable | A batch or update could not be started and was cancelled; some updates may already have been applied |
503 | upstream_unavailable | A check this API depends on is unavailable; retry |
503 | batches_unavailable | Batches and updates are not available right now |
503 | jobs_unavailable | A batch's jobs cannot be read right now; retry |
503 | results_unavailable | A batch's per-item results cannot be read right now; retry |
The same code can carry a different status, as jobs_unavailable (502 when starting a batch, 503 when reading
one) and bad_request (400, or 413 for a body that is too large): read the status and the code together.
The codes an item can carry (building_not_found, connector_required, missing_postal_identity, upstream_error, job_failed; a single update is a batch of one) are not HTTP errors. They are listed in Batches.
Limits
| Limit | Value |
|---|---|
| Requests, every route, per account | 120 per minute |
| Batch or update start requests, per account | 10 per minute |
| JSON body | 1,000,000 bytes (413 bad_request beyond) |
| Body refused by the server | 1 MiB (1,048,576 bytes), see below |
| Buildings in one batch | 1 to 1,000, each buildingId once |
Buildings per page (limit) | 1 to 100, 50 when absent |
buildingId | ^[A-Za-z0-9_.-]{1,128}$ |
| Per-item batch results kept | 3 days |
A body of more than 1 MiB (1,048,576 bytes) is refused earlier, by the server, with 413 in a different shape:
{ "code": "PAYLOAD_TOO_LARGE", "message": "Request body exceeds 1048576 bytes" }. Keep bodies under 1,000,000 bytes
to get the envelope above.
Rate limits
Requests are counted per account in one-minute windows, whichever credential of the account sends them:
- every route allows about 120 requests per minute (a request that is refused with
401is not counted); - batch and single-update start requests (
POST .../gross-area:batchandPUT .../gross-area) allow about 10 per minute together, including one that is then refused with400. A start request also counts toward the 120.
Past a limit the answer is 429 rate_limited with a Retry-After header: the seconds until the limit resets. Wait
that long before retrying. The limits are applied by each server instance, so the effective limit across instances
can be a small multiple of these numbers.
Retrying
429,502and503are worth retrying after a pause: for429wait theRetry-Afterseconds, for502and503back off (for example 1, 2, 4, 8 seconds). For502 jobs_unavailableon a batch, first check the buildings: some updates may already have been applied.500 internalis unexpected; one retry after a pause is reasonable, and a persistent500is a fault on our side, not in your request.401 token_expired: request a new token (see Authentication) and repeat the call.PUT .../gross-areais idempotent: repeating it with the same value is harmless (each call is a new job).- Starting a batch is not idempotent: a second
POSTstarts a second batch. If you did not get an answer, check the buildings before starting it again. - Other
4xxanswers will not change on a retry; fix the request.