code, a readable message, and sometimes details. A path that matches no route gets a plain-text 404, and a method the route does not accept gets a 405 with an empty body. Match on code. See Requests and errors for the envelope, the status code table and retry rules.
A code can appear with more than one status when two routes use it differently. The tables list the status each route family returns.
Authentication and access
| HTTP | Code | Cause | Fix |
|---|---|---|---|
| 401 | unauthorized | Missing Authorization header, a scheme other than Bearer, an empty token, or an unknown, malformed or revoked key | Send a current key as Authorization: Bearer <key> |
| 403 | insufficient_capability | A scoped key lacks the capability, or the route accepts organization keys only | Ask Nexio to grant the capability, or use an organization key. See Authentication |
| 403 | scoped_key_required | An organization key from a non-live environment called Records, graph or another route that needs a live key or a scoped key | Use the live organization key or a scoped key. See Authentication |
| 403 | engine_binding_forbidden | The scoped key is not bound to the engine, or to the engine of the run | Ask Nexio to bind the engine to the key |
| 400 | acting_principal_mismatch | The body’s submitted_by differs from X-Nexio-Acting-Principal | Send one value, in the header |
| 503 | auth_unavailable | Nexio could not reach its key store | Retry with backoff |
| 499 | client_closed_request | A Records read was abandoned: the client closed the connection before it finished. Nobody reads this answer | Nothing to fix; it is recorded so an abandoned read is not counted as a server error |
Rate limits and caps
| HTTP | Code | Cause | Fix |
|---|---|---|---|
| 429 | rate_limited | Your org or the engine used its per-minute budget, or on inbound events the sending address or the source used its budget | Wait Retry-After seconds. See Limits |
| 429 | run_cap_exceeded | Your org reached its monthly run cap. No run was created | Do not retry. Contact support to raise the cap |
| 504 | request_timeout | The request ran past its time budget | Retry with backoff. For large data reads, narrow the request |
Request shape and size
| HTTP | Code | Cause | Fix |
|---|---|---|---|
| 400 | invalid_request | The body is not valid JSON, has an unknown field, or misses a required value | Send only documented fields, as valid JSON |
| 400 | missing_input | A run request has no input | Put the engine’s input under input |
| 400 | invalid_input | input failed the engine’s validation. details is a list of {field, message} | Fix each listed field |
| 400 | invalid_offerings | offerings failed validation. details lists the problems | Fix the listed offerings |
| 400, 413 | request_bound_exceeded | The request is over a size or shape bound. 413 for total bytes or the transport limit, 400 for string length, array items, object fields and depth. details names the bound, the JSON path, the limit and the measured value | Reduce the request. See Request bounds |
| 413 | body_too_large | An inbound event body is over 1 MiB | Send a smaller event |
Idempotency
| HTTP | Code | Cause | Fix |
|---|---|---|---|
| 400 | invalid_idempotency_key | Idempotency-Key is longer than 255 characters | Use a shorter key |
| 409 | idempotency_key_reused | On run submission, the key was already used with a different request, and details.run_id is the original run. See Idempotency | Use a new key for a new request, or read the original run |
| 409 | event_id_reused | An outcome event_id was already used in this organization and environment bucket for a different run, engine, event type or payload, or from another sandbox | Use a new event_id for a new outcome |
Environments
| HTTP | Code | Cause | Fix |
|---|---|---|---|
| 400 | environment_slug_invalid | Slug missing or not ^[a-z0-9_]{1,16}$ | Use 1 to 16 lowercase letters, digits or underscores |
| 400 | environment_slug_reserved | Slug is live, test, internal, admin, api, nexio, draft or all | Choose another slug |
| 400 | environment_slug_taken | The slug exists in your org | Choose another slug |
| 400 | environment_name_invalid | Name over 64 bytes of UTF-8 | Shorten the name |
| 400 | environment_limit_reached | Your org has 5 sandboxes | Delete one you no longer use |
| 400 | environment_live_immutable | Tried to delete the live environment | Not allowed |
| 404 | environment_not_found | No environment with that slug | List environments to check the slug |
| 409 | environment_in_use | Keys, webhook endpoints or runs still reference it. The body has blockers | Clear the blockers |
| 500 | environment_operation_failed, list_environments_failed | Nexio failed to complete the change or list | Retry with backoff |
Engines and versions
| HTTP | Code | Cause | Fix |
|---|---|---|---|
| 404 | engine_not_found | No engine with that slug in your org | Use a slug from GET /api/v1/engines |
| 403 | engine_archived | The engine is archived | Reactivate it, or use another engine |
| 400 | invalid_engine_type | The engine type is not one of the six registered types | Use comparison, matching, entity_analysis, diligence, triage or opportunity |
| 409 | engine_slug_conflict | An engine with that slug exists | Choose another slug |
| 400 | validation_error | The engine configuration failed validation. details lists each issue | Fix the listed paths. Use POST .../config/validate to check first |
| 400 | engine_version_required | The engine requires a pinned engine_version | Send an exact major.minor version |
| 400 | engine_version_exact_required | The engine accepts only an exact major.minor pin | Send an exact version such as 1.3 |
| 400 | engine_version_invalid_format | The pin is not major.minor, major.x or draft | Use one of those forms |
| 400 | engine_version_not_found | On a run submission: no released version matches the engine_version pin | List versions and pick a released one |
| 404 | engine_version_not_found | On GET .../versions/{version}: no release with that number | List versions and pick a released one |
| 400 | engine_version_draft_requires_sandbox_key | "draft" was sent from a live key | Use a sandbox key, or pin a released version |
| 500 | engine_version_none_released | The engine has no released version | Publish a version, or pin "draft" from a sandbox key |
| 422 | engine_release_unservable | The resolved release cannot serve runs | Pin another version, or publish a new one |
| 409 | engine_version_publish_mismatch | The requested version does not match the one Nexio computed for this change | Publish the version named in details |
| 409 | engine_version_schema_change_requires_major | The change alters the request or response schema, so it needs a new major version | Publish the required major version in details |
| 409 | engine_config_changed | The draft changed while you were publishing | Read the draft again and publish |
| 422 | invalid_engine_config | The draft cannot be published | Fix the configuration, then publish |
| 422 | cold_start_gate_not_met, cold_start_gate_failed, cold_start_gate_regressed | The engine’s evaluation gate has not passed | See Evaluation |
| 500 | engine_config_hash_inconsistent | The engine’s stored configuration failed an integrity check | Contact support with the x-request-id |
| 503 | engine_config_hash_unavailable | The engine’s configuration hash is not available yet | Retry with backoff |
Runs
| HTTP | Code | Cause | Fix |
|---|---|---|---|
| 400 | missing_run_id, invalid_run_id | The run ID in the path is missing or not a UUID | Send the run_id you received |
| 404 | run_not_found | No run with that ID in your org and environment | Check the ID and that you use a key from the same environment |
| 400 | run_requires_acting_principal | A run of a matching engine was sent without an acting principal | Send X-Nexio-Acting-Principal |
| 422 | submission_stamp_<reason> | The submission failed a source check. details has reason and submission_source | Contact support with the x-request-id |
| 400 | invalid_batch_size | A latest-run batch had fewer than 1 or more than 100 subjects | Send 1 to 100 subjects |
| 500 | create_run_failed, load_run_failed, cancel_run_failed | Nexio failed to create, read or cancel the run | Retry with backoff. Retry submissions with the same Idempotency-Key |
| 503 | queue_unreachable | Nexio created the run, could not queue it, and marked it failed. A retry with the same Idempotency-Key returns that failed run | Retry later with a new Idempotency-Key |
Sandbox fixtures
| HTTP | Code | Cause | Fix |
|---|---|---|---|
| 400 | invalid_test_scenario | test_scenario is not completed, degraded or failed | Use one of the three values |
| 400 | test_scenario_sandbox_only | Sent from a live environment | Use a sandbox key |
| 403 | test_scenario_forbidden | The key does not hold runs:test | Use a scoped key with runs:test |
| 400 | test_scenario_exact_version_required | No exact major.minor pin | Pin an exact version |
| 400 | test_scenario_version_not_supported | The resolved version is not in the supported-version registry | Pin a registry version of the fixture engine |
Outcomes and annotations
| HTTP | Code | Cause | Fix |
|---|---|---|---|
| 400 | missing_event_id, invalid_event_id | The outcome has no valid event_id | Send a unique event_id |
| 400 | invalid_event_type | The outcome event_type is not recognized | Use a documented event type |
| 400 | invalid_payload | The outcome payload does not match its event type | Fix the payload |
| 400 | reason_text_too_long | The outcome reason text is over 1,000 characters | Shorten it |
| 500 | outcome_write_failed | Nexio failed to record the outcome | Retry with the same event_id |
Webhooks
| HTTP | Code | Cause | Fix |
|---|---|---|---|
| 400 | invalid_url | The endpoint URL is invalid or resolves to a disallowed host | Use a public HTTPS URL |
| 400 | missing_endpoint_id, invalid_endpoint_id | The endpoint ID in the path is missing or malformed | Send the endpoint id |
| 404 | webhook_not_found | No endpoint with that ID in your org | List endpoints to check |
| 404 | delivery_not_found | No delivery with that ID on that endpoint | List deliveries to check |
| 409 | webhook_limit_exceeded | The environment already has 10 active endpoints | Delete an endpoint you no longer use |
| 409 | delivery_not_resendable | The delivery is not in dead_letter, or the endpoint is inactive or deleted | Resend only dead-lettered deliveries on an active endpoint |
Conversations
| HTTP | Code | Cause | Fix |
|---|---|---|---|
| 404 | instance_not_found | No conversation instance with that slug | Check the slug |
| 403 | instance_archived | The instance is archived | Use an active instance |
| 409 | instance_not_published | The instance has no released version, so it cannot take turns or attachments | Publish a version |
| 404 | conversation_not_found, message_not_found, turn_not_found | Not found for this instance and end user | Check the IDs and the end_user value |
| 409 | conversation_archived | The conversation is archived | Reactivate it first |
| 400 | attachments_not_enabled | The instance does not accept attachments | Enable attachments in its configuration |
| 413 | attachment_too_large | The file is over the size limit | Send a smaller file |
| 400, 415 | attachment_rejected | The file type or content is not accepted | Send a supported file type |
| 503 | converse_unavailable, attachments_unavailable | The capability is not enabled in this environment | Contact support |
502, or 200 with an error frame | provider_error | The model provider returned an error. The stateless converse route answers HTTP 502 before any stream starts. The turn route has already answered HTTP 200 when it calls the model, so the failure arrives as a terminal error frame whose top-level reason names it: rate_limited, context_overflow, model_unavailable, invalid_request, provider_fault or provider_auth | Retry with backoff for rate_limited and provider_fault. Shorten the conversation for context_overflow. Contact support for the others |
Records
| HTTP | Code | Cause | Fix |
|---|---|---|---|
| 403 | identity_unmapped | The acting principal is not linked to a person in your connected records | Send the stable ID. If it is sent, ask Nexio to confirm the person’s match |
| 403 | identity_needs_review, identity_stale, identity_suspended | The person’s link needs review, is out of date, or is suspended | Ask Nexio to review the link |
| 403 | service_identity_unknown | X-Nexio-Service-Identity names no active service identity | Use a registered service identity |
| 403 | assertion_invalid, assertion_stale | The signed identity assertion failed verification, or its timestamp is more than 5 minutes from the server’s clock. On /api/v1/records/analyses, a missing or invalid assertion answers 401 assertion_invalid | Sign a fresh assertion |
| 403 | book_lens_read_only | A request that carried a read lens tried to write | Write from the person’s own session. See Lens |
| 403 | field_denied | The route serves only a field class the person’s role may not see. On other reads a denied field comes back as null instead | Read without the field |
| 403 | action_out_of_scope | The action targets a record outside the person’s scope | Act only on records in scope |
| 400 | action_schema_unknown, action_payload_invalid | The action type is unknown or its payload is invalid | Fix the action |
| 400 | action_list_too_large | A notes, tasks or workflows read matched more than 10,000 rows | Narrow the filter. (A batch of more than 20 commands is 400 invalid_request.) |
| 403 | overlay_read_only | Writes back to the system of record are not available | Make the change in the system of record itself |
| 400 | book_connection_ambiguous | Your org has more than one connected system and none was named | Pass connection_id |
| 400 | cursor_filter_mismatch | A filter the cursor already fixes was sent with it, or (activity and task registers) a value differs from the first page | On later pages send what What a cursor fixes lists for that register, and omit filters the cursor fixes |
| 409 | cursor_expired | The cursor no longer matches how the register is served | Start the list again |
| 403 | scope_unavailable | The person has no record of their own in the system of record, or the requested scope cannot be served for them | Read the message; change the selection, or change the person’s access in your system of record. See Authority and scope |
| 400 | lens_target_unknown | The X-Nexio-Records-Lens target is malformed or not a person in your org | Send principal:<id> for a known person |
| 403 | lens_caller_unattributed | A read lens was requested without an acting principal | Send X-Nexio-Acting-Principal |
| 400 | invalid_cursor | The pagination cursor is malformed | Resend the cursor you received, or start the list again |
| 400 | offset_cursor_conflict | Both offset and cursor were sent | Send one of them |
| 409, 503 | book_unavailable | The connected data cannot be read now. 503 means the warehouse statement queue is busy (details.reason is busy): wait for Retry-After. 409 carries details.reason (executor_timeout, budget_exhausted, pin_unavailable, cursor_expired, result_too_large, scope_datasources_missing, warehouse_unavailable), or no details when no qualifying connection exists yet | See Completeness and errors for which reasons are worth retrying |
| 503 | resolve_retry_exhausted | Nexio could not resolve the person’s authority in time | Retry with backoff |
Graph
| HTTP | Code | Cause | Fix |
|---|---|---|---|
| 400 | unsupported_node_type | The graph does not serve that node type | Use a node type listed by GET /api/v1/graph |
Inbound events
| HTTP | Code | Cause | Fix |
|---|---|---|---|
| 401 | ingest_source_not_found | No ingest source has that source_key | Check the key Nexio gave you |
| 403 | ingest_source_disabled | The source is disabled | Ask Nexio to enable it |
| 401 | invalid_signature | The signature does not match the body | Sign the exact raw body with the current secret |
| 401 | stale_timestamp | The signed timestamp is outside the allowed window | Sign with the current time |
| 401 | invalid_credentials | A delivery to an ams360_ons source carried no accepted authentication code | Check the authentication code configured in the sending system |
| 400 | invalid_body | The body could not be read | Send a complete JSON body |
| 413 | body_too_large | The body is over 1 MiB | Send a smaller event |
| 409 | delivery_id_reused | The same delivery ID arrived with different bytes | Use a new delivery ID for a new event |
| 422 | varies | The event was received but refused. code names the reason | See Inbound events |
Server errors
| HTTP | Code | Cause | Fix |
|---|---|---|---|
| 500 | internal_error | Nexio hit an unexpected error | Retry with backoff. If it persists, send the x-request-id to support |
| 500 | other *_failed codes | A named step failed, for example create_webhook_failed | Retry with backoff |
| 503 | other *_unavailable codes | A dependency is briefly unavailable | Retry with backoff |