> ## 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.

> ## Agent Instructions
> H Platform has four products: the Agents API (managed computer-use agents, base URL https://agp.eu.hcompany.ai/api/v2 or https://agp.hcompany.ai/api/v2 for the US), the Models API (OpenAI-compatible Holo vision-language models at https://api.hcompany.ai/v1), HoloDesktop CLI (Holo on the user's own desktop), and HoloTab (a free no-code Chrome extension that runs Holo in the user's browser, with recordable routines and schedules).
> Authenticate with a bearer API key from the HAI_API_KEY environment variable. SDKs: `pip install hai-agents` (Python, `from hai_agents import Client`) and `npm install hai-agents` (TypeScript, `import { HaiAgentsClient } from "hai-agents"`). CLI: `hai`.
> Agents do work in a browser or on a desktop; describe the task as an imperative instruction. To run a task quickly, prefer the pre-built agent `h/web-surfer-flash`. Read results from the session's `latest_answer` after it reaches a terminal status.
> Sessions are the unit of work; wait for a terminal status (completed, failed, timed_out, interrupted) before reading the answer. Use webhooks or the `changes` long-poll endpoint to follow progress.

# Sessions

> A session is one run of an agent on a task: lifecycle states, the session object, overrides, ways to wait for the result, listing and filtering.

export const SessionLifecycle = () => {
  const stroke = {
    fill: "none",
    stroke: "currentColor",
    strokeWidth: 1.75,
    strokeLinecap: "round",
    strokeLinejoin: "round"
  };
  const S = c => ({
    className: c,
    ...stroke
  });
  const icons = {
    queued: c => <svg viewBox="0 0 24 24" {...S(c)}><path d="M8 6h13M8 12h13M8 18h13M3 6h.01M3 12h.01M3 18h.01" /></svg>,
    pending: c => <svg viewBox="0 0 24 24" {...S(c)}><circle cx="12" cy="12" r="10" /><path d="M12 6v6l4 2" /></svg>,
    running: c => <svg viewBox="0 0 24 24" {...S(c)}><path d="M21 12a9 9 0 1 1-6.219-8.56" /></svg>,
    paused: c => <svg viewBox="0 0 24 24" {...S(c)}><rect x="14" y="3" width="5" height="18" rx="1" /><rect x="5" y="3" width="5" height="18" rx="1" /></svg>,
    idle: c => <svg viewBox="0 0 24 24" {...S(c)}><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" /></svg>,
    awaiting_tool_results: c => <svg viewBox="0 0 24 24" {...S(c)}><path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.106-3.105c.32-.322.863-.22.983.218a6 6 0 0 1-8.259 7.057l-7.91 7.91a1 1 0 0 1-2.999-3l7.91-7.91a6 6 0 0 1 7.057-8.259c.438.12.54.662.219.984z" /></svg>,
    completed: c => <svg viewBox="0 0 24 24" {...S(c)}><circle cx="12" cy="12" r="10" /><path d="m9 12 2 2 4-4" /></svg>,
    failed: c => <svg viewBox="0 0 24 24" {...S(c)}><circle cx="12" cy="12" r="10" /><path d="m15 9-6 6M9 9l6 6" /></svg>,
    timed_out: c => <svg viewBox="0 0 24 24" {...S(c)}><path d="M10 2h4M12 14l3-3" /><circle cx="12" cy="14" r="8" /></svg>,
    interrupted: c => <svg viewBox="0 0 24 24" {...S(c)}><circle cx="12" cy="12" r="10" /><path d="M4.929 4.929 19.07 19.071" /></svg>
  };
  const State = ({name, sub}) => <div className="flex items-start gap-3">
      <span className="mt-0.5 flex shrink-0 text-zinc-400 dark:text-zinc-500">{icons[name]("h-4 w-4")}</span>
      <div>
        <div className="font-mono text-[13px] font-medium leading-5 text-zinc-900 dark:text-zinc-100">{name}</div>
        <div className="text-sm leading-5 text-zinc-500 dark:text-zinc-400">{sub}</div>
      </div>
    </div>;
  const Phase = ({label, children}) => <div className="flex flex-1 flex-col self-center rounded-xl border border-zinc-200 bg-white p-5 dark:border-zinc-800 dark:bg-zinc-950">
      <div className="mb-4 text-xs font-semibold uppercase tracking-wide text-zinc-500 dark:text-zinc-400">{label}</div>
      {children}
    </div>;
  const Arrow = ({top}) => <div className="flex w-[88px] shrink-0 flex-col items-stretch justify-center gap-1 px-3 text-center text-xs leading-4 text-zinc-500 dark:text-zinc-400">
      <span className="whitespace-nowrap">{top}</span>
      <div className="flex items-center text-zinc-400 dark:text-zinc-600">
        <span className="h-px flex-1 bg-current" />
        <svg className="-ml-px h-3 w-2 shrink-0" viewBox="0 0 8 12" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><path d="M1 1.5 6 6l-5 4.5" /></svg>
      </div>
    </div>;
  return <div className="not-prose my-8 overflow-x-auto">
      <div className="flex min-w-[640px] items-stretch">
        <Phase label="Starting">
          <div className="flex flex-col gap-2.5">
            <State name="queued" sub="waiting for a slot" />
            <State name="pending" sub="launching" />
          </div>
        </Phase>

        <Arrow top="launch" />

        <Phase label="Active">
          <State name="running" sub="working" />
          <div className="my-3 h-px bg-zinc-200 dark:bg-zinc-800" />
          <div className="flex flex-col gap-2.5">
            <State name="paused" sub="you paused it" />
            <State name="idle" sub="waiting for your message" />
            <State name="awaiting_tool_results" sub="waiting for your tool output" />
          </div>
        </Phase>

        <Arrow top="ends" />

        <Phase label="Ended">
          <div className="flex flex-col gap-2.5">
            <State name="completed" sub="finished the task" />
            <State name="failed" sub="stopped by an error" />
            <State name="timed_out" sub="hit a time or step limit" />
            <State name="interrupted" sub="you cancelled it" />
          </div>
        </Phase>
      </div>
    </div>;
};

<SessionLifecycle />

A session moves through a fixed [lifecycle](#lifecycle). You can steer it while it runs and read the result when it finishes. Every follow-up call (sending a message, pausing, cancelling) is addressed to the session's `id`. The optional [`max_steps` and `max_time_s`](/agents-api/sessions/create) caps bound how long it runs before the agent is asked for a final answer.

<CodeGroup>
  ```bash CLI theme={"system"}
  hai run "Open Hacker News and list the top 3 stories with their URLs." \
    --agent h/web-surfer-flash
  ```

  ```bash cURL theme={"system"}
  SESSION=$(curl -s -X POST https://agp.eu.hcompany.ai/api/v2/sessions \
    -H "Authorization: Bearer $HAI_API_KEY" -H "Content-Type: application/json" \
    -d '{"agent": "h/web-surfer-flash", "messages": [{"type": "user_message", "message": "Open Hacker News and list the top 3 stories with their URLs."}]}' | jq -r .id)
  echo "$SESSION"
  ```

  ```python Python theme={"system"}
  from hai_agents import Client

  client = Client()

  session = client.sessions.create_session(
      agent="h/web-surfer-flash",
      messages=[{"type": "user_message", "message": "Open Hacker News and list the top 3 stories with their URLs."}],
  )
  print(session.id)
  ```

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

  const client = new HaiAgentsClient();

  const session = await client.sessions.createSession({
    body: {
      agent: "h/web-surfer-flash",
      messages: [{ type: "user_message", message: "Open Hacker News and list the top 3 stories with their URLs." }],
    },
  });
  console.log(session.id);
  ```
</CodeGroup>

Creating a session returns its `id`. For a one-shot run, the helper below creates the session, blocks until the agent finishes, and hands back the result.

<CodeGroup>
  ```python Python theme={"system"}
  result = client.run_session(
      agent="h/web-surfer-flash",
      messages="Open Hacker News and list the top 3 stories with their URLs.",
  )
  print(result.status, result.answer)
  ```

  ```typescript TypeScript theme={"system"}
  const result = await client.runSession({
    agent: "h/web-surfer-flash",
    messages: "Open Hacker News and list the top 3 stories with their URLs.",
  });
  console.log(result.status, result.answer);
  ```
</CodeGroup>

### Wait for the result

Pick the call that matches how much control you need. The final answer is `answer` on the result object and on `changes`, and `latest_answer` on the session object.

| Way                                                                                                                             | Use when                                | You get back                                                  |
| ------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------- | ------------------------------------------------------------- |
| `client.run_session(...)` / `runSession` ([Quickstart](/agents-api/quickstart#run-a-session))                                   | One call: create, block, read           | The final result: `status`, `answer`, `outcome`, `error_code` |
| `client.start_session(...)` then `session.wait_for_completion()` ([Watch and steer](/agents-api/observe-and-steer#watch-a-run)) | Read or steer while it runs, then block | A handle bound to the `id`, then the same final result        |
| `session.stream()` ([Watch and steer](/agents-api/observe-and-steer#stream-events-as-they-arrive))                              | A live, read-only event feed            | Each event in order until the session settles                 |
| `wait_for_session(client, id)` / `waitForSession` ([Changes](/agents-api/sessions/changes#long-polling-pattern))                | You hold an `id` created elsewhere      | Drains `changes`, returns the final result                    |
| [`GET /sessions/{id}/changes`](/agents-api/sessions/changes) long-poll                                                          | Raw HTTP, any language                  | New events plus `answer` once it lands                        |
| [Webhooks](/agents-api/webhooks/overview)                                                                                       | No polling; batches and queued runs     | `session.completed` and the other status events               |
| [`GET /sessions/{id}`](/agents-api/sessions/retrieve)                                                                           | Read a settled run any time             | `latest_answer`, no cursor needed                             |

Polling `changes` by hand has a few gotchas; see its [polling rules](/agents-api/sessions/changes#polling-rules).

## Session object

| Field                                       | Description                                                                                                                                                                                                                                               |
| ------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`                                        | The session's UUID, the handle for every follow-up call.                                                                                                                                                                                                  |
| `request`                                   | Echoes what you submitted, with `agent` resolved to its full spec even if you passed a catalog id.                                                                                                                                                        |
| `status`                                    | Carries the live `status`, step count, per-model token usage (`usage_per_model`), any `error` and its `error_code`, the agent's self-assessed `outcome`, and `subagent_session_ids`. See [Session status](/agents-api/sessions/status) for the breakdown. |
| `agent_view_url`                            | Link to the session's [Agent View](/agents-api/observe-and-steer) page for live viewing and replay.                                                                                                                                                       |
| `latest_answer`                             | The agent's most recent final answer, mirrored from [`changes`](/agents-api/sessions/changes); `null` until it first answers.                                                                                                                             |
| `created_at` / `started_at` / `finished_at` | Track the run's timeline. The latter two are `null` until they happen.                                                                                                                                                                                    |

## Lifecycle

Every session moves through the same state machine, whichever agent runs it:

| Status                  | Meaning                                                                                                                                                     | Terminal |
| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `queued`                | Session accepted above your [concurrency limit](/agents-api/plans-and-limits#concurrent-sessions); it starts automatically, oldest first, as slots free up. | No       |
| `pending`               | Session created, agent is launching.                                                                                                                        | No       |
| `running`               | Agent is actively working on the task.                                                                                                                      | No       |
| `paused`                | Manually paused via the API. State is preserved.                                                                                                            | No       |
| `idle`                  | Interactive agent finished a task and is waiting for your next message.                                                                                     | No       |
| `awaiting_tool_results` | Agent is blocked on [custom tool](/agents-api/custom-tools) calls your code must answer.                                                                    | No       |
| `completed`             | Agent finished the task successfully.                                                                                                                       | Yes      |
| `timed_out`             | Agent exceeded the maximum allowed time.                                                                                                                    | Yes      |
| `interrupted`           | Session was canceled via `DELETE`.                                                                                                                          | Yes      |
| `failed`                | An unrecoverable error occurred.                                                                                                                            | Yes      |

## Overrides

Reuse a catalog agent but adjust it for a single run with `overrides`, a map on the [create-session](/agents-api/sessions/create) body. Rather than defining a new agent, you point at fields of the resolved request. Each key is a dotted path, and its value replaces whatever that path resolves to, applied after `agent` is expanded from its catalog id.

* Dots walk into objects. `agent.instructions` sets behavior, `agent.model` swaps the serving model, and `agent.answer_format` pins a [structured answer](/agents-api/structured-output).
* A `[field=value]` selector picks a list member. `agent.environments[kind=web]` selects the web environment, so `agent.environments[kind=web].start_url` sets just its start page and `agent.environments[kind=web].mode` switches how it reads the page.
* Values are type-checked. Each value must match the type of the field its path targets. An unknown path or a wrong type is rejected with `422` at creation, before the agent runs.

For example, send a catalog web-surfer to a chosen start page:

<CodeGroup>
  ```bash CLI theme={"system"}
  hai run "Summarize the top discussion right now" \
    --agent h/web-surfer-flash \
    --override 'agent.environments[kind=web].start_url=https://news.ycombinator.com'
  ```

  ```bash cURL theme={"system"}
  curl -X POST https://agp.eu.hcompany.ai/api/v2/sessions \
    -H "Authorization: Bearer $HAI_API_KEY" -H "Content-Type: application/json" \
    -d '{
      "agent": "h/web-surfer-flash",
      "messages": [{"type": "user_message", "message": "Summarize the top discussion right now"}],
      "overrides": {"agent.environments[kind=web].start_url": "https://news.ycombinator.com"}
    }'
  ```

  ```python Python theme={"system"}
  session = client.sessions.create_session(
      agent="h/web-surfer-flash",
      messages="Summarize the top discussion right now",
      overrides={"agent.environments[kind=web].start_url": "https://news.ycombinator.com"},
  )
  ```

  ```typescript TypeScript theme={"system"}
  const session = await client.sessions.createSession({
    body: {
      agent: "h/web-surfer-flash",
      messages: "Summarize the top discussion right now",
      overrides: { "agent.environments[kind=web].start_url": "https://news.ycombinator.com" },
    },
  });
  ```
</CodeGroup>

## Listing and filtering

[`GET /api/v2/sessions`](/agents-api/sessions/list) pages through your sessions, newest first, with filters you can combine:

| Filter                               | Type                | Description                                                               |
| ------------------------------------ | ------------------- | ------------------------------------------------------------------------- |
| `status`                             | string (repeatable) | Filter by session status (e.g. `?status=running&status=queued`).          |
| `agent`                              | string (repeatable) | Filter by agent identifier (e.g. `h/web-surfer-flash`).                   |
| `group_id`                           | string              | Filter by group: useful for multi-session workflows.                      |
| `parent_session_id`                  | string              | Find [child sessions](/agents-api/multi-agent) of a parent.               |
| `schedule_id`                        | string              | Sessions created by a [schedule](/agents-api/schedules/overview)'s fires. |
| `search`                             | string              | Case-insensitive match on the first message or answer.                    |
| `created_before` / `created_after`   | string              | Bound by creation time (ISO 8601).                                        |
| `finished_before` / `finished_after` | string              | Bound by finish time (ISO 8601).                                          |
| `owner`                              | string              | Access scope. Default: `me-in-organization`.                              |

<CodeGroup>
  ```bash cURL theme={"system"}
  curl "https://agp.eu.hcompany.ai/api/v2/sessions?status=running&agent=web-price-finder" \
    -H "Authorization: Bearer $HAI_API_KEY"
  ```

  ```python Python theme={"system"}
  page = client.sessions.list_sessions(status=["running"], agent=["web-price-finder"])
  for summary in page.items:
      print(summary.id, summary.status)
  ```

  ```typescript TypeScript theme={"system"}
  const page = await client.sessions.listSessions({
    status: ["running"],
    agent: ["web-price-finder"],
  });
  for (const summary of page.items) {
    console.log(summary.id, summary.status);
  }
  ```
</CodeGroup>

Responses use the standard [page envelope](/agents-api/api-reference#pagination). See [List sessions](/agents-api/sessions/list) for `size`, `sort`, and the full parameter reference.

## Endpoints

| Method   | Path                                                  | Description                                              |
| -------- | ----------------------------------------------------- | -------------------------------------------------------- |
| `POST`   | `/api/v2/sessions`                                    | [Create a session](/agents-api/sessions/create)          |
| `GET`    | `/api/v2/sessions`                                    | [List sessions](/agents-api/sessions/list)               |
| `GET`    | `/api/v2/sessions/{id}`                               | [Retrieve a session](/agents-api/sessions/retrieve)      |
| `GET`    | `/api/v2/sessions/{id}/status`                        | [Get session status](/agents-api/sessions/status)        |
| `DELETE` | `/api/v2/sessions/{id}`                               | [Cancel a session](/agents-api/sessions/cancel)          |
| `POST`   | `/api/v2/sessions/{id}/messages`                      | [Send a message](/agents-api/sessions/send-messages)     |
| `POST`   | `/api/v2/sessions/{id}/tool_results`                  | [Send tool results](/agents-api/sessions/tool-results)   |
| `POST`   | `/api/v2/sessions/{id}/pause`                         | [Pause a session](/agents-api/sessions/pause)            |
| `POST`   | `/api/v2/sessions/{id}/resume`                        | [Resume a session](/agents-api/sessions/resume)          |
| `POST`   | `/api/v2/sessions/{id}/force_answer`                  | [Force final answer](/agents-api/sessions/force-answer)  |
| `GET`    | `/api/v2/sessions/{id}/changes`                       | [Long-poll for changes](/agents-api/sessions/changes)    |
| `GET`    | `/api/v2/sessions/{id}/events`                        | [List events](/agents-api/sessions/events)               |
| `GET`    | `/api/v2/sessions/quota`                              | [Get quota](/agents-api/sessions/quota)                  |
| `POST`   | `/api/v2/sessions/{id}/feedback`                      | [Session feedback](/agents-api/sessions/feedback)        |
| `PUT`    | `/api/v2/sessions/{id}/events/{event_index}/feedback` | [Event feedback](/agents-api/sessions/event-feedback)    |
| `POST`   | `/api/v2/sessions/{id}/share`                         | [Share a session](/agents-api/sessions/share)            |
| `DELETE` | `/api/v2/sessions/{id}/share`                         | [Unshare a session](/agents-api/sessions/unshare)        |
| `GET`    | `/api/v2/sessions/{id}/resources/{bucket}/{key}`      | [Get a session resource](/agents-api/sessions/resources) |
