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

# Events

> List and stream a session's events, resumable by sequence.

Every [session](/docs/api/sessions) emits an ordered stream of **events**, each with a monotonically increasing `seq`. You can list past events or subscribe to a live Server-Sent Events (SSE) stream. Both are **resumable**: pass the last `seq` you handled to continue with no gaps or duplicates.

Event types use a `{domain}.{action}` naming scheme. For the full catalog across all phases, see [Events & streaming](/docs/concepts/events-and-streaming).

## The event object

<ResponseField name="id" type="string">Unique id (e.g. `evt_01H...`).</ResponseField>
<ResponseField name="seq" type="integer">Monotonic sequence number within the session — starts at 1, gap-free. Use it to resume. Mirrored as `last_seq` on the session and as the SSE `id:`.</ResponseField>
<ResponseField name="type" type="string">The `{domain}.{action}` type — see [below](#event-types).</ResponseField>
<ResponseField name="session_id" type="string">The session that emitted the event.</ResponseField>
<ResponseField name="data" type="object">Type-specific payload.</ResponseField>
<ResponseField name="created_at" type="string">Emission timestamp.</ResponseField>

## Event types

| Type                | Data                                                                | Meaning                                                                                                                                                                                                                                                      |
| ------------------- | ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `message.delta`     | `text`                                                              | A chunk of assistant text.                                                                                                                                                                                                                                   |
| `message.completed` | `text`, `tokens`                                                    | An assistant message finished.                                                                                                                                                                                                                               |
| `tool.started`      | `name`, `args`                                                      | A tool call began.                                                                                                                                                                                                                                           |
| `tool.completed`    | `name`, `result`, `duration_ms`                                     | A tool call finished.                                                                                                                                                                                                                                        |
| `tool.confirm`      | `tool_call_id`, `name`, `args`                                      | A tool requires approval (`ask` [permission](/docs/api/agents)). Answer via [tool confirmations](/docs/api/sessions#respond-to-a-tool-confirmation).                                                                                                                   |
| `session.running`   | —                                                                   | The agent started a turn.                                                                                                                                                                                                                                    |
| `session.usage`     | `token_usage`, `consumed_micro_usd`, `active_seconds`, `tool_calls` | Cumulative usage snapshot, emitted before every idle/terminal transition.                                                                                                                                                                                    |
| `session.idle`      | `stop_reason`, `pending_actions?`, `structured_output`, `error?`    | A turn yielded control. Read `stop_reason` (see [session lifecycle](/docs/api/sessions#lifecycle)). `structured_output` is `null` unless an [output schema](/docs/capabilities/structured-outputs) was satisfied; `error` appears only when a required schema was not. |
| `budget.exceeded`   | `estimate_micro_usd`, `remaining_micro_usd`                         | A call was refused because it would breach the cap.                                                                                                                                                                                                          |

The `session.idle` `stop_reason` is one of `end_turn`, `awaiting_input`, `awaiting_approval`, `awaiting_answer`, `awaiting_delegation`, `budget_paused`, `interrupted`, `max_iterations`, `context_exhausted`, or `error` — the same enum as the [session object](/docs/api/sessions#lifecycle), which is where each one is explained.

Three of them park the turn on something outside the loop, and only two of those park it on a *person*: `awaiting_approval` and `awaiting_answer` both carry `pending_actions` and both wait for a reply, while `awaiting_delegation` waits for the coordinator's own children and no reply will move it.

## List events

`GET /v1/sessions/{id}/events` → `200 OK`. Past events in order (oldest-first). Resume by passing `after_seq`; combine with `limit` for paging. Events are replayable for at least 72 hours.

<ParamField query="after_seq" type="integer">Return events with `seq` **strictly greater** than this. Omit to start from the beginning.</ParamField>
<ParamField query="limit" type="integer">Max events to return. Default `20`, max `100`.</ParamField>

```bash theme={"system"}
curl -fsSL "https://api.vetta.sh/v1/sessions/ses_01H9AB.../events?after_seq=140&limit=50" \
  -H "authorization: Bearer sk_live_..."
```

<ResponseExample>
  ```json Response theme={"system"}
  {
    "data": [
      { "id": "evt_01H9II...", "seq": 141, "type": "session.running", "session_id": "ses_01H9AB...", "data": {}, "created_at": "2026-08-20T17:05:01Z" },
      { "id": "evt_01H9IJ...", "seq": 142, "type": "message.delta", "session_id": "ses_01H9AB...", "data": { "text": "Looking up order #4821…" }, "created_at": "2026-08-20T17:05:01Z" },
      { "id": "evt_01H9IK...", "seq": 143, "type": "session.idle", "session_id": "ses_01H9AB...", "data": { "stop_reason": "end_turn" }, "created_at": "2026-08-20T17:05:04Z" }
    ],
    "has_more": false,
    "next_cursor": null
  }
  ```
</ResponseExample>

## Stream events (SSE)

`GET /v1/sessions/{id}/stream?after_seq={seq}` opens a Server-Sent Events stream. Each SSE message carries one event as JSON in its `data:` field, with the event `seq` as the SSE `id:`. On reconnect, pass the last `seq` you saw as `after_seq` to replay everything since.

```bash theme={"system"}
curl -N "https://api.vetta.sh/v1/sessions/ses_01H9AB.../stream?after_seq=140" \
  -H "authorization: Bearer sk_live_..." \
  -H "accept: text/event-stream"
```

```text Stream theme={"system"}
id: 141
data: {"seq":141,"type":"session.running","data":{}}

id: 142
data: {"seq":142,"type":"message.delta","data":{"text":"Looking up order #4821…"}}

id: 143
data: {"seq":143,"type":"session.idle","data":{"stop_reason":"end_turn"}}
```

<Note>
  Track the highest `seq` you have fully processed. After any disconnect, reconnect with `?after_seq=<that seq>` — the stream is gap-free and duplicate-free from that point.
</Note>

<Info>
  `tool.confirm` pauses the turn (`stop_reason: "awaiting_approval"`) until you resolve it via [`POST /v1/sessions/{id}/tool_confirmations`](/docs/api/sessions#respond-to-a-tool-confirmation). `budget.exceeded` accompanies a `session.idle` with `stop_reason` `budget_paused`.

  **A question emits no event of its own.** An agent that calls `ask_operator` parks the same way, and the only signal on the stream is the `session.idle` — `stop_reason: "awaiting_answer"`, with the question in `pending_actions`. Answer it via [`POST /v1/sessions/{id}/answers`](/docs/api/sessions#answer-a-question). A stream reader that branches only on `tool.confirm` will sit on a session that is waiting for it.
</Info>
