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

# Sessions

> Start a session, follow it through its lifecycle, and know exactly when it has succeeded, stopped, or failed.

A session is one run of an agent against a task. It pins the agent version and environment at start, runs in its own sandbox, and keeps a transcript you can read, stream, and resume.

The TypeScript samples assume the `rl` client from [Client setup](/managed-agents/api#client-setup).

## Before you begin

* You need the organization developer or admin role to start, message, interrupt, cancel, or delete sessions. The organization user role can list and read sessions. The billing role cannot see sessions. See [Organizations and roles](/managed-agents/organizations-and-roles).
* For API calls, create a key under **API keys**. See [API keys](/managed-agents/api-keys).
* You need an [agent](/managed-agents/agents) and an [environment](/managed-agents/environments). If the environment has a setup script, that script must have passed a current setup run.

## How a session runs

Every session has two fields that change as it runs. `status` says whether the session is still live. `execution_state` says what the agent loop is doing right now. When the loop is not running, `stop_reason` says why.

```mermaid theme={"theme":"css-variables"}
stateDiagram-v2
  [*] --> provisioning: start accepted
  [*] --> queued: agent at its session limit
  queued --> provisioning: slot frees
  provisioning --> running
  running --> idle: interrupted, sleeping, or waiting
  idle --> running: message or wake time
  running --> completed: loop finishes
  provisioning --> failed: provisioning timed out
  running --> failed: unrecoverable error
  running --> cancelled: cancel
  idle --> cancelled: cancel
  completed --> provisioning: follow-up message
  failed --> provisioning: follow-up message
  cancelled --> provisioning: follow-up message
```

`provisioning`, `queued`, `running`, and `idle` are execution states of a session whose `status` is `active`. `completed`, `failed`, and `cancelled` are statuses. They are terminal: the session does not change on its own after reaching one. A follow-up message to a root session in a terminal status starts it again from `provisioning`. After a cancel, the session gets a new sandbox. After a completed or failed run, the sandbox is reused when possible.

| `status`         | Meaning                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `active`         | The session is live. Check `execution_state` for what it is doing.                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `completed`      | The agent loop finished. This does not by itself mean the task succeeded. See [What success means](#what-success-means).                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `failed`         | The session stopped on an error. The `failure` object explains it.                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `cancelled`      | Someone cancelled the session. Its sandbox is torn down.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `awaiting_human` | The agent asked a person to handle a step in its browser display, such as a sign-in, which can happen only when the environment has computer use on. `active_handoff` describes the request. The agent resumes when you send a `handoff_resolved` event (see [Events](/managed-agents/events)), or on its own when the hand-off deadline passes: 30 minutes unless the agent set another, at most 4 hours. Interrupting or cancelling the session also ends the hand-off. `execution_state` is `idle` with `stop_reason: requires_action`. |

| `execution_state` | Meaning                                                                                                                          |
| ----------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `provisioning`    | The sandbox is starting. This normally takes under a minute. After 5 minutes the session fails with `sandbox_provision_timeout`. |
| `queued`          | Waiting for a free slot under the agent's `max_concurrent_sessions`.                                                             |
| `running`         | The agent is working.                                                                                                            |
| `idle`            | The loop is not running. `stop_reason` is always set.                                                                            |
| `completed`       | A grader verified that the outcome was met. Always paired with `stop_reason: outcome_satisfied`.                                 |

| `stop_reason`        | Meaning                                                                                                                                      | What to do                                                                                                                          |
| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `end_turn`           | The agent finished its turn with nothing left to do. Not a success signal on its own.                                                        | Read the final message and deliverables.                                                                                            |
| `outcome_satisfied`  | The grader accepted the work.                                                                                                                | Nothing. This is success.                                                                                                           |
| `outcome_unmet`      | The grader declined the work.                                                                                                                | Read the outcome evaluation, then send guidance to try again.                                                                       |
| `max_iterations`     | The grader loop hit its revision limit.                                                                                                      | Send guidance, or [define a new outcome](/managed-agents/outcomes) with a higher `max_iterations` or a refined rubric, then resume. |
| `grader_failed`      | The grader produced no usable verdict. The work is ungraded.                                                                                 | Send a follow-up message to retry.                                                                                                  |
| `requires_action`    | The session was stopped for review after failing the same way repeatedly, or it is waiting on a browser hand-off (`status: awaiting_human`). | After a review stop, fix what blocked it, then reply to continue. For a hand-off, see `awaiting_human` above.                       |
| `sleeping`           | The agent chose to wait. The session stays `active`.                                                                                         | Nothing, or send a message to wake it before `wake_at`.                                                                             |
| `awaiting_subagents` | A coordinator is waiting for subagents to report back.                                                                                       | Nothing. See [Multi-agent sessions](/managed-agents/multi-agent).                                                                   |
| `interrupted`        | Someone interrupted or cancelled the run.                                                                                                    | Send a message to continue.                                                                                                         |
| `error`              | The loop stopped on an error.                                                                                                                | Read `failure`.                                                                                                                     |

## Start a session

<Tabs>
  <Tab title="Console">
    1. In the sidebar, click **Sessions**, then click **Launch session**.
    2. Under **Agent**, select an agent and an **Environment**.
    3. Under **Task**, write the **Opening message**. To grade the run, turn on **Grade this session against a rubric** and enter a **Rubric**.
    4. Optionally, choose vaults under **Credential access**, a mode under **Team**, and add **Custom metadata**.
    5. Click **Launch session**.
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={"theme":"css-variables"}
    const started = await rl.managedAgents.startSession({
      'Idempotency-Key': 'weekly-risk-review-2026-09-25',
      body: {
        agent_id: 'b7e1c9a4-3d62-4f15-8a07-5c2e9f6d1b38',
        environment_id: '4c8e2a61-9b3f-4d70-a5e2-1f6b8c9d0e47',
        message: 'Review the open incidents and write a risk summary named risks.md.',
        outcome: {
          description: 'risks.md lists every open incident with an owner and a severity.',
          rubric: '- risks.md lists every open incident.\n- Each incident has an owner and a severity.',
          max_iterations: 3,
        },
        metadata: { customer_id: 'acme-042', run: 'weekly' },
      },
    });
    const sessionId = started.session_id;
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={"theme":"css-variables"}
    curl -X POST 'https://api.recursion.labelbox.com/managed-agents/v1/sessions' \
      -H "Authorization: Bearer $RECURSION_API_KEY" \
      -H 'Content-Type: application/json' \
      -H 'Idempotency-Key: weekly-risk-review-2026-09-25' \
      -d '{
        "agent_id": "b7e1c9a4-3d62-4f15-8a07-5c2e9f6d1b38",
        "environment_id": "4c8e2a61-9b3f-4d70-a5e2-1f6b8c9d0e47",
        "message": "Review the open incidents and write a risk summary named risks.md.",
        "outcome": {
          "description": "risks.md lists every open incident with an owner and a severity.",
          "rubric": "- risks.md lists every open incident.\n- Each incident has an owner and a severity.",
          "max_iterations": 3
        },
        "metadata": {"customer_id": "acme-042", "run": "weekly"}
      }'
    ```
  </Tab>
</Tabs>

The response is `202 Accepted`:

```json theme={"theme":"css-variables"}
{
  "session_id": "e3a91f5c-7d24-4b68-9c10-2f8e6b4d7a53",
  "status_path": "/v1/sessions/e3a91f5c-7d24-4b68-9c10-2f8e6b4d7a53"
}
```

`202` means the session was accepted, not that it is running. Use `session_id` with [Get a session](#get-a-session) or [stream its events](/managed-agents/events). `status_path` is relative to `https://api.recursion.labelbox.com/managed-agents`. The `Location` response header carries the full path under `/managed-agents/v1/`.

### Request fields

| Field                    | Required | Description                                                                                                                                                                                                                                                                                |
| ------------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `agent_id`               | Yes      | The agent to run. The session pins the agent's current version at start and reports it as `agent_version_id`. You cannot choose an older version here.                                                                                                                                     |
| `environment_id`         | Yes      | The environment the sandbox is built from. If it has a setup script without a current passing setup run, the request fails with `422 environment_not_verified`.                                                                                                                            |
| `message`                | No       | The opening message. It stays in the agent's context for the whole run. A grader never sees it, so put success criteria in `outcome`.                                                                                                                                                      |
| `outcome`                | No       | What the grader checks: `description` and `rubric` (both required), `max_iterations` (`0` or omitted means revise until satisfied), and `grader_model_ref_id` (defaults to the session's model). If omitted, the agent's default rubric applies. See [Outcomes](/managed-agents/outcomes). |
| `skip_default_outcome`   | No       | `true` runs without the agent's default rubric.                                                                                                                                                                                                                                            |
| `vault_ids`              | No       | Vaults to grant. Omit to use the agent's default vaults. `[]` grants none. See [Vaults](/managed-agents/vaults).                                                                                                                                                                           |
| `credential_refs`        | No       | `[{ "vault_id", "credential_id" }]`. Narrows access to exactly these credentials across the granted vaults. `[]` with non-empty `vault_ids` is rejected.                                                                                                                                   |
| `referenced_session_ids` | No       | Up to 10 earlier sessions the agent may read. If you cannot read one of them, the request fails with `404` and nothing starts. See [Referenced sessions](/managed-agents/referenced-sessions).                                                                                             |
| `metadata`               | No       | Your own string key/value pairs, such as a customer id. Up to 32 entries. Keys are up to 64 characters of letters, digits, `_`, `.`, and `-`. Values are 1 to 512 characters without control characters. Metadata is fixed once the session starts.                                        |
| `team`                   | No       | `{ "mode": "auto" \| "on" \| "off" }`. Omit to keep the agent's setting, which is `auto` unless the agent sets another. See [Teams](/managed-agents/teams).                                                                                                                                |

<Note>
  Metadata can only be set at start. It is returned on the root session by `getSession` and `listSessions`, and you can filter on it. There is no call to change it later. See [Session operations](/managed-agents/session-operations) for metadata search.
</Note>

### Retry a start safely

`startSession` requires an `Idempotency-Key` header. Use a value that identifies the work, such as a job id, and reuse it on every retry of that start.

| You send                                                                                               | Result                                                                                                                                                               |
| ------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| No key                                                                                                 | `400 invalid_request`.                                                                                                                                               |
| A key that is empty, longer than 256 characters, has non-visible characters, or is sent more than once | `400 invalid_request`.                                                                                                                                               |
| The same key and the exact same request                                                                | The original `202` response again, with the header `Idempotency-Replayed: true`. No second session starts. The first response carries `Idempotency-Replayed: false`. |
| The same key with a different body, path, or query                                                     | `409 idempotency_conflict`.                                                                                                                                          |
| The same key while the first request is still being processed                                          | `409 idempotency_in_progress` with `Retry-After`. Wait and retry.                                                                                                    |
| The same key after the first attempt failed with a non-2xx response                                    | The key is released. The retry runs as a new attempt.                                                                                                                |

Keys are shared across your whole organization, so include something unique to the caller. A key is remembered for about 24 hours. After that, the same key may start a new session. The session id is derived from the key, so a replay always returns the same `session_id`.

## What success means

When the agent loop finishes, `status` becomes `completed` whether or not the task succeeded. Read `execution_state` and `stop_reason` to know the result.

| You see                                                                                                          | Result                                                                                         |
| ---------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| `status: completed`, `execution_state: completed`, `stop_reason: outcome_satisfied`                              | Success. The grader verified the outcome.                                                      |
| `status: completed`, `execution_state: idle`, `stop_reason: end_turn`                                            | The agent finished without a grader. Check its final message and deliverables.                 |
| `status: completed`, `execution_state: idle`, `stop_reason: outcome_unmet`, `max_iterations`, or `grader_failed` | The run finished but the outcome was not verified. Resume with guidance or refine the outcome. |
| `status: failed`                                                                                                 | The session hit an error. Read `failure`.                                                      |
| `status: cancelled`                                                                                              | The session was cancelled. Events and outcomes stay readable.                                  |
| `status: active`, `execution_state: idle`, `stop_reason: interrupted` or `sleeping`                              | Not finished. The session is paused and waits for a message or its wake time.                  |
| `status: active`, `execution_state: idle`, `stop_reason: requires_action`                                        | Not finished. The session needs your review before it continues.                               |

When a session fails, `failure` holds `phase`, `code`, `message`, `retryable`, `category`, and `at`. `category` is `transient` (retry), `caller_error` (fix the request or setup), or `internal`.

## Wait for a session to finish

Stream the session's events for live progress; the stream closes when the session reaches a terminal status. See [Stream events](/managed-agents/events). To poll instead, stop on any terminal status, not only `completed`, and also stop when the session needs you.

<Tabs>
  <Tab title="Console">
    Open the session from **Sessions**. The transcript updates live, and the status badge shows the current state.
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={"theme":"css-variables"}
    const terminal = new Set(['completed', 'failed', 'cancelled']);
    let session = await rl.managedAgents.getSession({ session_id: sessionId, view: 'summary' });
    while (
      !terminal.has(session.status) &&
      session.stop_reason !== 'requires_action'
    ) {
      await new Promise((resolve) => setTimeout(resolve, 5000));
      session = await rl.managedAgents.getSession({ session_id: sessionId, view: 'summary' });
    }
    const succeeded = session.stop_reason === 'outcome_satisfied';
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={"theme":"css-variables"}
    curl 'https://api.recursion.labelbox.com/managed-agents/v1/sessions/e3a91f5c-7d24-4b68-9c10-2f8e6b4d7a53?view=summary' \
      -H "Authorization: Bearer $RECURSION_API_KEY"
    ```
  </Tab>
</Tabs>

<Warning>
  An interrupted or sleeping session stays `active`. A loop that waits only for a terminal status keeps waiting until someone sends a message, the wake time arrives, or the session is cancelled.
</Warning>

## Get a session

`view=full` (the default) returns the whole session, including the agent and model snapshots and the resolved configuration. `view=summary` omits `agent_snapshot`, `model_snapshot`, and `config`, which makes polling cheaper. Any other `view` value returns `400`.

<Tabs>
  <Tab title="Console">
    In **Sessions**, click a session. The **Session** tab shows its state, agent, environment, and **Custom metadata**.
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={"theme":"css-variables"}
    const session = await rl.managedAgents.getSession({
      session_id: 'e3a91f5c-7d24-4b68-9c10-2f8e6b4d7a53',
      view: 'summary',
    });
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={"theme":"css-variables"}
    curl 'https://api.recursion.labelbox.com/managed-agents/v1/sessions/e3a91f5c-7d24-4b68-9c10-2f8e6b4d7a53?view=summary' \
      -H "Authorization: Bearer $RECURSION_API_KEY"
    ```
  </Tab>
</Tabs>

```json theme={"theme":"css-variables"}
{
  "session_id": "e3a91f5c-7d24-4b68-9c10-2f8e6b4d7a53",
  "root_session_id": "e3a91f5c-7d24-4b68-9c10-2f8e6b4d7a53",
  "session_path": "/",
  "kind": "chat",
  "status": "completed",
  "execution_state": "completed",
  "stop_reason": "outcome_satisfied",
  "agent_id": "b7e1c9a4-3d62-4f15-8a07-5c2e9f6d1b38",
  "agent_version_id": "9d2f7b1e-6c43-4a85-b0e9-3a7c5d8f2e16",
  "environment_id": "4c8e2a61-9b3f-4d70-a5e2-1f6b8c9d0e47",
  "metadata": { "customer_id": "acme-042", "run": "weekly" },
  "created_at": "2026-09-25T14:02:11Z",
  "updated_at": "2026-09-25T14:19:48Z",
  "last_activity_at": "2026-09-25T14:19:48Z"
}
```

| Field                                                  | Description                                                                                                                                              |
| ------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `root_session_id`, `parent_session_id`, `session_path` | Where the session sits in its tree. A root has `session_path` `/` and no parent.                                                                         |
| `kind`                                                 | `chat` for sessions you start, `subagent` for sessions an agent starts, `session_analyst` for the [session analyst](/managed-agents/session-operations). |
| `agent_version_id`                                     | The agent version pinned at start.                                                                                                                       |
| `metadata`                                             | Set at start. Present on root sessions only.                                                                                                             |
| `wake_at`                                              | When a sleeping session wakes on its own.                                                                                                                |
| `concurrency_slot_held`                                | Whether the session counts against the agent's `max_concurrent_sessions`.                                                                                |
| `failure`                                              | Present only after a failure.                                                                                                                            |

## List sessions

`listSessions` returns sessions in your organization, most recently updated first.

<Tabs>
  <Tab title="Console">
    In the sidebar, click **Sessions**. Filter with **Status**, **Agent**, **Agent tags**, and **Metadata**, or search by id, agent, state, or metadata.
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={"theme":"css-variables"}
    const page = await rl.managedAgents.listSessions({
      status: 'failed',
      agent_id: 'b7e1c9a4-3d62-4f15-8a07-5c2e9f6d1b38',
      metadata: ['customer_id:acme-042'],
      root_only: true,
      limit: 50,
    });
    const next = page.next_page_token
      ? await rl.managedAgents.listSessions({
          status: 'failed',
          agent_id: 'b7e1c9a4-3d62-4f15-8a07-5c2e9f6d1b38',
          metadata: ['customer_id:acme-042'],
          root_only: true,
          limit: 50,
          page_token: page.next_page_token,
        })
      : undefined;
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={"theme":"css-variables"}
    curl 'https://api.recursion.labelbox.com/managed-agents/v1/sessions?status=failed&metadata=customer_id:acme-042&root_only=true&limit=50' \
      -H "Authorization: Bearer $RECURSION_API_KEY"
    ```
  </Tab>
</Tabs>

| Parameter      | Description                                                                                                                                                                                             |
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `status`       | One status, such as `failed`.                                                                                                                                                                           |
| `kind`         | Comma-separated kinds, matched as OR: `chat`, `subagent`, `session_analyst`. Analyst sessions appear only when you name `session_analyst`.                                                              |
| `agent_id`     | Sessions of one agent.                                                                                                                                                                                  |
| `tag_ids`      | Comma-separated agent tag ids, up to 32. A session matches only if its agent currently has every tag. An unknown tag id returns `404`.                                                                  |
| `metadata`     | `key:value`, repeatable up to 32 times. All pairs must match. The value is everything after the first colon. Child sessions of a matching root also match, so add `root_only=true` for one row per run. |
| `metadata_key` | A key that must be present, repeatable up to 32 times.                                                                                                                                                  |
| `root_only`    | `true` returns root sessions only.                                                                                                                                                                      |
| `limit`        | Page size. Default 100, maximum 1000. Larger values are reduced to 1000.                                                                                                                                |
| `page_token`   | The `next_page_token` from the previous page.                                                                                                                                                           |

A page token is valid for one hour and only with the same filters and `limit`. Changing either returns `400 invalid_request`; start again without a token. Because the list is ordered by last update, a session that changes while you page can appear twice or be skipped. Deduplicate by `session_id`, or filter on a value that does not change.

List rows are summaries. They leave out snapshots, and `config` is empty. Token and cost totals are not included; see [Usage and cost](/managed-agents/usage-and-cost).

## Send a follow-up message

A message to a running session is read at its next turn. A message to an idle or finished root session resumes it. The full send options, including the delivery states in the response, are in [Events](/managed-agents/events).

<Tabs>
  <Tab title="Console">
    Open the session, type in **Message the agent…**, and click **Send**. While the agent is working the button reads **Queue**.
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={"theme":"css-variables"}
    const sent = await rl.managedAgents.sendSessionEvents({
      session_id: 'e3a91f5c-7d24-4b68-9c10-2f8e6b4d7a53',
      body: { message: 'Also add a mitigation for each high-severity item.' },
    });
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={"theme":"css-variables"}
    curl -X POST 'https://api.recursion.labelbox.com/managed-agents/v1/sessions/e3a91f5c-7d24-4b68-9c10-2f8e6b4d7a53/events' \
      -H "Authorization: Bearer $RECURSION_API_KEY" \
      -H 'Content-Type: application/json' \
      -d '{"message": "Also add a mitigation for each high-severity item."}'
    ```
  </Tab>
</Tabs>

```json theme={"theme":"css-variables"}
{ "ok": true, "delivery_state": "resumed", "events_accepted": 1 }
```

Only root sessions resume. A message to a subagent session in a terminal status returns `409 conflict`; message the root session instead.

## Send an image

To show the agent a screenshot or chart that isn't in your [Files](/managed-agents/files) library, upload it to the session, then reference it from a message. The model sees the image when its model accepts images.

<Tabs>
  <Tab title="Console">
    In the session's message box, click **Attach image**, choose the image, write your message, and click **Send**. To use an image from your library, click **Attach from Files**.
  </Tab>

  <Tab title="cURL">
    ```bash theme={"theme":"css-variables"}
    curl -X POST 'https://api.recursion.labelbox.com/managed-agents/v1/sessions/e3a91f5c-7d24-4b68-9c10-2f8e6b4d7a53/files' \
      -H "Authorization: Bearer $RECURSION_API_KEY" \
      -F 'file=@error.png'
    curl -X POST 'https://api.recursion.labelbox.com/managed-agents/v1/sessions/e3a91f5c-7d24-4b68-9c10-2f8e6b4d7a53/events' \
      -H "Authorization: Bearer $RECURSION_API_KEY" \
      -H 'Content-Type: application/json' \
      -d '{"events": [{"type": "user.message", "content": [
        {"type": "text", "text": "This error appears after sign-in. What causes it?"},
        {"type": "image", "uri": "<the uri from the upload>"}
      ]}]}'
    ```
  </Tab>
</Tabs>

The upload returns `201` with the stored image:

```json theme={"theme":"css-variables"}
{
  "uri": "<private image URI>",
  "media_type": "image/png",
  "byte_size": 184233,
  "width": 1280,
  "height": 800,
  "sha256": "2d8b4e0a1c7f5d934f1c9a0e7b2d5836c1e04a9f7d3b6e2a8c5f0d1b9e7a3c6f"
}
```

* Send PNG, JPEG, or WebP. The type is detected from the bytes. You can also send the bytes as the raw request body with an image `Content-Type`.
* The `uri` works only in the session it was uploaded to. An upload that no message references is removed after a while.
* An image the session's image limits refuse returns `400` with the reason. See [Limits](/managed-agents/limits).

## Interrupt a session

An interrupt stops the current model call right away and gives a running tool a short grace period to stop. If messages are queued, the newest starts a fresh turn. Otherwise the session stays `active` and goes `idle` with `stop_reason: interrupted`, ready for your next message. The sandbox stays up.

<Tabs>
  <Tab title="Console">
    While the agent is working, open the session and click **Interrupt** under the last event.
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={"theme":"css-variables"}
    const { interrupted } = await rl.managedAgents.interruptSession({
      session_id: 'e3a91f5c-7d24-4b68-9c10-2f8e6b4d7a53',
      body: {},
    });
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={"theme":"css-variables"}
    curl -X POST 'https://api.recursion.labelbox.com/managed-agents/v1/sessions/e3a91f5c-7d24-4b68-9c10-2f8e6b4d7a53/interrupt' \
      -H "Authorization: Bearer $RECURSION_API_KEY" \
      -H 'Content-Type: application/json' \
      -d '{}'
    ```
  </Tab>
</Tabs>

```json theme={"theme":"css-variables"}
{ "interrupted": true }
```

`interrupted: false` means nothing was running to stop. That is not an error.

## Interrupt and send a new message

`interruptAndSendSessionMessage` stops the current turn and starts a fresh one with your message in one call. Send `message` for plain text, or `content` for content blocks; `content` wins if you send both.

<Tabs>
  <Tab title="Console">
    Type your message in **Message the agent…** and click **Interrupt & send**. The button appears while the agent is working.
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={"theme":"css-variables"}
    const sent = await rl.managedAgents.interruptAndSendSessionMessage({
      session_id: 'e3a91f5c-7d24-4b68-9c10-2f8e6b4d7a53',
      body: { message: 'Stop. Only cover incidents opened this week.' },
    });
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={"theme":"css-variables"}
    curl -X POST 'https://api.recursion.labelbox.com/managed-agents/v1/sessions/e3a91f5c-7d24-4b68-9c10-2f8e6b4d7a53/interrupt-and-send' \
      -H "Authorization: Bearer $RECURSION_API_KEY" \
      -H 'Content-Type: application/json' \
      -d '{"message": "Stop. Only cover incidents opened this week."}'
    ```
  </Tab>
</Tabs>

The response has the same shape as a send, with `events_accepted: 2`: the interrupt and your message.

## Cancel a session

Cancelling stops the session now. In-flight work is abandoned, the sandbox is torn down, and the status becomes `cancelled` with `stop_reason: interrupted`. Events, outcomes, and deliverables stay readable. A follow-up message to a cancelled root session starts it again in a new sandbox.

<Tabs>
  <Tab title="Console">
    1. Open the session, then open **Session actions** and click **Hard stop…**.
    2. Click **Stop now**.
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={"theme":"css-variables"}
    await rl.managedAgents.cancelSession({ session_id: 'e3a91f5c-7d24-4b68-9c10-2f8e6b4d7a53' });
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={"theme":"css-variables"}
    curl -X POST 'https://api.recursion.labelbox.com/managed-agents/v1/sessions/e3a91f5c-7d24-4b68-9c10-2f8e6b4d7a53/cancel' \
      -H "Authorization: Bearer $RECURSION_API_KEY"
    ```
  </Tab>
</Tabs>

```json theme={"theme":"css-variables"}
{ "cancelled": true }
```

The response is the same when the session was already finished, so it is safe to repeat. Sandbox teardown can finish shortly after the response.

## Delete a session

Deleting removes the session and all its subagent sessions from lists and reads, stops any running work, and tears down the sandbox. The transcript is retained, not erased. You cannot undo a delete.

<Tabs>
  <Tab title="Console">
    1. Open the session, then open **Session actions** and click **Delete session…**.
    2. Click **Delete**.
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={"theme":"css-variables"}
    await rl.managedAgents.deleteSession({ session_id: 'e3a91f5c-7d24-4b68-9c10-2f8e6b4d7a53' });
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={"theme":"css-variables"}
    curl -X DELETE 'https://api.recursion.labelbox.com/managed-agents/v1/sessions/e3a91f5c-7d24-4b68-9c10-2f8e6b4d7a53' \
      -H "Authorization: Bearer $RECURSION_API_KEY"
    ```
  </Tab>
</Tabs>

```json theme={"theme":"css-variables"}
{ "deleted": true }
```

## Get the deliverables

Ask for deliverables by name in your message, for example "write a risk summary named `risks.md`". Agents already know where to save files so they are kept after the session ends. Only files saved there are kept; anything else in the sandbox is lost when it is torn down. Download them from the session's **Files** tab, or with `listFiles` and `getFileContent`. See [Deliverables and artifacts](/managed-agents/artifacts) and [Download session deliverables](/managed-agents/files#download-session-deliverables).

To give a session input files, attach them at start with `resources` or while it runs. See [Files](/managed-agents/files).

## What can go wrong

| Symptom or code                                                               | Cause                                                                                 | Fix                                                                                        |
| ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
| `400 invalid_request` on `Idempotency-Key`                                    | The header is missing, malformed, or sent twice.                                      | Send exactly one key of 1 to 256 visible characters.                                       |
| `409 idempotency_conflict`                                                    | The key was used for a different request.                                             | Use a new key for different work.                                                          |
| `409 idempotency_in_progress`                                                 | The first request with this key is still running.                                     | Wait for `Retry-After`, then retry with the same key.                                      |
| `422 environment_not_verified`                                                | The environment's setup script has not passed a current setup run.                    | Run environment setup, then start again. See [Environments](/managed-agents/environments). |
| `404 not_found` on start                                                      | An agent, environment, vault, or referenced session is missing or not visible to you. | Check each id and your access.                                                             |
| `400 invalid_request` on `metadata`                                           | Too many entries, a bad key, or an empty or too-long value.                           | Keep to 32 entries and the key and value rules above.                                      |
| `400 invalid_request` on `page_token`                                         | The token expired or the filters changed.                                             | List again without a token.                                                                |
| The session stays `provisioning`, then fails with `sandbox_provision_timeout` | The sandbox did not start within 5 minutes.                                           | Start again. If it repeats, check the environment.                                         |
| The session stays `queued`                                                    | The agent is at `max_concurrent_sessions`.                                            | Wait, cancel other sessions, or raise the agent limit.                                     |
| `status: completed` but the task is not done                                  | The loop finished without a satisfied outcome.                                        | Check `stop_reason`. See [What success means](#what-success-means).                        |
| A poller never returns                                                        | The session is interrupted or sleeping and stays `active`.                            | Stop on `idle` states you care about, or send a message.                                   |
| `409 conflict` when messaging or deleting                                     | A cancel is still finishing.                                                          | Retry after a few seconds.                                                                 |
| `409 conflict` when messaging a subagent                                      | Subagent sessions in a terminal status do not resume.                                 | Message the root session.                                                                  |
| `429 rate_limit_exceeded`                                                     | Too many requests.                                                                    | Back off and retry after `Retry-After`.                                                    |

Every error uses the same body: `code`, `message`, and `details` with `field`, `requestId`, and `retryable`. See [Errors](/managed-agents/errors).

## Limits

* Metadata: 32 entries per session, 64-character keys, 512-character values.
* Referenced sessions: 10 per start.
* List page size: 1000.
* Provisioning: 5 minutes.
* Concurrency is set per agent with `max_concurrent_sessions`.

See [Limits](/managed-agents/limits) for the rest.

## Next steps

<CardGroup cols={2}>
  <Card title="Events" icon="wave-pulse" href="/managed-agents/events">
    Send messages, read the transcript, and stream live events.
  </Card>

  <Card title="Session operations" icon="gauge" href="/managed-agents/session-operations">
    Search metadata, inspect compute, ask the analyst, and read the tree.
  </Card>

  <Card title="Outcomes" icon="bullseye" href="/managed-agents/outcomes">
    Define what success means and let a grader check it.
  </Card>

  <Card title="Deliverables and artifacts" icon="box-archive" href="/managed-agents/artifacts">
    Ask for deliverables and see how they're kept.
  </Card>
</CardGroup>
