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

# Get session changes

> Long-poll for real-time session updates.

export const ChangesLoop = () => {
  const Node = ({left, top, width, height, title, sub}) => <div className="absolute rounded-xl border border-zinc-200 bg-white p-4 dark:border-zinc-800 dark:bg-zinc-950" style={{
    left,
    top,
    width,
    height
  }}>
      <div className="font-mono text-[13px] font-medium text-zinc-900 dark:text-zinc-100">{title}</div>
      <div className="mt-1 text-[11.5px] leading-4 text-zinc-400 dark:text-zinc-500">{sub}</div>
    </div>;
  const Label = ({left, top, width, children, strong}) => <div className={`absolute text-center text-[11px] ${strong ? "text-zinc-500 dark:text-zinc-400" : "text-zinc-400 dark:text-zinc-500"}`} style={{
    left,
    top,
    width
  }}>{children}</div>;
  return <div className="not-prose my-6 overflow-x-auto">
      <div className="relative mx-auto" style={{
    width: 720,
    height: 250
  }}>
        <svg className="absolute inset-0 text-zinc-300 dark:text-zinc-600" width="720" height="250" viewBox="0 0 720 250" fill="none" stroke="currentColor" strokeWidth="1.25" strokeLinecap="round" strokeLinejoin="round">
          <path d="M214 134 H300" /><path d="M295 129 L300 134 L295 139" />
          <path d="M470 134 H540" /><path d="M535 129 L540 134 L535 139" />
          <path d="M69 88 C69 56 169 56 169 88" /><path d="M164 83 L169 88 L174 83" />
          <path d="M385 180 V222 H119 V180" /><path d="M114 185 L119 180 L124 185" />
        </svg>

        <Node left={24} top={88} width={190} height={92} title="GET /changes" sub="?from_index · wait 25s" />
        <Node left={300} top={88} width={170} height={92} title="GET /status" sub="authoritative liveness" />

        <div className="absolute flex flex-col justify-center rounded-xl border border-transparent bg-zinc-900 px-4 dark:bg-zinc-100" style={{
    left: 540,
    top: 102,
    width: 160,
    height: 64
  }}>
          <div className="text-[13px] font-medium text-white dark:text-zinc-900">answer ready</div>
          <div className="mt-0.5 text-[11px] leading-4 text-zinc-400 dark:text-zinc-500">drain, read answer</div>
        </div>

        <Label left={232} top={110} width={50} strong>200</Label>
        <Label left={19} top={32} width={200}>204 · nothing new</Label>
        <Label left={470} top={108} width={70} strong>settled</Label>
        <Label left={470} top={138} width={70}>yes</Label>
        <Label left={162} top={226} width={180}>no · poll again</Label>
      </div>
    </div>;
};

Returns a stream of changes (events, status transitions, agent actions) that have occurred since your last request. Uses **long polling**: the server holds the connection open until new changes are available or the timeout expires.

**Returns** `200` with a `SessionChanges` object, or `204 No Content` if no new events arrive within the wait period.

`changes` is a delta: each call returns only what's new since `from_index`, and `204` when nothing new has arrived yet. Note that `status` can read `completed` while events (including the [`answer`](#response)) are still unread on later pages, so keep advancing `from_index` until the session is [terminal](/computer-use-agents/sessions/overview#lifecycle) *and* a poll returns no further events. To skip the loop entirely and just read a finished run's result, use [`latest_answer`](/computer-use-agents/sessions/retrieve); the [SDK helper](#long-polling-pattern) drains for you.

***

## Path parameters

<ParamField path="id" type="string" required>
  The session ID.
</ParamField>

***

## Query parameters

<ParamField query="from_index" type="integer" default="0">
  Event index to start from. Use this to resume from where you left off.
</ParamField>

<ParamField query="limit" type="integer">
  Maximum number of events to return.
</ParamField>

<ParamField query="include_events" type="boolean" default="true">
  Whether to include event details in the response.
</ParamField>

<ParamField query="wait_for_seconds" type="integer" default="0">
  How long the server should hold the connection waiting for changes, up to `25` seconds. The default `0` returns immediately; set `20` to `25` for efficient long polling.
</ParamField>

***

## Response

```json Response theme={null}
{
  "status": "running",
  "started_at": "2026-05-07T14:30:02Z",
  "finished_at": null,
  "error": null,
  "error_code": null,
  "answer": null,
  "outcome": null,
  "metrics": {
    "steps": 2,
    "total_cost": 0.0093874,
    "input_cost": 0.0084664,
    "output_cost": 0.000921,
    "reasoning_cost": 0.0,
    "cost_per_model": [
      {
        "name": "holo3-122b-a10b",
        "input_tokens": 21166,
        "output_tokens": 307,
        "reasoning_tokens": 0,
        "input_cost": 0.0084664,
        "output_cost": 0.000921,
        "reasoning_cost": 0.0,
        "total_cost": 0.0093874
      }
    ]
  },
  "new_events": [
    { "type": "AgentEvent", "data": { "...": "..." }, "timestamp": "2026-05-07T14:30:05Z" }
  ]
}
```

| Field         | Type                     | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| ------------- | ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `status`      | string                   | Current session status.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `started_at`  | string \| null           | ISO 8601 timestamp when the agent started executing.                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `finished_at` | string \| null           | ISO 8601 timestamp when the session reached a terminal state.                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `error`       | string \| null           | Short, stable error message if the session failed or timed out. Branch on `error_code`, not on this text.                                                                                                                                                                                                                                                                                                                                                                                                            |
| `error_code`  | string \| null           | Machine-readable failure category when the session failed or timed out: `environment_error`, `no_answer`, `answer_validation`, `timeout`, or `internal`. See [Read how the run ended](/computer-use-agents/observe-and-steer#read-how-the-run-ended).                                                                                                                                                                                                                                                                |
| `outcome`     | string \| null           | The agent's self-assessed task outcome, reported with its final answer: `success`, `partial`, `infeasible`, or `blocked`. See [Read how the run ended](/computer-use-agents/observe-and-steer#outcomes).                                                                                                                                                                                                                                                                                                             |
| `answer`      | string \| object \| null | The agent's final result once produced; `null` otherwise. A string by default, or an object matching the agent's [`answer_format`](/computer-use-agents/agents/overview) JSON Schema when one was set. It rides the page that delivers the final events, so keep polling until the session is [terminal](/computer-use-agents/sessions/overview#lifecycle) and drained. For a cursor-independent read, the same value is mirrored on the [Session object](/computer-use-agents/sessions/overview)'s `latest_answer`. |
| `metrics`     | object                   | Usage and cost rolled up to the moment of the response: `steps`, `total_cost`, `input_cost`, `output_cost`, `reasoning_cost`, and `cost_per_model[]` (each entry carries per-model tokens and costs, including `reasoning_tokens`). Cost fields are in USD and are `null` when a model's price is unavailable, so null-check before summing.                                                                                                                                                                         |
| `new_events`  | array                    | Events since `from_index`, each following the [event shape](/computer-use-agents/sessions/events#event-shape) (`type`, `data`, `timestamp`).                                                                                                                                                                                                                                                                                                                                                                         |

***

## Examples

<CodeGroup>
  ```bash cURL theme={null}
  curl "https://agp.eu.hcompany.ai/api/v2/sessions/$SESSION_ID/changes?from_index=0&wait_for_seconds=25" \
    -H "Authorization: Bearer $HAI_API_KEY"
  ```

  ```python Python theme={null}
  from hai_agents import Client

  client = Client()

  changes = client.sessions.get_session_changes(
      session_id,
      from_index=0,
      wait_for_seconds=25,
  )
  ```

  ```typescript TypeScript theme={null}
  import { HaiAgentsClient } from "hai-agents";

  const client = new HaiAgentsClient();

  const changes = await client.sessions.getSessionChanges({
    id: sessionId,
    fromIndex: 0,
    waitForSeconds: 25,
  });
  ```
</CodeGroup>

***

## Long-polling pattern

Long polling is more efficient than repeated status checks because the server only responds when something actually changes. The SDK ships a helper that runs the loop for you: it drives termination off `status` (authoritative) while streaming events from `changes`, resuming `from_index` and handling the `204` no-change responses automatically.

<ChangesLoop />

<CodeGroup>
  ```python Python theme={null}
  from hai_agents import wait_for_session

  result = wait_for_session(client, session_id, wait_for_seconds=25)

  for event in result.events:
      print(event.type)
  print(result.status, result.answer)

  # client.run_session(...) creates the session and runs this loop in one call.
  ```

  ```typescript TypeScript theme={null}
  import { waitForSession } from "hai-agents";

  const result = await waitForSession(client, { id: sessionId, waitForSeconds: 25 });

  for (const event of result.events) {
    console.log(event.type);
  }
  console.log(result.status, result.answer);

  // client.runSession(...) creates the session and runs this loop in one call.
  ```
</CodeGroup>

Long-poll `changes` to follow a run: it returns new events and the final `answer` with near-instant latency and far fewer calls than fixed-interval polling. Reach for [`status`](/computer-use-agents/sessions/status) only when you want a cheap, one-off liveness check.
