> ## Documentation Index
> Fetch the complete documentation index at: https://docs.usenexio.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Requests and errors

> Send well-formed requests, read every status code, correlate a failure with support, and retry safely.

## Request basics

| Rule           | Value                                                                                                                                                                                                                                                                                                                                      |
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Base URL       | `https://api.usenexio.com`                                                                                                                                                                                                                                                                                                                 |
| API version    | Every public route is under `/api/v1/`, except the unauthenticated [`GET /health`](/api-reference/platform/health) and `GET /robots.txt`. See [Versioning](/reference/versioning).                                                                                                                                                         |
| Format         | JSON request and response bodies by default. Send `Content-Type: application/json` on a JSON body. An operation that takes or returns another format says so on its page: file uploads use `multipart/form-data`, conversation turns stream `text/event-stream`, and a document download returns the file itself or a redirect to it.      |
| Authentication | `Authorization: Bearer <key>` on every `/api/v1/` route except the inbound event route `POST /api/v1/events/ingest/{source_key}`, which is authenticated per source instead: an HMAC signature, or, for an `ams360_ons` source, a shared authentication code. See [Authentication](/authentication) and [Inbound events](/events/inbound). |
| Callers        | Server to server only. The API sends no CORS headers, so browsers cannot call it.                                                                                                                                                                                                                                                          |
| Unknown fields | Run submission, environment and many other write bodies reject fields they do not know with `400 invalid_request`.                                                                                                                                                                                                                         |
| Timestamps     | RFC 3339, for example `2026-09-23T15:04:05Z`.                                                                                                                                                                                                                                                                                              |
| IDs            | Run and webhook endpoint IDs are UUIDs. Slugs (engines, environments, conversation instances) are names you choose. Record keys served under `/api/v1/records` are opaque strings.                                                                                                                                                         |

## Headers

Request headers Nexio reads:

| Header                     | Required                                                 | Purpose                                                                                                                                                      |
| -------------------------- | -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `Authorization`            | Yes, except on `POST /api/v1/events/ingest/{source_key}` | `Bearer <key>`                                                                                                                                               |
| `Content-Type`             | With a body                                              | `application/json`, unless the operation's page names another type (for example `multipart/form-data` for an attachment upload)                              |
| `Idempotency-Key`          | No                                                       | Makes a run submission safe to retry. See [Idempotency](#idempotency).                                                                                       |
| `X-Nexio-Acting-Principal` | No                                                       | The person the request acts for. See [Acting for a person](/authentication#acting-for-a-person).                                                             |
| `X-Request-ID`             | No                                                       | Your own correlation ID, 1 to 128 printable ASCII characters with no spaces. Echoed back when valid. An invalid value is replaced by the request's trace ID. |
| `traceparent`              | No                                                       | A W3C trace context header. Nexio adopts its trace ID when the header is valid.                                                                              |

Response headers:

| Header                 | When                                                                                                                                                                                                                                                                                                               | Purpose                                                                                                  |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------- |
| `x-request-id`         | Every response                                                                                                                                                                                                                                                                                                     | Your `X-Request-ID` if it was valid, otherwise the request's 32-character trace ID. Quote it to support. |
| `Retry-After`          | On `429 rate_limited` and on `503 book_unavailable` (busy). Not on `429 run_cap_exceeded`                                                                                                                                                                                                                          | Whole seconds to wait, at least 1.                                                                       |
| `X-Nexio-Engine-Build` | Responses from the `/api/v1/records` routes, including their refusals, when the running build is stamped with its commit. Not on a 401 or 429 refused before the request reaches those routes, and not on a `504 request_timeout` or `500 internal_error` written when the request times out or fails unexpectedly | The build of the API that answered.                                                                      |
| `Server-Timing`        | `GET /api/v1/runs/{run_id}` and the Records reads that need `records:read`                                                                                                                                                                                                                                         | How long each stage of the read took.                                                                    |

A run status response can carry a `trace_id` field. It is the trace ID of the request that created the run.

## Health check

`GET /health` needs no key. It answers `200` whenever the API process is up:

```json theme={null}
{
  "status": "ok",
  "commit": "0f3c1a9e7b2d4c6a8e1f3b5d7a9c2e4f6b8d0a1c"
}
```

`status` is `ok` or `degraded`. `degraded` means the API is up but its database or queue did not answer a check, so some requests may fail. `commit` is the running build and is sometimes absent. The status code is `200` in both cases, so read the body. The shared middleware can still answer `500 internal_error` or `504 request_timeout`, as on any route; see [Operations](/platform/operations). There is no `/api/v1/health` route.

## Error envelope

Every error from a matched route uses the shape below. 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.

```json theme={null}
{
  "code": "engine_not_found",
  "message": "Engine not found"
}
```

| Field     | Type          | Meaning                                                                                                                                                                                |
| --------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `code`    | string        | Stable, snake\_case. Match on this.                                                                                                                                                    |
| `message` | string        | For people. The wording can change; do not parse it.                                                                                                                                   |
| `details` | any, optional | Extra structure for some codes, for example the field list on `invalid_input`, the bound on `request_bound_exceeded`, or the first run on a run submission's `idempotency_key_reused`. |

One exception: `409 environment_in_use` carries a top-level `blockers` object instead of `details`. See [Environments](/environments#deleting-a-sandbox).

Every code, with cause and fix, is in the [error reference](/reference/errors).

## Status codes

| Status | Meaning                                                                                                                                                          | Retry?                                                                                                                                                                         |
| ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `200`  | Success                                                                                                                                                          |                                                                                                                                                                                |
| `201`  | Created, for example an environment or a webhook endpoint                                                                                                        |                                                                                                                                                                                |
| `202`  | Accepted: a run was queued, or a cancel was recorded                                                                                                             |                                                                                                                                                                                |
| `204`  | Deleted, no body                                                                                                                                                 |                                                                                                                                                                                |
| `302`  | Redirect to a short-lived download URL, for example an attachment's content                                                                                      |                                                                                                                                                                                |
| `400`  | The request is malformed or failed validation                                                                                                                    | No. Fix the request                                                                                                                                                            |
| `401`  | Missing, malformed, unknown or revoked key, or a bad signature on an inbound event                                                                               | No. Fix the credential                                                                                                                                                         |
| `403`  | The key may not do this: missing capability, organization-key-only route, live key required, engine not bound, or a person's authority refuses it                | No. Change the key or the request                                                                                                                                              |
| `404`  | Not found in your org and environment                                                                                                                            | No                                                                                                                                                                             |
| `405`  | Method not allowed on this route                                                                                                                                 | No                                                                                                                                                                             |
| `409`  | Conflict with current state: an idempotency key reused with a different body, a revision conflict, an environment still in use, a data read whose cursor expired | Read current state, then decide                                                                                                                                                |
| `413`  | The body or a measured size is over its limit                                                                                                                    | No. Make the request smaller                                                                                                                                                   |
| `415`  | Unsupported file type, for example on an attachment upload                                                                                                       | No                                                                                                                                                                             |
| `422`  | Well-formed but not processable, for example an evaluation gate failed or a selection is incomplete                                                              | No. Fix the content                                                                                                                                                            |
| `428`  | A precondition header is required, for example `If-Match` with the current revision                                                                              | Add the header                                                                                                                                                                 |
| `429`  | Rate limit (`rate_limited`) or monthly run cap (`run_cap_exceeded`)                                                                                              | `rate_limited`: yes, after `Retry-After`. `run_cap_exceeded`: no                                                                                                               |
| `500`  | Nexio failed while handling the request                                                                                                                          | Yes, with backoff, for idempotent requests                                                                                                                                     |
| `501`  | A feature this route needs is not configured in this deployment                                                                                                  | No                                                                                                                                                                             |
| `502`  | An upstream provider or source system returned an error                                                                                                          | Usually, with backoff. A turn reports `provider_error` inside its `200` stream, with `reason` on the `error` frame; see the [error reference](/reference/errors#conversations) |
| `503`  | A dependency is unavailable (key store, queue, warehouse), or a capability is not enabled in this deployment                                                     | Yes, with backoff, for a dependency. Not for a capability that is not enabled                                                                                                  |
| `504`  | The request ran past its time budget (`request_timeout`) or a source did not answer in time                                                                      | Yes, with backoff                                                                                                                                                              |

## Retries

* Retry `429 rate_limited` after the `Retry-After` delay.
* Retry `500`, `502`, `503` and `504` with exponential backoff and jitter, starting near 1 second and capping near 30 seconds.
* Retry a run submission only with the same `Idempotency-Key` and the same body, so a retry never creates a second run. The one exception is `503 queue_unreachable`: Nexio already marked that run `failed`, and the same key returns the failed run, so retry it with a new `Idempotency-Key`.
* Never retry `run_cap_exceeded` in a loop. It clears only when the month rolls over or the cap is raised.
* Never retry other `4xx` codes unchanged.

## Idempotency

These surfaces deduplicate retries, each with its own key:

| Surface                                            | Key                                                        | Scope                                                                                                                    | Same key, same request                                                                                 | Same key, different request                                             |
| -------------------------------------------------- | ---------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------- |
| Run submission, `POST /api/v1/engines/{slug}/runs` | `Idempotency-Key` header, optional, at most 255 characters | Your organization, the key's environment, and the submitter: the acting principal if you send one, otherwise the API key | `202` with the original `run_id` and its current status. Nothing new is created and no run cap is used | `409 idempotency_key_reused`, with the original run in `details.run_id` |
| Records actions, `POST /api/v1/records/actions`    | `idempotency_key` in each command, a UUID, required        | Your organization's action ledger                                                                                        | `200` with the original `command_id` and `seq` and `"idempotent_replay": true`                         | `400 action_payload_invalid`                                            |

* A run key has no timer. It deduplicates for as long as its run is stored; runs are removed by the 90-day retention job. The request a run key compares covers the engine, environment, resolved version, `test_scenario`, `input` and `offerings`. Full rules are on the [Runs](/engines/runs#idempotency) page.
* Action rules are on [Writes and the action ledger](/data-services/writes#idempotency-and-safe-retries).
* An outcome's `event_id` is its idempotency key: a repeat with the same payload answers `200` and records nothing, and a different payload answers `409 event_id_reused`. Rules are on [Outcomes and annotations](/engines/outcomes-and-annotations#idempotency).

## Body size and time limits

| Limit                  | Value                                                                                                                                                                                                                                                                                                                          |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Request body           | 1 MiB on every `POST`, `PUT` and `PATCH`, unless the route has its own limit                                                                                                                                                                                                                                                   |
| Run submission body    | 1 MiB for most engines, 16 MiB for `triage` engines. See [Limits](/reference/limits)                                                                                                                                                                                                                                           |
| Environment write body | 4 KiB                                                                                                                                                                                                                                                                                                                          |
| Request time budget    | 30 seconds, then `504 request_timeout`. Exempt: `POST /api/v1/converse`, conversation turns, conversation instance publish and `POST /api/v1/records/analyses/{id}/statements`. `GET /api/v1/records/accounts/{client_key}/program-evidence` has 180 seconds. Some composite reads of one record stop at 20 seconds by default |
| No 30-second budget    | `POST /api/v1/converse`, conversation turns, conversation instance publish and `POST /api/v1/records/analyses/{id}/statements`, which stream, run evaluations or run one warehouse statement                                                                                                                                   |

## Correlate a failure with support

When you contact support, send the `x-request-id` from the response, the time in UTC, the route, and the `run_id` if there is one. Send your own `X-Request-ID` on every request to make this easier.
