> ## 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.

# Operations

> Check platform health, tell which build answered, understand what happens to runs during a deploy, recover failed work, and escalate to Nexio with what support needs.

This page covers what your integration sees of how Nexio runs the platform: the health endpoint, the build header, deploys, how runs survive them, how to recover failed work, and how to reach support.

## Health

`GET https://api.usenexio.com/health` needs no API key and is not rate limited.

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

| Field    | Meaning                                                                                                     |
| -------- | ----------------------------------------------------------------------------------------------------------- |
| `status` | `ok` when the API can reach its database and job queue. `degraded` when either check fails within 3 seconds |
| `commit` | The build of the API that answered. Omitted when the build is not stamped                                   |

The HTTP status is 200 whenever the health handler answers, including when `status` is `degraded`: database or queue trouble never changes the status code, so read the body. Like every route, `/health` passes through the shared request middleware, which answers `500 internal_error` if the handler fails unexpectedly and `504 request_timeout` if it runs past the 30-second request limit. Treat either as the API not answering. There is no `/api/v1/health` route.

## Which build answered

Responses from the Records routes (`/api/v1/records` and below) carry the header `X-Nexio-Engine-Build` with the same commit as `/health`, when the build is stamped. Use it to key a cache to the build that produced the data. Responses refused before they reach those routes (401 for a bad key, 429 for a rate limit) do not carry it. Neither does a `504 request_timeout` or a `500 internal_error` written when the request times out or fails unexpectedly. Other route families do not send it.

Every response also carries `x-request-id`. Send your own `x-request-id` (1 to 128 printable ASCII characters, no spaces) and the API echoes it back and records it in its access log. A missing or invalid value is replaced by the request's 32-character trace ID.

## Deploys

Nexio deploys continuously: every change merged to its main branch goes to production after automated checks. A deploy counts as done only when production reports the new commit on `/health` and a production smoke test passes; otherwise it is rolled back automatically. The API has no maintenance mode, and deploys do not take it offline: a stopping API instance finishes its in-flight requests for up to 10 seconds before it exits.

## Runs during a deploy

A run is processed by a worker. When a worker stops for a deploy, it gives each run a grace period to finish.

| What happens                                   | What you see when you poll the run                                                                                                                                                                                           | What to do           |
| ---------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- |
| The run finishes within the grace period       | The normal final status                                                                                                                                                                                                      | Nothing              |
| The run does not finish in time                | `status: "processing"` with `error_details.type: "worker_interrupted"`, `code: "worker_shutdown"`, `restarting: true`, message "The engine is restarting this run on another worker." The run starts again on another worker | Keep polling         |
| The restarted run is interrupted a second time | `status: "failed"`, error "The engine was interrupted while working on this account; submit it again"                                                                                                                        | Submit the run again |

Run statuses and polling are defined on [Runs](/engines/runs).

## Stuck and lost runs

Workers record a heartbeat on every run they process. Nexio's worker checks for runs that stopped reporting:

* A running run with no heartbeat for 3 minutes (15 minutes if it never reported one) is reclaimed and restarted once. It stays `processing`. If it goes silent again, it fails and is not retried.
* A run that no worker holds any more fails with the error "worker restarted: run did not complete" and `error_details.type: "pipeline_error"`. A matching engine's run fails instead with an error of the form `matching run timed out during {stage} after its worker lease expired` and `error_details.type: "pipeline_timeout"`, with the stage in `error_details.stage`.
* A run with a pending cancel request is marked cancelled instead.

A failed run is final. To try again, submit a new run with a new `Idempotency-Key`: sending the original key again returns the original failed run, because the key stays bound for as long as that run is stored (see [Runs](/engines/runs)).

## Cancelling a run

`POST /api/v1/runs/{run_id}/cancel` stops a run that is `queued` or `processing`.

* A queued run is cancelled at once: the response is 202 with `status: "cancelled"`.
* A processing run is asked to stop: the response is 202 with `status: "processing"` and `cancel_requested_at`. The worker checks for cancel requests every 2 seconds, then marks the run cancelled and sends the `run.cancelled` webhook event.
* A run that already finished answers 200 with its status fields and stored output, without `solutions` and the other fields only `GET /api/v1/runs/{run_id}` adds. Read the result with `GET`.

The reason from the first cancel request is kept. See [Runs](/engines/runs) for the full lifecycle.

## Failed deliveries and recovery

| What failed                                            | Where you see it                                                                                                                                                                                                                                                    | How it is recovered                                                                                                                                                                                                       |
| ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| A webhook delivery to your endpoint                    | Its status becomes `dead_letter` after the retry budget runs out, or at once if your endpoint answers with a permanent error. Visible in **Settings, then Webhooks**, on the endpoint's Deliveries tab, and through `GET /api/v1/webhooks/{endpoint_id}/deliveries` | You resend it, from the Deliveries tab or with `POST /api/v1/webhooks/{endpoint_id}/deliveries/{delivery_id}/resend`. The resend keeps the same delivery id and payload. See [Webhooks](/api-reference/webhooks/overview) |
| An event you send to the inbound events route          | The response tells you the outcome (`appended`, `ignored` or `rejected`)                                                                                                                                                                                            | Send it again with the same delivery id. The platform records each delivery id once, so a repeat of the same body returns the stored outcome and never appends twice. See [Inbound events](/events/inbound)               |
| An automation Nexio runs for you, or a connection sync | Not shown to you                                                                                                                                                                                                                                                    | Nexio replays failed automation steps and failed sync work. Contact support if you see stale data                                                                                                                         |

## Rate limits and caps

The API limits requests per minute and can cap runs per month for an organization. A rate-limit refusal is `429 rate_limited` with a `Retry-After` header. A monthly cap refusal is `429 run_cap_exceeded` with no `Retry-After`: it does not clear until the next month. Limits, defaults and the monthly run cap are on [Limits and rate limits](/reference/limits).

## Escalate to Nexio

Email [support@usenexio.com](mailto:support@usenexio.com). Include:

| Include                                                 | Where to find it                                        |
| ------------------------------------------------------- | ------------------------------------------------------- |
| The `x-request-id` of the failing request               | Response header on every API response                   |
| The run id, and the run's `trace_id` if it has one      | The run submission response, or the run status response |
| The time of the request, in UTC                         | Your logs                                               |
| The endpoint, the HTTP status, and the error `code`     | The response                                            |
| The environment and the API key id (never the full key) | Your configuration                                      |

<CardGroup cols={2}>
  <Card title="Runs" href="/engines/runs">
    Statuses, polling, idempotency and cancellation.
  </Card>

  <Card title="Errors" href="/reference/errors">
    Every error code and what to do about it.
  </Card>
</CardGroup>
