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

# Runs

> Observe, resume, take over, and abort browser-driven register/login/connect runs.

A run is one browser-driven attempt: `register`, `login`, or `connect`. Runs are created by [`POST /v1/registrations`](/api-reference/registrations), `POST /v1/registrations/:id/login`, and [`POST /v1/connections`](/api-reference/connections) — there is no standalone "create run" endpoint. Observe a run by polling `GET /v1/runs/:id` or by subscribing to the [`run.blocked` / `run.completed` / `run.failed` webhooks](/api-reference/webhooks). Concepts: [Runs and human takeover](/concepts/runs-and-human-takeover).

## The run object

```json theme={null}
{
  "id": "run_8d9e0f1a2b3c4d5e6f708192a3b4c5d6",
  "type": "register",
  "status": "blocked",
  "registrationId": "reg_1c2d3e4f5a6b708192a3b4c5d6e7f801",
  "error": { "code": "CAPTCHA_REQUIRED", "detail": "captcha on the signup form" },
  "result": null,
  "liveViewUrl": "https://app.hyperbrowser.ai/live?...",
  "gatewaySessionId": "3f6a9b2c-...",
  "createdAt": "2026-07-20T11:00:00.000Z",
  "endedAt": null
}
```

| Field         | Description                                                                                                               |
| ------------- | ------------------------------------------------------------------------------------------------------------------------- |
| `type`        | `register`, `login`, or `connect`.                                                                                        |
| `status`      | See lifecycle below.                                                                                                      |
| `error`       | `{ code, detail? }` — set while `blocked` (why it needs a human) and on `failed` (why it failed). `null` otherwise.       |
| `result`      | Set on `completed` (e.g. the agent's final answer / username).                                                            |
| `liveViewUrl` | Interactive browser live view — a human can watch and drive. Set once a browser session exists; surfaced on blocked runs. |
| `endedAt`     | Set when the run reaches `completed` or `failed`.                                                                         |

## Run lifecycle

```
queued → running → awaiting_verification → completed
                 ↘ blocked (human needed) ↗
                 ↘ failed
```

| Status                  | Meaning                                                                                                                                                                            |
| ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `queued`                | Waiting for a worker slot.                                                                                                                                                         |
| `running`               | The browser agent is driving the app.                                                                                                                                              |
| `awaiting_verification` | The app sent a verification email; Sente is watching the identity's inbox and will inject the code or open the link (times out after \~8 minutes → `failed VERIFICATION_TIMEOUT`). |
| `blocked`               | The run needs a human. `error.code` says why; `liveViewUrl` is the interactive takeover surface. Held for **\~10 minutes**, then auto-fails with `BLOCKED_TIMEOUT`.                |
| `completed`             | Terminal success.                                                                                                                                                                  |
| `failed`                | Terminal failure; `error.code` says why.                                                                                                                                           |

### Blocked codes

When a run blocks, `error.code` is one of:

| Code                           | Why the run paused                                                                                                                                                                                                                               |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `CAPTCHA_REQUIRED`             | The page shows a CAPTCHA. Sente does not automate CAPTCHAs — a human completes it in the live view, then resumes.                                                                                                                                |
| `PHONE_REQUIRED`               | The app wants a phone number or SMS code. Sente has no SMS channel — a human handles it.                                                                                                                                                         |
| `SUBMIT_CONFIRMATION_REQUIRED` | You asked for `confirmBeforeSubmit`: the form is filled, a human clicks the final submit.                                                                                                                                                        |
| `MFA_REQUIRED`                 | Connected account: a second-factor code went to the owner's email or phone, which Sente cannot read. The human enters it in the live view. (Avoidable for emailed codes via `verifyToIdentity` — see [Connections](/api-reference/connections).) |
| `TOTP_REQUIRED`                | The app wants an authenticator code and no TOTP seed is vaulted (or injection failed repeatedly). With a vaulted seed this is handled server-side without blocking.                                                                              |
| `PAYMENT_REQUIRED`             | The flow is asking for payment details. Sente never enters payment data.                                                                                                                                                                         |
| `MISSING_FIELD`                | The form wants something the agent doesn't have (company name, invite code, …).                                                                                                                                                                  |
| `LOGIN_UNCONFIRMED`            | The agent could not confirm it ended up logged in.                                                                                                                                                                                               |
| `MANUAL_INTERVENTION`          | You paused the run yourself via `POST /v1/runs/:id/intervene`.                                                                                                                                                                                   |

### Failure codes

| Code                   | Why the run failed                                                                                                                                           |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `BLOCKED_TIMEOUT`      | Blocked and nobody resumed within the hold (\~10 min).                                                                                                       |
| `VERIFICATION_TIMEOUT` | No verification email arrived within the wait window.                                                                                                        |
| `AUTOMATION_STUCK`     | The agent could not make progress, or its worker died.                                                                                                       |
| `APP_UNREACHABLE`      | A resource the run depends on disappeared mid-run (e.g. its identity or registration was deleted). An unreachable target app surfaces as `AUTOMATION_STUCK`. |
| `ABORTED`              | You aborted the run.                                                                                                                                         |

A blocked-style code (e.g. `CAPTCHA_REQUIRED`) can also appear on a `failed` run when the browser session had already ended, so takeover was impossible.

## Get a run

`GET /v1/runs/:id`

```bash theme={null}
curl https://api.sente.run/v1/runs/run_8d9e0f1a2b3c4d5e6f708192a3b4c5d6 \
  -H "Authorization: Bearer sk_sente_..."
```

Response `200`: the run object. `404 {"error": "not found"}` otherwise.

## Resume a blocked run

`POST /v1/runs/:id/resume`

After a human clears the gate in the live view (completed the CAPTCHA, entered the code, clicked submit), resume hands control back to the agent, which re-checks the page state and continues.

```bash theme={null}
curl -X POST https://api.sente.run/v1/runs/run_8d9e0f1a2b3c4d5e6f708192a3b4c5d6/resume \
  -H "Authorization: Bearer sk_sente_..."
```

Response `200`: the run object with `"status": "running"` and `"error": null`.

`409 {"error": "run is not blocked", "code": "NOT_BLOCKED", "status": "running"}` if the run isn't blocked.

## Take over a live run

`POST /v1/runs/:id/intervene`

Pauses a `running` or `awaiting_verification` run so a human can drive the browser via the interactive `liveViewUrl`. The browser session stays alive. When done, `POST /:id/resume` hands back to the agent. An unresumed takeover fails `BLOCKED_TIMEOUT` after the same \~10-minute hold.

```bash theme={null}
curl -X POST https://api.sente.run/v1/runs/run_8d9e0f1a2b3c4d5e6f708192a3b4c5d6/intervene \
  -H "Authorization: Bearer sk_sente_..."
```

Response `200`: the run object with `"status": "blocked"` and `"error": { "code": "MANUAL_INTERVENTION", "detail": "paused for manual takeover" }`.

`409 {"error": "run is not intervenable", "code": "NOT_INTERVENABLE", "status": "queued"}` if the run isn't `running`/`awaiting_verification`.

## Abort a run

`POST /v1/runs/:id/abort`

Terminates a non-terminal run and stops its browser session. If the run completes concurrently, the completion wins.

```bash theme={null}
curl -X POST https://api.sente.run/v1/runs/run_8d9e0f1a2b3c4d5e6f708192a3b4c5d6/abort \
  -H "Authorization: Bearer sk_sente_..."
```

Response `200`: the run object with `"status": "failed"` and `"error": { "code": "ABORTED", "detail": "aborted by user" }`.

`409 {"error": "run is already terminal", "code": "ALREADY_TERMINAL", "status": "completed"}` if it already ended.

## Get the run recording

`GET /v1/runs/:id/recording`

The run's browser session video, ready shortly after the run ends. Poll while the recording is processing.

```bash theme={null}
curl https://api.sente.run/v1/runs/run_8d9e0f1a2b3c4d5e6f708192a3b4c5d6/recording \
  -H "Authorization: Bearer sk_sente_..."
```

Response `200`:

```json theme={null}
{ "status": "completed", "recordingUrl": "https://...mp4" }
```

| `status`                  | Meaning                                                                  |
| ------------------------- | ------------------------------------------------------------------------ |
| `pending` / `in_progress` | Still processing — poll again.                                           |
| `completed`               | `recordingUrl` is ready.                                                 |
| `failed`                  | The recording is unavailable.                                            |
| `not_enabled`             | The run never had a browser session (e.g. it failed before one started). |
