Errors
Status codes, the error body, and which failures are worth retrying.
Errors return a JSON body with a single error field carrying a
human-readable message:
{ "error": "A building with this slug already exists" }The status code is the part to branch on. The message is for a human reading a log, and its wording can change.
Status codes
| Code | Meaning | Retry? |
|---|---|---|
400 | The request was understood and rejected — a validation or business-rule failure. | No. Fix the request. |
401 | Missing, malformed or unrecognised bearer token. | No. See Authentication. |
403 | The key is valid but lacks the scope this route requires. | No. Issue a key with the right scope. |
404 | No such record, or not visible to this key's workspace. | No. |
409 | Conflicts with something that already exists — a unique field collision. | No, not unchanged. |
429 | Rate limit exceeded for this key. | Yes, after backing off. |
500 | Something failed on our side. | Yes, with backoff. |
The two that are commonly misread
404 does not always mean "does not exist". A record belonging to another
workspace is a 404, not a 403 — the API does not confirm the existence of
data your key cannot see. So a 404 for an id you are certain about usually
means the key belongs to a different workspace than you assumed.
403 is about the key, not the record. It means this key's scopes do not
include what the route requires. The record may be perfectly readable with a
different key.
Retrying
Only 429 and 5xx are worth retrying. Everything else will fail again
identically, and retrying it just consumes your rate budget.
For 429, back off before retrying — the window is rolling, so an immediate
retry is likely to fail again and push the reset further out. Budgets are per
key, so a well-behaved integration is not affected by a noisy neighbour.
Retry writes carefully. inquiries:write, leads:write,
check-in-links:write, reservation-links:write and purchases:write are not
idempotent: a retried request that actually succeeded the first time creates a
second record. On an ambiguous failure — a timeout, a dropped connection —
reconcile before retrying rather than retrying blind.
Validation failures
A 400 names what was wrong in its message. Common causes:
- A required field missing or the wrong type.
- A value outside an allowed set.
- A business rule refusing the operation — for example a date that conflicts
with an existing booking. These are
400, not409, because nothing collided; the request was simply not allowed.
A 409 is narrower: something with that unique value already exists. Changing
the conflicting field and resending is the fix.
See also Authentication.