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

# Anthropic Managed Agents

> Event-sourced managed-agent sessions - post user events, stream a replayable agent.* event log, and confirm tool use.

The Managed Agents adapter models a conversation as an **event-sourced
session**: you create a session, post user events into it, and stream back an
ordered `agent.*` event log. It maps Karta's
[typed events](/concepts/streaming-events) onto the Anthropic managed-agent
shape. Auth: a [session token](/security/session-tokens) or a `kt_live_...` key.

## Create a session

`POST /{org}/{agent}/v1/managed-agents/sessions`

The body is optional. Pass a `metadata` object to carry your own end-user id
for per-visitor continuity.

<ParamField body="metadata" type="object">
  Optional client metadata. `metadata.end_user_id` is used for per-visitor
  continuity when the caller is anonymous or soft-identified; a verified session
  token's `sub` remains authoritative.
</ParamField>

<ParamField body="prewarm" type="boolean">
  Defaults to `true`. Set `false` when your client will open the visible
  [warm stream](#warm-before-first-turn) before the first turn.
</ParamField>

```bash theme={null}
curl -X POST https://agent.karta.sh/my-org/my-app/v1/managed-agents/sessions \
  -H "Authorization: Bearer $SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"metadata": {"end_user_id": "u_42"}}'
# -> 201 { "id": "sess_9f3a...", "object": "session", "status": "idle" }
```

## Warm before first turn

Optional, before the first turn: ask Karta to start the agent ahead of time so
the first response is not delayed by startup. Two shapes are available:
fire-and-forget, or an observable stream. Warming is best-effort and never
required; if you skip it, the first turn starts the agent as needed.

`POST /{org}/{agent}/v1/managed-agents/sessions/{session_id}/prewarm`

Returns immediately; the agent keeps warming in the background.

```bash theme={null}
curl -X POST https://agent.karta.sh/my-org/my-app/v1/managed-agents/sessions/$SID/prewarm \
  -H "Authorization: Bearer $SESSION_TOKEN"
# -> 202 { "status": "warming" }
```

`GET /{org}/{agent}/v1/managed-agents/sessions/{session_id}/warm`

Streams the readiness lifecycle as Server-Sent Events, so a UI can show a "getting
ready" state and proceed once the agent is ready:

```bash theme={null}
curl -N https://agent.karta.sh/my-org/my-app/v1/managed-agents/sessions/$SID/warm \
  -H "Authorization: Bearer $SESSION_TOKEN"
```

It emits `warming` (repeated as a heartbeat while the agent starts) and then a
terminal `ready` - or `error` if warming failed, in which case you can still send the
turn and it pays the cold start. The widget SDK wraps this as
`KartaAgentClient.warm()`, which yields a `WarmEvent` stream
(`warming` | `ready` | `error`).

## List sessions

`GET /{org}/{agent}/v1/managed-agents/sessions?end_user=<id>`

Returns prior conversations for the current end user, newest activity first:

```json theme={null}
{
  "object": "list",
  "data": [
    { "id": "sess_9f3a...", "object": "session", "status": "idle" }
  ]
}
```

If the caller uses a verified session token, Karta uses the verified `sub`.
Anonymous callers must pass their stable `end_user` value and possess the
session id to reopen a transcript.

## Post an event

`POST /{org}/{agent}/v1/managed-agents/sessions/{session_id}/events`

Posting a user event spawns the turn in the background and returns immediately;
you observe the result on the [event stream](#stream-events).

<ParamField body="type" type="string" required>
  `user.message`, `user.tool_confirmation`, or `user.interrupt`.
</ParamField>

<ParamField body="text" type="string">
  The message text - required for `user.message`.
</ParamField>

<ParamField body="tool_use_id" type="string">
  Optional tool reference.
</ParamField>

<ParamField body="request_id" type="string">
  Required for `user.tool_confirmation` - the approval being answered.
</ParamField>

<ParamField body="result" type="string">
  `approve_once`, `approve_session`, or `deny` - required for
  `user.tool_confirmation` (`allow` still works as an alias for `approve_once`).
  A `user.tool_confirmation` without both `result` and `request_id` is a `400`.
</ParamField>

```bash theme={null}
curl -X POST https://agent.karta.sh/my-org/my-app/v1/managed-agents/sessions/$SID/events \
  -H "Authorization: Bearer $SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"type": "user.message", "text": "What roasts do you have?"}'
# -> 202 { "accepted": true }
```

Approve a pending tool use:

```bash theme={null}
curl -X POST .../sessions/$SID/events \
  -H "Authorization: Bearer $SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"type": "user.tool_confirmation", "request_id": "req_7c1...", "result": "approve_once"}'
```

## Stream events

`GET /{org}/{agent}/v1/managed-agents/sessions/{session_id}/events/stream`

Streams `agent.*` events as the turn runs. Pass `?after=<seq>` to resume from a
known sequence number - the log is ordered and replayable.

```bash theme={null}
curl -N "https://agent.karta.sh/my-org/my-app/v1/managed-agents/sessions/$SID/events/stream?after=0" \
  -H "Authorization: Bearer $SESSION_TOKEN"
```

## Warm before first turn

Managed-agent sessions can start the agent runtime before the first user
message. Use this for chat UIs that want a faster first turn or a visible
"warming up" state.

| Path                                                                  | Use                                                        | Result                                                                                                                                  |
| --------------------------------------------------------------------- | ---------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| `POST /{org}/{agent}/v1/managed-agents/sessions/{session_id}/prewarm` | Fire-and-forget warmup from input focus or page idle time. | Returns `202 { "status": "warming" }` and continues in the background. If warmup misses, the first turn still runs and may take longer. |
| `GET /{org}/{agent}/v1/managed-agents/sessions/{session_id}/warm`     | Visible warmup before enabling the composer.               | Streams `warm` SSE events with `{"status":"warming"}` heartbeats, then `{"status":"ready"}` or `{"status":"error"}`.                    |

When creating the session, leave `prewarm` at its default for hidden background
warmup. Set `prewarm: false` only when your UI immediately opens the visible
`/warm` stream and wants that stream to own the progress indicator.

```bash theme={null}
curl -X POST https://agent.karta.sh/my-org/my-app/v1/managed-agents/sessions/$SID/prewarm \
  -H "Authorization: Bearer $SESSION_TOKEN"
# -> 202 { "status": "warming" }
```

```bash theme={null}
curl -N https://agent.karta.sh/my-org/my-app/v1/managed-agents/sessions/$SID/warm \
  -H "Authorization: Bearer $SESSION_TOKEN"
```

## Upload a file for the next turn

`POST /{org}/{agent}/v1/managed-agents/sessions/{session_id}/files`

Stages a user upload for the next `user.message` turn. The agent sees the file
under `uploads/<name>`.

<ParamField body="name" type="string" required>
  Original filename. Karta stores it as a basename under `uploads/`.
</ParamField>

<ParamField body="content_base64" type="string" required>
  Base64-encoded file bytes.
</ParamField>

```json theme={null}
{ "accepted": true, "path": "uploads/menu.pdf" }
```

## Fetch session state

`GET /{org}/{agent}/v1/managed-agents/sessions/{session_id}`

```json theme={null}
{
  "id": "sess_9f3a...",
  "object": "session",
  "status": "idle",
  "events": [
    { "seq": 1, "type": "session.status_running" },
    { "seq": 2, "type": "agent.message", "text": "We've got Sunrise, ..." },
    { "seq": 3, "type": "session.status_idle", "stop_reason": "end_turn", "usage": { ... } }
  ]
}
```

`status` is `idle` or `running`; `events` is the ordered log so far.

## Fetch transcript

`GET /{org}/{agent}/v1/managed-agents/sessions/{session_id}/transcript`

Returns the compact transcript for reopening a past conversation:

```json theme={null}
{
  "session_id": "sess_9f3a...",
  "messages": [
    { "role": "user", "text": "What roasts do you have?" },
    { "role": "assistant", "text": "We've got Sunrise, Midnight, and Decaf Dusk." }
  ]
}
```

Verified callers are scoped by the token subject. Anonymous callers pass the
same stable `end_user` value used for listing.

## MCP app proxy

`POST /{org}/{agent}/v1/managed-agents/mcp`

Use this only when building an MCP Apps host for a Managed Agents session. Put
the active session id in `X-Karta-Session`, and post the MCP method and params:

```json theme={null}
{ "method": "tools/call", "params": { "name": "lookup", "arguments": {} } }
```

Karta returns the JSON result from the agent session. The browser never receives
the MCP server credential.

The agent emits `agent.message` (agent text), `agent.thinking`,
`agent.tool_use`, and `agent.tool_result`. A turn opens with
`session.status_running` and ends with a terminal `session.status_idle`
(carrying `stop_reason` and `usage`) or `session.error`. When the agent pauses
for a tool approval, the terminal `session.status_idle` carries
`stop_reason: "requires_action"` plus the `request_id` to answer with a
`user.tool_confirmation` event.

## Why event-sourced

This shape suits clients that prefer **post-and-observe** over request/response:
a UI posts a user message, then renders the agent's `agent.*` events as they
arrive - including tool-confirmation prompts it answers with a follow-up event.
The ordered, replayable log makes reconnection and catch-up straightforward
(`after=<seq>`).

## Status codes

`201` (create), `202` (event or prewarm accepted), `400` (bad body), `401`,
`402`, `403`, `404` (unknown agent / no active release), `409` (release not
materialized). The visible warm stream reports readiness or timeout as `warm`
events. See [Errors](/api-reference/errors).
