> ## 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 and human takeover

> A run is one browser-agent job — register, login, or connect. When it hits something only a human should do, it blocks, pages you, and waits.

A **run** is one browser-agent job against a third-party app. There are three run types:

* `register` — create a new account under the identity's email ([Register](/guides/register))
* `login` — re-authenticate an existing registration
* `connect` — log in to an account you already own with the credentials you supplied ([Connect](/guides/connect))

Runs are asynchronous and persisted. You start one (usually indirectly, via `POST /v1/registrations` or `POST /v1/connections`), then observe it by polling `GET /v1/runs/:id` or through [webhooks](/guides/webhooks).

## Lifecycle

```text theme={null}
queued ──► running ◄──► awaiting_verification ──► completed
              │
              ▼
           blocked ──resume──► running
              │
              └──(~10 min, no resume)──► failed (BLOCKED_TIMEOUT)
```

| Status                  | Meaning                                                                                                                                                                                     |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `queued`                | Accepted; waiting for a worker slot. One run at a time per identity.                                                                                                                        |
| `running`               | The browser agent is driving the app.                                                                                                                                                       |
| `awaiting_verification` | The app sent a verification email; Sente is completing email verification from the identity's own inbox (the annotated OTP or magic link is applied automatically — you never copy a code). |
| `blocked`               | The run hit something only a human should do. It holds and pages you (below).                                                                                                               |
| `completed`             | Terminal. The registration is `active`; the run's `result` carries the outcome.                                                                                                             |
| `failed`                | Terminal. `error.code` says why (for example `AUTOMATION_STUCK`, `VERIFICATION_TIMEOUT`, `BLOCKED_TIMEOUT`).                                                                                |

`blocked` is a stop state, not a failure: the run keeps its browser session alive and waits for a human.

## What blocks a run

Sente does not attempt to defeat these gates. Hitting one stops the run and hands it to a person — that is deliberate. The blocking gate is the site's decision to require a human, and Sente honors it.

| `error.code`                   | What happened                                                                                                      |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------ |
| `CAPTCHA_REQUIRED`             | The app presented a CAPTCHA. A human solves it in the live view.                                                   |
| `PHONE_REQUIRED`               | The app requires SMS/phone verification. Sente has no phone channel; a human handles it or the run fails.          |
| `MISSING_FIELD`                | The form needs data the run wasn't given (e.g. a company name, an invite code).                                    |
| `PAYMENT_REQUIRED`             | The app asked for payment details. Sente never enters payment data.                                                |
| `SUBMIT_CONFIRMATION_REQUIRED` | You set `confirmBeforeSubmit` — the form is filled and waiting for a human to click the final submit (below).      |
| `MFA_REQUIRED`                 | Connect runs: a second-factor code went to the account owner's email or phone. A human enters it in the live view. |
| `TOTP_REQUIRED`                | Connect runs: the app asked for an authenticator code and no TOTP seed was vaulted.                                |
| `LOGIN_UNCONFIRMED`            | The agent could not confirm it ended up signed in; a human verifies in the live view.                              |

Two connected-account MFA cases stay autonomous: if a TOTP seed was supplied at connect time, the server computes the 30-second code and submits it (the seed never reaches any model); and if the account's notification email has been repointed to the Sente identity, an email code lands in the identity's own inbox and is applied like any other verification email. Everything else — SMS codes, email codes sent to *your* inbox — needs a human.

## What happens when a run blocks

1. The run's status becomes `blocked`, with `error.code`, and `liveViewUrl` — an **interactive live browser view**. Whoever opens it sees the exact page the agent stopped on and can click and type.
2. You get paged, three ways:
   * The **`run.blocked` webhook** fires, carrying `code`, `liveViewUrl`, `actionUrl` (a dashboard deep link), and `holdExpiresAt`.
   * The org's operators get an **email** with the dashboard link (per-user opt-in in the dashboard).
   * `sente watch`, if running, fires a **desktop notification**.
3. A human opens the live view (or the run page at [app.sente.run](https://app.sente.run)), does the one thing needed — solves the CAPTCHA, enters the MFA code, fills the missing field, clicks submit — then resumes:

<CodeGroup>
  ```bash CLI theme={null}
  sente run resume <runId>
  ```

  ```ts TypeScript theme={null}
  await sente.runs.resume(runId);
  ```

  ```python Python theme={null}
  client.runs.resume(run_id)
  ```
</CodeGroup>

4. The run picks up from where it stopped — same browser, same page — and continues toward `completed`.

<Warning>
  A blocked run holds for about **10 minutes**. If nobody resumes it, it fails with `BLOCKED_TIMEOUT` and releases the browser. Wire up the `run.blocked` webhook or run `sente watch` so a block reaches a human while the hold is still open.
</Warning>

You can also abort a non-terminal run at any point: `sente run abort <runId>` / `runs.abort(id)`.

## Confirm-before-submit

For registrations, pass `confirmBeforeSubmit: true` (Python: `confirm_before_submit=True`) and the agent fills the entire signup form but **deliberately stops before the final submit**. The run blocks with `SUBMIT_CONFIRMATION_REQUIRED`; a person reviews the filled form in the live view, clicks submit themselves — so a human, not an agent, forms the agreement with the site — and then resumes the run.

Use this whenever you want a human in the loop at the moment of account creation. Registration runs should only target apps whose terms permit them; see [Acceptable use](/trust/acceptable-use).

## Observing runs

<CodeGroup>
  ```bash CLI theme={null}
  sente run show <runId>       # status, error, live-view URL
  ```

  ```ts TypeScript theme={null}
  // Poll until the run settles: terminal (completed/failed) or blocked.
  const run = await sente.runs.waitForRun(runId, { timeout: 180_000 });
  if (run.status === "blocked") console.log("needs a human:", run.liveViewUrl);
  ```

  ```python Python theme={null}
  run = client.runs.wait_for_run(run_id, timeout=180)
  if run.status == "blocked":
      print("needs a human:", run.live_view_url)
  ```
</CodeGroup>

`run.completed` and `run.failed` webhooks fire on terminal states, so a server can react without polling. Payloads and delivery semantics: [Webhooks](/guides/webhooks) and the [runs API reference](/api-reference/runs).

Runs are also rate-limited per org (429 `RUN_LIMIT_EXCEEDED` past the cap) — see [Limits](/trust/limits).

## Related

<CardGroup cols={2}>
  <Card title="Identities and registrations" href="/concepts/identities-and-registrations">
    The objects a run creates and maintains.
  </Card>

  <Card title="Register" href="/guides/register">
    Creating a new account at an app, including confirm-before-submit.
  </Card>

  <Card title="Connect" href="/guides/connect">
    Owner-authorized access to an account you already have.
  </Card>

  <Card title="Webhooks" href="/guides/webhooks">
    run.blocked, run.completed, run.failed payloads.
  </Card>
</CardGroup>
