Skip to navigation

Errors

One error envelope, stable codes, human-readable messages.

View as Markdown

Jelliu uses conventional HTTP status codes and returns every error in the same JSON envelope:

{
"error": {
"code": "CAMPAIGN_NOT_ACTIVE",
"message": "Campaign can only be activated from DRAFT or PAUSED status"
}
}
FieldAlways presentDescription
error.codeYesStable, machine-readable identifier. Branch on this.
error.messageYesHuman-readable explanation. May change at any time.
error.detailsOnly on some VALIDATION_FAILED responsesWhich fields failed and why. See Validation errors.
error.metadataOnly on a few codesStructured context, such as plan limits. See Metadata.

Messages are for people, codes are for code

Messages are written for the person reading them, and the language depends on the endpoint. Jelliu’s customers are Spanish-speaking, so many product-facing messages are in Spanish, while others are in English. Both of these are real responses:

{
"error": {
"code": "SERVICE_UNAVAILABLE",
"message": "Servicio no disponible temporalmente. Vuelve a intentarlo en unos segundos."
}
}
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Too many requests, please slow down"
}
}

Never parse or match message. It is not translated consistently and can be reworded without notice. Switch on error.code and the HTTP status.

HTTP status codes

StatusMeaning
400The request is malformed or failed validation.
401Missing, malformed, unknown, revoked or expired API key.
402A plan limit was exceeded (PLAN_LIMIT_EXCEEDED on some routes).
403Authenticated but not allowed: scope, role, plan feature, a feature that needs an active subscription, compliance rule or suspended workspace.
404The resource does not exist or belongs to another workspace.
409The request conflicts with the resource’s current state.
413The request body or an uploaded file is larger than the route accepts (PAYLOAD_TOO_LARGE).
422The request is well-formed but semantically invalid (used by a few endpoints).
429Rate limit, concurrency limit or budget exhausted. Honor Retry-After.
500Unexpected server error. Malformed IDs, numbers and dates, unparseable JSON and oversized uploads are answered with 400 or 413 instead.
502An upstream provider failed (for example an integration sync).
503A temporary infrastructure problem. Safe to retry after Retry-After.

For 5xx responses the real cause is logged on our side and never returned. The body carries a generic message: Internal server error, or An unexpected error occurred with code INTERNAL_ERROR.

Common error codes

The status shown is the usual one. A few codes are returned with a different status on specific endpoints (for example VALIDATION_FAILED with 409 or 422), so read the status and the code together.

CodeStatusWhen
VALIDATION_FAILED400Body, query or path parameters failed validation, including a malformed ID, a number out of range or a date that cannot be parsed, a JSON body that does not parse, or an invalid multipart upload.
PAYLOAD_TOO_LARGE413The request body or an uploaded file is over the route’s size limit.
UNAUTHORIZED401See Authentication.
FORBIDDEN403The key’s scope or the route’s role requirement does not allow the request.
TENANT_SUSPENDED403The workspace is suspended.
BILLING_ERROR403 (usually)The plan does not include the feature or channel, a resource cap (agents, campaigns, contacts, integrations) was reached, or the workspace has no active subscription (metadata.kind: "subscription_required").
COMPLIANCE_BLOCKED403Blocked by compliance rules or content screening.
PHONE_NUMBER_REQUIRED403Outbound calling needs a phone number owned by the workspace.
NOT_FOUND404Generic not found.
AGENT_NOT_FOUND, CAMPAIGN_NOT_FOUND, CALL_NOT_FOUND, CONVERSATION_NOT_FOUND404The specific resource was not found in your workspace.
CAMPAIGN_NOT_ACTIVE400 or 409The campaign is not in a state that allows the transition.
PLAN_LIMIT_EXCEEDED402 or 409A hard limit was reached, such as 25 active API keys.
CALL_ALREADY_IN_PROGRESS409The same operation is already running, for example a number being provisioned. Retry shortly.
AGENT_PROVISIONING409The agent is still being set up. Retry after Retry-After (5 seconds).
AGENT_PAUSED409The agent has been stopped in the dashboard. 503 if its state could not be checked.
AGENT_CHANGE_PENDING_APPROVAL409The change was held for review and not applied.
AGENT_ACTION_PENDING_APPROVAL409The action is waiting for a person to approve it and did not run.
AGENT_ACTION_APPROVAL_CLOSED409The approval request already expired or was decided.
NUMBER_UNVERIFIED400The telephony account can only call verified numbers.
RATE_LIMIT_EXCEEDED429See Rate limits.
MAX_CONCURRENT_CALLS_REACHED429The concurrency limit for calls was reached.
AGENT_BUDGET_EXCEEDED429The agent used up the action or spend budget set by the workspace.
AI_WEEKLY_CAP_REACHED429The weekly budget for an in-product AI feature is used up.
INTEGRATION_SYNC_FAILED502 (usually)A connected integration or upstream provider failed.
INTERNAL_ERROR500Unexpected error.
SERVICE_UNAVAILABLE503Temporary infrastructure problem. Retry-After: 5.

Validation errors

Validation failures return 400 with code VALIDATION_FAILED and a details field. Depending on the endpoint, details takes one of two shapes.

Field map. Most create and update endpoints report errors grouped by field:

{
"error": {
"code": "VALIDATION_FAILED",
"message": "Invalid campaign input",
"details": {
"formErrors": [],
"fieldErrors": {
"agentId": ["Invalid uuid"],
"productContext": ["String must contain at least 10 character(s)"]
}
}
}
}

Issue list. Other endpoints return a flat list of issues, each with a dotted path:

{
"error": {
"code": "VALIDATION_FAILED",
"message": "Request validation failed",
"details": [
{ "path": "url", "message": "Invalid url", "code": "invalid_string" }
]
}
}

Handle both: if details is an array, read path and message from each item; if it is an object, read fieldErrors.

No details. Some input problems are caught outside the endpoint’s own validation and come back as VALIDATION_FAILED with only a Spanish message:

Causemessage
A value the database cannot read as its type, such as an ID that is not a UUID, a number out of range, or a date that cannot be parsed, on a route that does not check it firstUno de los valores enviados no tiene un formato válido (por ejemplo, un identificador mal formado).
A JSON body that does not parseEl cuerpo de la petición no es un JSON válido.
A multipart upload with the file in an unexpected field, or too many filesLa carga del archivo no es válida., with details: [{ "code": "LIMIT_UNEXPECTED_FILE", "field": "..." }]

These requests used to fail with 500 INTERNAL_ERROR. Fix the value and send the request again.

Size limits

A JSON or form body larger than 1 MB, or an uploaded file larger than the route’s limit (20 MB for knowledge documents, 10 MB for a web chat attachment), is refused with 413:

{
"error": {
"code": "PAYLOAD_TOO_LARGE",
"message": "El cuerpo de la petición es demasiado grande."
}
}

An oversized file gets El archivo es demasiado grande para esta operación. A few routes answer their own size errors instead: the CSV contact upload returns 400 VALIDATION_FAILED (Uploaded file is too large (max 10MB).), and a web chat attachment checked after upload returns the widget’s own 413 body. Do not retry a 413 unchanged: split the batch or shrink the file.

Metadata

metadata is included only for the four codes below, and only with keys from a fixed allowlist. Everything else stays server-side. The keys you will typically see:

CodeTypical keys
BILLING_ERRORlimit, current, tier, upgradeTo, kind
AI_WEEKLY_CAP_REACHEDkind, tier, weekStart, limitTokens, upgradeTo
AGENT_CHANGE_PENDING_APPROVALchangeRequestId, fields
AGENT_ACTION_PENDING_APPROVALrequestId, expiresAt, reversibility, match

No active subscription

A workspace whose subscription is not active, trialing or past_due is refused some features with 403 BILLING_ERROR, metadata.tier: "none" and metadata.kind: "subscription_required". Use kind to tell this apart from a plan that lacks a feature, and send the user to choose a plan. The message names the feature:

{
"error": {
"code": "BILLING_ERROR",
"message": "«Servidores MCP» requiere una suscripción activa. Este espacio de trabajo no tiene un plan activo: elige uno en Ajustes → Plan para continuar. Tus datos siguen disponibles para consultar y exportar.",
"metadata": { "tier": "none", "kind": "subscription_required" }
}
}

Retrying does not help until the workspace subscribes. Reading and exporting your own data is not affected. The list of refused operations is in Billing and usage.

Retrying

  • Retry 429 and 503 after the number of seconds in the Retry-After header.
  • 409 AGENT_PROVISIONING also carries Retry-After.
  • Other 4xx errors, including 413, will fail again until the request, the key or the resource state changes.
  • For other 5xx errors, retry with exponential backoff.