Get started
Errors
Every error has the same JSON shape, a machine-readable code and a message you can show or log.
Error shape
Failed requests answer with a 4xx or 5xx status and an error object: a stable code to branch on, a human-readable message, and for validation errors the fields that need attention. Some errors add details next to them, like retryAfter or feature.
{ "error": { "code": "validation_error", "message": "Some fields need your attention", "fields": { "email": "Enter a valid email address", "customAttributes.plan": "Choose one of the options" } }} Status codes and error codes
Successful requests answer 200 OK, or 201 Created when something new was
created.
| Status | Code | Meaning |
|---|---|---|
| 400 | validation_error | A field is missing or invalid. fields maps each field (dot paths for nested ones) to a message. |
| 400 | bad_request | The request can’t be processed as sent — a body that isn’t valid JSON, an unknown teammate, a viewer acting on a conversation. |
| 400 | unsupported_version | The X-Rabbitblaze-Version header names a version that doesn’t exist. |
| 401 | unauthenticated | No API key, or an unknown or revoked one. |
| 403 | forbidden | The key lacks the scope the endpoint needs. |
| 403 | plan_limit | The plan doesn’t include the API, or a limit (such as contacts) is reached. Includes plan and feature or limit. |
| 404 | not_found | The resource doesn’t exist in this workspace (malformed ids answer 404 too), or the route doesn’t exist. |
| 409 | conflict | A uniqueness rule — a duplicate email, user id or tag name — or a state conflict, such as converting a ticket twice. |
| 413 | payload_too_large | The body is over 2 MB. |
| 415 | unsupported_media_type | A body was sent without Content-Type: application/json. |
| 422 | unprocessable | Valid input that can’t be applied — for example closing without required attributes, or publishing an article without a body. |
| 422 | idempotency_key_reused | The Idempotency-Key was already used for a different request. |
| 429 | rate_limited | Too many requests. Includes retryAfter (seconds) and a Retry-After header. |
| 500 | internal | Something went wrong on our side. Safe to retry with backoff. |
Messages are written for people and may change; branch on code and the status, never on the
message.
Handling errors
- Fix 4xx errors before retrying — sending the same request again gets the same answer.
-
Retry 429 after
retryAfterseconds, and 5xx or network errors with exponential backoff. Add an Idempotency-Key toPOSTs so a retry never creates a duplicate.
const res = await fetch(url, options)if (!res.ok) { const { error } = await res.json() if (res.status === 429) { // Wait error.retryAfter seconds (also in the Retry-After header), then retry } else if (error.code === "validation_error") { console.warn("Fix these fields:", error.fields) } else { throw new Error(`${res.status} ${error.code}: ${error.message}`) }} res = session.post(url, json=payload)if not res.ok: error = res.json()["error"] if res.status_code == 429: time.sleep(error.get("retryAfter", 1)) # then retry elif error["code"] == "validation_error": print("Fix these fields:", error["fields"]) else: raise RuntimeError(f"{res.status_code} {error['code']}: {error['message']}")