Skip to content

Errors

Use the HTTP status first to classify a failure and, when present, the code field to choose the specific action. Do not program against the error text: it is written in English, can change and, for some internal failures, may contain technical details.

The Agents, Knowledge Bases, Conversations, Lists and Tags endpoints use this envelope:

{
"error": "Invalid or missing API token",
"code": "unauthorized"
}
FieldTypeHow to use it
errorstringEnglish diagnostic message. Do not use it as an identifier or show it directly to the end customer.
codestringMachine-readable identifier. Handle known codes and keep a fallback for new or missing values.
codeTypical statusWhat it meansRecommended action
invalid_request400Invalid JSON, parameter, field or UUID.Fix the request; retrying the same content does not help.
unauthorized401Missing, invalid or revoked token.Stop the call and replace the token. See Authentication.
forbidden403The target is outside the organization or is not a compatible API inbox.Review the resource and configuration; do not retry automatically.
not_found404Resource or route not found, including a resource from another organization.Confirm the ID and path. An unsupported method also falls through to 404, not 405.
conflict409Current state blocks the operation, such as preserved unsubscribe consent, a duplicate tag or a non-editable knowledge-base item.Read the current state and reconcile before trying another action.
internal_error500Unexpected application, database or configuration failure.Treat the outcome as unknown; reconcile and only then retry with backoff.
service_unavailable503A knowledge-base search dependency is unavailable.Retry with exponential backoff and jitter; do not interpret the response as an empty knowledge base.
StatusCurrent use
200 OKRead, update, completed action or synchronous Chat.
201 CreatedCreated knowledge-base item or created/confirmed list membership.
202 AcceptedChat accepted for asynchronous processing or placed in the debounce queue. The response does not prove the run finished.
204 No ContentDeleted knowledge-base item; do not try to decode JSON.
400 Bad RequestInvalid input.
401 UnauthorizedMissing or invalid token.
403 ForbiddenForbidden, incompatible or inactive Chat target.
404 Not FoundResource, route, or method-and-route combination not found.
409 ConflictCurrent state is incompatible with the operation.
500 Internal Server ErrorUnexpected failure or synchronous Chat pipeline failure.
503 Service UnavailableTemporarily unavailable dependency or persistence failure classified by the pipeline.

The API does not currently implement public 408 Request Timeout or 429 Too Many Requests responses. Synchronous Chat has no fixed product HTTP deadline: a model timeout or another pipeline failure currently arrives as 500, while a proxy or client may close the connection without receiving JSON. See the full contract in Chat.

Chat shares part of the runtime used by other channels and does not yet follow a closed code catalog. Depending on the phase, you may receive:

  • specific lowercase codes such as agent_not_found and trigger_inactive;
  • legacy uppercase codes such as AGENT_NOT_FOUND, AGENT_ARCHIVED and AGENT_INACTIVE;
  • the technical failure class, such as TimeoutError, in a 500;
  • on one rare defensive path, a 500 with error but no code.

This divergence is tracked as BUG-API-038; the promised 408 and incomplete Swagger catalog also extend BUG-API-022. Until the product unifies the contract, use the status as a fallback and record unknown codes for observability without failing to decode them.

  1. Read the body as text and then try to decode JSON; proxies may also return HTML or an empty body.
  2. For a 2xx response, handle the endpoint-specific status — especially 202 and 204.
  3. For 400, 401, 403, 404 or 409, fix the input, credential, target or state before retrying.
  4. For 500 or 503, assume a write may have happened partially. Query the resource or history before retrying.
  5. When retrying is safe, use exponential backoff with jitter and a maximum attempt count. There is no guaranteed Retry-After header today.
const response = await fetch(url, options);
const raw = await response.text();
let body = null;
try {
body = raw ? JSON.parse(raw) : null;
} catch {
// Non-JSON body returned by a proxy or the platform.
}
if (!response.ok) {
const code = typeof body?.code === "string" ? body.code : null;
if (code === "unauthorized") rotateOrReplaceToken();
else if (response.status >= 500) scheduleReconciliationAndRetry();
else handlePermanentFailure(response.status, code);
}