## Retrieve an event

**get** `/graphs/{graph_id}/events/{event_id}`

Retrieves one event, with every change it made. `expand[]=node` adds its node as it stood just after it. An event older than the graph's retained history is `410 outside_retention_window`.

### Path Parameters

- `graph_id: string`

- `event_id: string`

### Query Parameters

- `expand: optional array of string`

  Fields to expand: `node`, and its own fields, `node.parent`.

  Send one `expand[]` per path. A path goes at most 4 levels deep; at most 20 paths per request. An expanded field appears beside its `_id` field, which is always there; one not expanded is absent.

### Returns

- `Event object { id, changes, created, 7 more }`

  One thing that happened in a graph, and every change it made to its nodes.

  - `id: string`

    Unique identifier for the event, `evt_…`. Sorts by time.

  - `changes: array of NodeChange`

    Every node this event changed, starting with `node_id`. Empty when it changed nothing (a repeated status, say).

    - `created: boolean`

      Whether the event created it. Its `fields` then go from `null`.

    - `fields: map[FieldChange]`

      Each [node](#tag/Nodes) field that changed, by name, from what to what. Derived fields count (`child_count`, `descendant_count`, `blocked`, `headline`, `task_counts`). `stale` doesn't, as it changes with time rather than events, and nor do expandable fields.

      - `from: unknown`

        The value before the event.

      - `to: unknown`

        The value after it.

    - `node_id: string`

  - `created: number`

    When it happened, in Unix milliseconds.

  - `graph_id: string`

  - `node_id: string`

    The node it's about.

  - `object: "event"`

    String representing the object's type: always `event`.

    - `"event"`

  - `payload: map[unknown]`

    What the agent tool reported, by `type`: see [event types](#tag/Events). Ids in it are the provider's own. Text in it is untrusted.

  - `source: EventSource`

    What reported the event.

    - `adapter: string`

      The Agent Graph adapter that recorded it, and its version, when it says.

    - `provider: string`

    - `provider_version: string`

      The agent tool's version, when it says.

  - `type: "session.started" or "session.ended" or "agent.spawned" or 11 more`

    What happened. See [event types](#tag/Events). More may be added: ignore those you don't recognise.

    - `"session.started"`

    - `"session.ended"`

    - `"agent.spawned"`

    - `"agent.finished"`

    - `"status"`

    - `"tasks.updated"`

    - `"task.upserted"`

    - `"task.deleted"`

    - `"spawn.requested"`

    - `"spawn.returned"`

    - `"wait.started"`

    - `"wait.ended"`

    - `"message.sent"`

    - `"activity"`

  - `node: optional Node`

    That node, as it stood just after this event. Present only when expanded.

    - `id: string`

      Unique identifier for the node within its graph: `node_` and the base64url of `provider_ref`.

    - `agent_type: string`

      For an agent, its type, as the tool names it (`Explore`, `general-purpose`, …).

    - `as_of_event_id: string`

      The event this node is shown as of.

    - `attention: string`

      While `input_required`: what the person is being asked. Untrusted text.

    - `background: boolean`

      Whether it was started in the background, so its requester carries on without waiting. `null` when unknown.

    - `background_agent_count: number`

      Helpers its tool ran on its own between turns (memory extraction, summaries, prompt suggestions). They report nothing about what they're for, so they're counted, not made nodes.

    - `blocked: Blocked`

      What stands between a node and carrying on.

    - `child_count: number`

      How many nodes sit directly under it.

    - `created: number`

      When it started (or was first seen), in Unix milliseconds.

    - `cwd: string`

      The directory it runs in, when reported.

    - `depth: number`

      How far below its root it is: 0 for a root.

    - `descendant_count: number`

      How many nodes sit under it, at any depth: the size of `descendants`.

    - `ended: number`

      When it finished, in Unix milliseconds. `null` while it hasn't.

    - `graph_id: string`

      The graph it belongs to.

    - `headline: string`

      One line on what it's doing now: `summary`, else the task in progress. Untrusted text.

    - `kind: NodeKind`

      `session`: one run of a coding agent (Claude Code, Codex, Cursor, …). `agent`: an agent started inside a session, by it or by another agent.

      - `"session"`

      - `"agent"`

    - `last_event: number`

      When it last had an event, in Unix milliseconds.

    - `link_method: "env" or "run" or "process" or "suggested"`

      For a session started by another, how that was worked out: `env` (it inherited its parent's identity), `run` (`agent-graph run` started it), `process` (its parent's agent is among its processes) or `suggested` (it took a name its parent suggested).

      - `"env"`

      - `"run"`

      - `"process"`

      - `"suggested"`

    - `object: "node"`

      String representing the object's type: always `node`.

      - `"node"`

    - `parent_id: string`

      The node it sits under: the agent or session that started it. `null` for a root.

    - `provider: string`

      The agent tool: `claude-code`, `codex`, `cursor`, or another that reports to Agent Graph.

    - `provider_ref: string`

      The id the agent tool gave it: `<provider>:<session>` for a session, `<provider>:<session>/<agent>` for an agent. Not an id in this API: use it to match the node to the tool's own records.

    - `purpose: string`

      Why it was started, from the request that started it. Untrusted text.

    - `requested_by_id: string`

      The node whose spawn request started it, when known. Usually the parent; `null` for a session nothing started, or an agent no request was matched to.

    - `root_id: string`

      The top of its tree: follow `parent_id` until it's `null`. A session started by another session is in that session's tree. A root's `root_id` is its own `id`.

    - `session_id: string`

      The session it runs in: itself, for a session; for an agent, the nearest session above it.

    - `spawn_call_id: string`

      The tool call, in its requester's session, that started it: matches a `spawns[].call_id` on `requested_by`.

    - `stale: boolean`

      `working`, waiting on nothing, and silent for 30 minutes: it may have hung or crashed. Measured against `as_of`, not now.

    - `state: NodeState`

      What a node is doing.

      - `working`: doing something.
      - `input_required`: waiting on a person (`attention` says what for).
      - `idle`: a session between turns, waiting for its next prompt.
      - `completed`, `failed`, `canceled`: finished.

      - `"working"`

      - `"input_required"`

      - `"idle"`

      - `"completed"`

      - `"failed"`

      - `"canceled"`

    - `summary: string`

      Its own latest status line, if it reports one. Untrusted text.

    - `task_counts: TaskCounts`

      Its tasks, by status.

      - `completed: number`

      - `in_progress: number`

      - `open: number`

        Not completed: `pending` and `in_progress`.

      - `pending: number`

      - `total: number`

    - `title: string`

      The session's name, as its tool shows it. It can change. Untrusted text.

    - `children: optional unknown`

      The nodes directly under it, oldest first: the first 100, and a `url` for the rest. Present only when expanded.

    - `descendants: optional unknown`

      Every node under it, at any depth, as one flat list in tree order: each parent before its children, siblings oldest first. The first 1,000, and a `url` for the rest. Present only when expanded.

    - `messages: optional array of Message`

      Messages it has sent and received, oldest first. Present only when expanded.

      - `id: string`

        The tool's id for the message.

      - `body: string`

        The whole message, only if the share was made with body capture on. Untrusted text.

      - `created: number`

        When it was sent, in Unix milliseconds.

      - `direction: "sent" or "received"`

        - `"sent"`

        - `"received"`

      - `peer_id: string`

        The node on the other side, when it's one in this graph.

      - `peer_name: string`

        The tool's name for the other side, when it isn't a node in this graph.

      - `reply_to_message_id: string`

        The message it answers.

      - `summary: string`

        Untrusted text.

    - `parent: optional Node`

      The parent node. Present only when expanded.

    - `requested_by: optional Node`

      The node that requested it. Present only when expanded.

    - `root: optional Node`

      The root node. Present only when expanded.

    - `session: optional Node`

      The session node. Present only when expanded.

    - `spawns: optional array of Spawn`

      The children it has asked for, oldest first. Present only when expanded.

      - `agent_type: string`

      - `background: boolean`

        If false, the requester is blocked until the call returns.

      - `call_id: string`

        The tool call that asked for it.

      - `child_id: string`

        The node it started, once matched. Before the call returns this can be a best guess, corrected when it does.

      - `kind: "agent" or "session"`

        `agent`: an agent in the same session. `session`: a separate session, e.g. `codex exec` run from a shell.

        - `"agent"`

        - `"session"`

      - `purpose: string`

        Untrusted text.

      - `requested: number`

        When it was asked for, in Unix milliseconds.

      - `returned: boolean`

        Whether the call has returned.

      - `run: boolean`

        Whether it's through `agent-graph run`, when known.

      - `title: string`

        For a session, the name it was to be given.

    - `tasks: optional array of Task`

      Its task list, in the tool's order. Present only when expanded.

      - `id: string`

        The tool's id for the task, unique within the node.

      - `active_text: string`

        How the tool words it while it's in progress (`Running the tests`). Untrusted text.

      - `status: "pending" or "in_progress" or "completed"`

        - `"pending"`

        - `"in_progress"`

        - `"completed"`

      - `text: string`

        What the task is. Untrusted text.

    - `waits: optional array of Wait`

      What it has waited on and is waiting on, oldest first. Present only when expanded.

      - `id: string`

        The wait's id, unique within the node.

      - `ended: number`

        When it stopped, in Unix milliseconds.

      - `kind: "spawn" or "explicit"`

        `spawn`: waiting for a child it asked for, until the call returns. `explicit`: any other wait the tool reported.

        - `"spawn"`

        - `"explicit"`

      - `on_id: string`

        The node waited on. `null` while a requested child hasn't started.

      - `open: boolean`

        Whether it's still waiting.

      - `reason: string`

        Untrusted text.

      - `started: number`

        When it started waiting, in Unix milliseconds.

### Example

```http
curl https://agentgraph.chofter.com/api/v1/graphs/$GRAPH_ID/events/$EVENT_ID \
    -H "Authorization: Bearer $AGENT_GRAPH_API_KEY"
```

#### Response

```json
{
  "id": "evt_01M4G2FMPN7KD3N1PZ0QX8RM4A",
  "object": "event",
  "type": "agent.spawned",
  "created": 1791540843221,
  "graph_id": "gph_k3P9xQ2mWt7a",
  "node_id": "node_Y2xhdWRlLWNvZGU6NWYyYzFlOWEtOGQxYi00YjZlLTlhNTEtMGY2ZjJjN2QzZTEwL2EzZmQwN2MyYjE5ZTRkNjE",
  "source": {
    "provider": "claude-code",
    "provider_version": "2.1.260",
    "adapter": "claude-code@1"
  },
  "payload": {
    "agent_type": "Explore",
    "purpose": "Find every caller of the old session store"
  },
  "changes": [
    {
      "node_id": "node_Y2xhdWRlLWNvZGU6NWYyYzFlOWEtOGQxYi00YjZlLTlhNTEtMGY2ZjJjN2QzZTEwL2EzZmQwN2MyYjE5ZTRkNjE",
      "created": true,
      "fields": {
        "state": {
          "from": null,
          "to": "working"
        },
        "parent_id": {
          "from": null,
          "to": "node_Y2xhdWRlLWNvZGU6NWYyYzFlOWEtOGQxYi00YjZlLTlhNTEtMGY2ZjJjN2QzZTEw"
        }
      }
    },
    {
      "node_id": "node_Y2xhdWRlLWNvZGU6NWYyYzFlOWEtOGQxYi00YjZlLTlhNTEtMGY2ZjJjN2QzZTEw",
      "created": false,
      "fields": {
        "child_count": {
          "from": 2,
          "to": 3
        },
        "descendant_count": {
          "from": 4,
          "to": 5
        },
        "blocked": {
          "from": null,
          "to": {
            "on_ids": [
              "node_Y2xhdWRlLWNvZGU6NWYyYzFlOWEtOGQxYi00YjZlLTlhNTEtMGY2ZjJjN2QzZTEwL2EzZmQwN2MyYjE5ZTRkNjE"
            ],
            "starting": 0,
            "node_count": 1,
            "open_tasks": 0,
            "cycle": false
          }
        }
      }
    }
  ]
}
```
