Skip to content
Taylorz CRM Developers
Esc
↑↓navigate↵open⌘Jpreview
On this page

Errors

Both refusal shapes, what each status code means, which refusals are worth retrying, and why a validation failure tells you so little.

A refusal is JSON. There are two shapes.

Most carry only a message, which is for a log rather than for a person:

{ "error": "Invalid request" }

A domain refusal carries a machine-readable reason as well:

{
  "code": "conflict",
  "error": "Settings changed; reload before saving",
  "reason": "settings_stale"
}

Branch on the status first, then on code and reason when they are there — never on error. A refusal of the first shape carries neither, so code that reads reason unconditionally breaks on one. The message is prose and may be reworded; code is one of invalid_input, not_found, conflict and forbidden, and reason is a stable slug. Some refusals carry a detail object with more about what failed.

What each status means

Status Means Retry?
400 The body, query or a parameter was refused No, until you change the request
401 The token is missing, invalid, expired or revoked Yes, once — refresh and send it again
403 The module is off, or your scope or role does not permit the action No
404 No such record, or none you may read No
409 A revision conflict, a reused idempotency key, or a state that forbids the operation Only after reading again and changing the request
413 The body exceeded the limit No
500 An unexpected failure Yes, with backoff

403 does not distinguish “your role cannot” from “the module is off” in the status alone — read reason. external_api_disabled means the workspace’s api module is off; permission_required means the scope or the role is the problem.

A 404 and a 403 are sometimes the same underlying situation seen from different angles: a record you may not read answers 404 rather than confirming it exists.

Why validation failures say so little

A refused body answers 400 {"error":"Invalid request"} without naming the field. That is deliberate: the API does not echo your request back, and it does not list the internal validation that ran. Check the request against the reference’s schema for that endpoint.

Retrying safely

An endpoint that takes an Idempotency-Key is safe to retry after a timeout or a 500: reuse the same key and the server either does the work or replays the answer it already gave. Generating a fresh key for a retry is how a duplicate is created.

For an endpoint that takes no key — the pricing previews, the download link, POST /api/v1/bootstrap — a retry repeats the request. None of the four creates anything on a second call, but nothing stops the work happening twice either.

Was this page helpful?