Error Handling
Error format, status codes, and solutions for the integration API.
When a request to the integration API fails, the response includes a JSON body with information about the error.
Error format
{
"statusCode": 401,
"error": "Unauthorized",
"message": "Invalid or revoked API key"
}| Field | Type | Description |
|---|---|---|
statusCode | number | HTTP status code |
error | string | Error name |
message | string | Detailed description of the problem |
code | string | Present only on errors a client has to branch on. It is a stable UPPER_SNAKE value: branch on code, never on the text of message, which may change. Today the only one is DEFAULT_ROOT_CONFIRMATION_REQUIRED (see Publish Config). It is not the Code column of the table below, which is the HTTP error name |
Error codes
| Status | Code | Description | Solution |
|---|---|---|---|
401 | Unauthorized | Invalid, revoked or expired API key, or its owner is inactive | Check that the key is copied exactly and is still active in Settings → API Keys; if it was revoked or expired, create a new one |
403 | Forbidden | The key does not have the required permission, or a project key names another project in x-project-id | Confirm that the key has the necessary permissions: activity:view for queries, activity-result:submit for submitting results, commerce:batch-upsert / operator:batch-upsert / route:batch-upsert for the batch upserts. With a project key, omit x-project-id or send the key's own project |
400 | Bad Request | Validation error in the request body, missing x-api-key header (Missing required header: x-tenant-id), an x-project-id that is not a valid UUID, or a result without activity_id submitted without a project | Check that the body complies with the documented format: data types and required fields. If you send x-project-id, use a project UUID; with a tenant key or a user token, send it to submit a result without activity_id |
404 | Not Found | Resource not found, or the project named in x-project-id does not exist | Confirm that the activity_id or other identifier exists in the tenant, and that the project in x-project-id belongs to the key's tenant |
422 | Unprocessable Entity | The body is valid but cannot be processed: the activity does not accept a result in its current state or day, or the result type is not active or needs data that is missing | Verify that the activity is in a state that accepts a result (READY, DISPATCHED, RETRYING or COMPLETED) and that its day has not been closed by the end-of-day cutoff; use an active result code and send future_scheduled_at (today or later) when its type requires it |
429 | Too Many Requests | Too many requests in a short time | Wait before retrying, and spread the requests over time |
Common errors and diagnostics
401 — Unrecognized key
{
"statusCode": 401,
"error": "Unauthorized",
"message": "Invalid or revoked API key"
}Possible causes:
- The key was revoked from the administration panel
- The key has an expired expiration date
- Formatting error (spaces, extra characters)
- The key's owner is inactive — in that case the
messageisAPI key owner is inactive or not found - The API could not validate the key at that moment — in that case the
messageisAPI key validation failed; retry the request
A request that carries no key does not receive this 401. The API only reads x-api-key as a key when its value starts with rtn_sk_; any other value counts as no key. Without a key and without x-tenant-id, the API responds 400 Bad Request with Missing required header: x-tenant-id; with x-tenant-id but no credentials, it responds 401.
Project errors
On GET /api/integration/activities/tasks and POST /api/integration/activity-results/tasks, x-project-id is optional: both are project-optional endpoints. When the header is sent, the API checks it before the permissions and the body. The 400 of a result without activity_id is not part of that check: it comes after the body is validated, so an error in the body is reported first. How each key chooses its project is explained in Key scope.
| Status | When | message |
|---|---|---|
400 | A result without activity_id is submitted without a project: a tenant key or a user token that does not send x-project-id | Falta el header obligatorio x-project-id: un resultado sin activity_id necesita proyecto. |
400 | x-project-id is not a valid UUID (tenant key or user token) | El header x-project-id debe ser un UUID válido. |
403 | A project key sends an x-project-id that is not its own project | La API key pertenece a un proyecto distinto del que declara el header x-project-id. |
404 | The project in x-project-id does not exist or belongs to another tenant | El proyecto no existe. |
403 — Insufficient permission
{
"statusCode": 403,
"error": "Forbidden",
"message": "Required permissions: activity:view"
}Possible causes:
- The key does not include the required permission for the endpoint
- Ask the key's owner to edit its permissions with
PUT /api/api-keys/:id/permissionsor from Settings → API Keys
400 — Validation error
The API responds 400 when the body does not match the documented format.
Possible causes:
- Missing required fields:
occurred_atandtask_result.resultalways;commerce_external_idonly whenactivity_idis absent (standalone executions) - Invalid date format (must be ISO 8601)
activity_idis not a valid UUID- Fields that are not part of the documented body
422 — Non-processable state
{
"statusCode": 422,
"error": "Unprocessable Entity",
"message": "La actividad no está en un estado válido para registrar resultado."
}Possible causes:
- The linked activity is not in a state that accepts a result.
READY,DISPATCHEDandRETRYINGaccept one;COMPLETEDalso does, and submitting again updates the activity's existing result;CANCELEDandFAILEDdo not —messageabove - The activity's execution date has already crossed the end-of-day cutoff —
La actividad corresponde a un día ya cerrado y no admite registrar resultado.Past that cutoff, an auto-close runs and may register the result (asNOT_EXECUTED). Standalone executions (STANDALONE, withoutactivity_id) are exempt from this rule and the previous one - The result code in
task_result.resultdoes not exist or is not active —El tipo de resultado seleccionado no está activo.See List Configurations to get valid codes - The result type requires
task_result.future_scheduled_atand it was not sent —Este tipo de resultado requiere una fecha comprometida. task_result.future_scheduled_atfalls on a day before today, in the tenant's time zone —La fecha programada no puede ser en el pasado.