Start a session

Create a session to run your agent and begin executing tasks.


A session is an agent instance within an environment. Each session references an agent and an environment (both created separately), and maintains conversation history across multiple interactions. Sessions follow a two-step lifecycle: first create the session to provision its container, then send a user event to start work.

Note

All Managed Agents API requests require the managed-agents-2026-04-01 beta header. The SDK sets the beta header automatically.

Creating a session

A session requires an agent ID and an environment ID. Agents are versioned resources; passing in the agent ID as a string starts the session with the latest agent version.

session=$(curl -fsSL https://api.anthropic.com/v1/sessions \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "anthropic-beta: managed-agents-2026-04-01" \
  -H "content-type: application/json" \
  -d @- <<EOF
{
  "agent": "$AGENT_ID",
  "environment_id": "$ENVIRONMENT_ID"
}
EOF
)
SESSION_ID=$(jq -r '.id' <<< "$session")
ant beta:sessions create \
  --agent "$AGENT_ID" \
  --environment-id "$ENVIRONMENT_ID"
session = client.beta.sessions.create(
    agent=agent.id,
    environment_id=environment.id,
)
const session = await client.beta.sessions.create({
  agent: agent.id,
  environment_id: environment.id
});
var session = await client.Beta.Sessions.Create(new()
{
    Agent = agent.ID,
    EnvironmentID = environment.ID,
});
session, err := client.Beta.Sessions.New(ctx, anthropic.BetaSessionNewParams{
	Agent: anthropic.BetaSessionNewParamsAgentUnion{
		OfString: anthropic.String(agent.ID),
	},
	EnvironmentID: environment.ID,
})
if err != nil {
	panic(err)
}
var session = client.beta().sessions().create(SessionCreateParams.builder()
    .agent(agent.id())
    .environmentId(environment.id())
    .build());
$session = $client->beta->sessions->create(
    agent: $agent->id,
    environmentID: $environment->id,
);
session = client.beta.sessions.create(
  agent: agent.id,
  environment_id: environment.id
)

To pin a session to a specific agent version, pass an object. This lets you control exactly which version runs and stage rollouts of new versions independently.

pinned_session=$(curl -fsSL https://api.anthropic.com/v1/sessions \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "anthropic-beta: managed-agents-2026-04-01" \
  -H "content-type: application/json" \
  -d @- <<EOF
{
  "agent": {"type": "agent", "id": "$AGENT_ID", "version": 1},
  "environment_id": "$ENVIRONMENT_ID"
}
EOF
)
PINNED_SESSION_ID=$(jq -r '.id' <<< "$pinned_session")
ant beta:sessions create <<YAML
agent:
  type: agent
  id: $AGENT_ID
  version: 1
environment_id: $ENVIRONMENT_ID
YAML
pinned_session = client.beta.sessions.create(
    agent={"type": "agent", "id": agent.id, "version": 1},
    environment_id=environment.id,
)
const pinnedSession = await client.beta.sessions.create({
  agent: { type: "agent", id: agent.id, version: 1 },
  environment_id: environment.id
});
var pinnedSession = await client.Beta.Sessions.Create(new()
{
    Agent = new BetaManagedAgentsAgentParams
    {
        Type = Anthropic.Models.Beta.Sessions.Type.Agent,
        ID = agent.ID,
        Version = 1,
    },
    EnvironmentID = environment.ID,
});
pinnedSession, err := client.Beta.Sessions.New(ctx, anthropic.BetaSessionNewParams{
	Agent: anthropic.BetaSessionNewParamsAgentUnion{
		OfBetaManagedAgentsAgents: &anthropic.BetaManagedAgentsAgentParams{
			Type:    anthropic.BetaManagedAgentsAgentParamsTypeAgent,
			ID:      agent.ID,
			Version: anthropic.Int(1),
		},
	},
	EnvironmentID: environment.ID,
})
if err != nil {
	panic(err)
}
var pinnedSession = client.beta().sessions().create(SessionCreateParams.builder()
    .agent(BetaManagedAgentsAgentParams.builder()
        .type(BetaManagedAgentsAgentParams.Type.AGENT)
        .id(agent.id())
        .version(1)
        .build())
    .environmentId(environment.id())
    .build());
$pinnedSession = $client->beta->sessions->create(
    agent: ['type' => 'agent', 'id' => $agent->id, 'version' => 1],
    environmentID: $environment->id,
);
pinned_session = client.beta.sessions.create(
  agent: {type: :agent, id: agent.id, version: 1},
  environment_id: environment.id
)
Tip

The agent defines how Claude behaves within the session, including the model, system prompt, tools, and MCP servers. See Define your agent for details.

MCP authentication through vaults

If your agent uses MCP tools that require authentication, pass vault_ids at session creation to reference a vault containing stored OAuth credentials. Anthropic manages token refresh on your behalf. See Authenticate with vaults for how to create vaults and register credentials.

vault_session=$(curl -fsSL https://api.anthropic.com/v1/sessions \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "anthropic-beta: managed-agents-2026-04-01" \
  -H "content-type: application/json" \
  -d @- <<EOF
{
  "agent": "$AGENT_ID",
  "environment_id": "$ENVIRONMENT_ID",
  "vault_ids": ["$VAULT_ID"]
}
EOF
)
VAULT_SESSION_ID=$(jq -r '.id' <<< "$vault_session")
ant beta:sessions create <<YAML
agent: $AGENT_ID
environment_id: $ENVIRONMENT_ID
vault_ids:
  - $VAULT_ID
YAML
vault_session = client.beta.sessions.create(
    agent=agent.id,
    environment_id=environment.id,
    vault_ids=[vault.id],
)
const vaultSession = await client.beta.sessions.create({
  agent: agent.id,
  environment_id: environment.id,
  vault_ids: [vault.id]
});
var vaultSession = await client.Beta.Sessions.Create(new()
{
    Agent = agent.ID,
    EnvironmentID = environment.ID,
    VaultIds = [vault.ID],
});
vaultSession, err := client.Beta.Sessions.New(ctx, anthropic.BetaSessionNewParams{
	Agent: anthropic.BetaSessionNewParamsAgentUnion{
		OfString: anthropic.String(agent.ID),
	},
	EnvironmentID: environment.ID,
	VaultIDs:      []string{vault.ID},
})
if err != nil {
	panic(err)
}
var vaultSession = client.beta().sessions().create(SessionCreateParams.builder()
    .agent(agent.id())
    .environmentId(environment.id())
    .addVaultId(vault.id())
    .build());
$vaultSession = $client->beta->sessions->create(
    agent: $agent->id,
    environmentID: $environment->id,
    vaultIDs: [$vault->id],
);
vault_session = client.beta.sessions.create(
  agent: agent.id,
  environment_id: environment.id,
  vault_ids: [vault.id]
)

Starting the session

Creating a session provisions the environment's container but does not start any work. To delegate a task, send events to the session using a user event. The session acts as a state machine that tracks progress while events drive the actual execution.

curl -fsSL "https://api.anthropic.com/v1/sessions/$SESSION_ID/events" \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "anthropic-beta: managed-agents-2026-04-01" \
  -H "content-type: application/json" \
  -d @- <<'EOF'
{
  "events": [
    {
      "type": "user.message",
      "content": [{"type": "text", "text": "List the files in the working directory."}]
    }
  ]
}
EOF
ant beta:sessions:events send \
  --session-id "$SESSION_ID" <<'YAML'
events:
  - type: user.message
    content:
      - type: text
        text: List the files in the working directory.
YAML
client.beta.sessions.events.send(
    session.id,
    events=[
        {
            "type": "user.message",
            "content": [
                {"type": "text", "text": "List the files in the working directory."}
            ],
        },
    ],
)
await client.beta.sessions.events.send(session.id, {
  events: [
    {
      type: "user.message",
      content: [{ type: "text", text: "List the files in the working directory." }]
    }
  ]
});
await client.Beta.Sessions.Events.Send(session.ID, new()
{
    Events =
    [
        new BetaManagedAgentsUserMessageEventParams
        {
            Type = BetaManagedAgentsUserMessageEventParamsType.UserMessage,
            Content =
            [
                new BetaManagedAgentsTextBlock
                {
                    Type = BetaManagedAgentsTextBlockType.Text,
                    Text = "List the files in the working directory.",
                },
            ],
        },
    ],
});
if _, err := client.Beta.Sessions.Events.Send(ctx, session.ID, anthropic.BetaSessionEventSendParams{
	Events: []anthropic.BetaManagedAgentsEventParamsUnion{{
		OfUserMessage: &anthropic.BetaManagedAgentsUserMessageEventParams{
			Type: anthropic.BetaManagedAgentsUserMessageEventParamsTypeUserMessage,
			Content: []anthropic.BetaManagedAgentsUserMessageEventParamsContentUnion{{
				OfText: &anthropic.BetaManagedAgentsTextBlockParam{
					Type: anthropic.BetaManagedAgentsTextBlockTypeText,
					Text: "List the files in the working directory.",
				},
			}},
		},
	}},
}); err != nil {
	panic(err)
}
client.beta().sessions().events().send(
    session.id(),
    EventSendParams.builder()
        .addEvent(BetaManagedAgentsUserMessageEventParams.builder()
            .type(BetaManagedAgentsUserMessageEventParams.Type.USER_MESSAGE)
            .addTextContent("List the files in the working directory.")
            .build())
        .build());
$client->beta->sessions->events->send(
    $session->id,
    events: [
        [
            'type' => 'user.message',
            'content' => [['type' => 'text', 'text' => 'List the files in the working directory.']],
        ],
    ],
);
client.beta.sessions.events.send_(
  session.id,
  events: [
    {
      type: :"user.message",
      content: [{type: :text, text: "List the files in the working directory."}]
    }
  ]
)

See Session event stream for how to stream the agent's responses and handle tool confirmations.

Session statuses

Sessions progress through these statuses:

StatusDescription
idleAgent is waiting for input, including user messages or tool confirmations. Sessions start in idle.
runningAgent is actively executing.
reschedulingTransient error occurred, retrying automatically.
terminatedSession has ended due to an unrecoverable error.

Other session operations

Updating the agent configuration

You can update a session's agent.tools and agent.mcp_servers, including permission policies, mid-session without creating a new agent version. Updates are session-local and do not propagate back to the underlying agent.

The semantics of an update are full replacement: the provided array is the new value. To preserve existing entries, GET the session, modify the array, and POST it back.

The session must be idle to update the agent. Interrupt the session if you need to update the agent while it's running.

curl -sS --fail-with-body "https://api.anthropic.com/v1/sessions/$SESSION_ID" \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "anthropic-beta: managed-agents-2026-04-01" \
  -H "content-type: application/json" \
  -d @- <<EOF
{
  "agent": {
    "tools": [
      {"type": "agent_toolset_20260401"},
      {"type": "mcp_toolset", "mcp_server_name": "linear"}
    ],
    "mcp_servers": [
      {"type": "url", "name": "linear", "url": "https://mcp.linear.app/sse"}
    ]
  }
}
EOF
ant beta:sessions update --session-id "$SESSION_ID" <<'YAML'
agent:
  tools:
    - type: agent_toolset_20260401
    - type: mcp_toolset
      mcp_server_name: linear
  mcp_servers:
    - type: url
      name: linear
      url: https://mcp.linear.app/sse
YAML
client.beta.sessions.update(
    session.id,
    agent={
        "tools": [
            {"type": "agent_toolset_20260401"},
            {"type": "mcp_toolset", "mcp_server_name": "linear"},
        ],
        "mcp_servers": [
            {"type": "url", "name": "linear", "url": "https://mcp.linear.app/sse"}
        ],
    },
)
await client.beta.sessions.update(session.id, {
  agent: {
    tools: [
      { type: "agent_toolset_20260401" },
      { type: "mcp_toolset", mcp_server_name: "linear" }
    ],
    mcp_servers: [{ type: "url", name: "linear", url: "https://mcp.linear.app/sse" }]
  }
});
using Anthropic.Models.Beta.Agents;

await client.Beta.Sessions.Update(session.ID, new()
{
    Agent = new()
    {
        Tools =
        [
            new BetaManagedAgentsAgentToolset20260401Params
            {
                Type = BetaManagedAgentsAgentToolset20260401ParamsType.AgentToolset20260401,
            },
            new BetaManagedAgentsMcpToolsetParams
            {
                Type = BetaManagedAgentsMcpToolsetParamsType.McpToolset,
                McpServerName = "linear",
            },
        ],
        McpServers =
        [
            new()
            {
                Type = BetaManagedAgentsUrlMcpServerParamsType.Url,
                Name = "linear",
                Url = "https://mcp.linear.app/sse",
            },
        ],
    },
});
_, err = client.Beta.Sessions.Update(ctx, session.ID, anthropic.BetaSessionUpdateParams{
	Agent: anthropic.BetaManagedAgentsSessionAgentUpdateParam{
		Tools: []anthropic.BetaManagedAgentsSessionAgentUpdateToolUnionParam{
			{
				OfAgentToolset20260401: &anthropic.BetaManagedAgentsAgentToolset20260401Params{
					Type: anthropic.BetaManagedAgentsAgentToolset20260401ParamsTypeAgentToolset20260401,
				},
			},
			{
				OfMCPToolset: &anthropic.BetaManagedAgentsMCPToolsetParams{
					Type:          anthropic.BetaManagedAgentsMCPToolsetParamsTypeMCPToolset,
					MCPServerName: "linear",
				},
			},
		},
		MCPServers: []anthropic.BetaManagedAgentsURLMCPServerParams{
			{
				Type: anthropic.BetaManagedAgentsURLMCPServerParamsTypeURL,
				Name: "linear",
				URL:  "https://mcp.linear.app/sse",
			},
		},
	},
})
if err != nil {
	panic(err)
}
client.beta().sessions().update(
    session.id(),
    SessionUpdateParams.builder()
        .agent(BetaManagedAgentsSessionAgentUpdate.builder()
            .addTool(BetaManagedAgentsAgentToolset20260401Params.builder()
                .type(BetaManagedAgentsAgentToolset20260401Params.Type.AGENT_TOOLSET_20260401)
                .build())
            .addTool(BetaManagedAgentsMcpToolsetParams.builder()
                .type(BetaManagedAgentsMcpToolsetParams.Type.MCP_TOOLSET)
                .mcpServerName("linear")
                .build())
            .addMcpServer(BetaManagedAgentsUrlMcpServerParams.builder()
                .type(BetaManagedAgentsUrlMcpServerParams.Type.URL)
                .name("linear")
                .url("https://mcp.linear.app/sse")
                .build())
            .build())
        .build()
);
$client->beta->sessions->update(
    $session->id,
    agent: BetaManagedAgentsSessionAgentUpdate::with(
        tools: [
            BetaManagedAgentsAgentToolset20260401Params::with(type: 'agent_toolset_20260401'),
            BetaManagedAgentsMCPToolsetParams::with(mcpServerName: 'linear', type: 'mcp_toolset'),
        ],
        mcpServers: [
            BetaManagedAgentsURLMCPServerParams::with(
                name: 'linear',
                type: 'url',
                url: 'https://mcp.linear.app/sse',
            ),
        ],
    ),
);
client.beta.sessions.update(
  session.id,
  agent: {
    tools: [
      {type: :agent_toolset_20260401},
      {type: :mcp_toolset, mcp_server_name: "linear"}
    ],
    mcp_servers: [
      {type: :url, name: "linear", url: "https://mcp.linear.app/sse"}
    ]
  }
)

Retrieving a session

retrieved=$(curl -fsSL "https://api.anthropic.com/v1/sessions/$SESSION_ID" \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "anthropic-beta: managed-agents-2026-04-01")
echo "Status: $(jq -r '.status' <<< "$retrieved")"
ant beta:sessions retrieve --session-id "$SESSION_ID"
retrieved = client.beta.sessions.retrieve(session.id)
print(f"Status: {retrieved.status}")
const retrieved = await client.beta.sessions.retrieve(session.id);
console.log(`Status: ${retrieved.status}`);
var retrieved = await client.Beta.Sessions.Retrieve(session.ID);
Console.WriteLine({{CONTENT}}quot;Status: {retrieved.Status.Raw()}");
retrieved, err := client.Beta.Sessions.Get(ctx, session.ID, anthropic.BetaSessionGetParams{})
if err != nil {
	panic(err)
}
fmt.Printf("Status: %s\n", retrieved.Status)
var retrieved = client.beta().sessions().retrieve(session.id());
IO.println("Status: " + retrieved.status());
$retrieved = $client->beta->sessions->retrieve($session->id);
echo "Status: {$retrieved->status}\n";
retrieved = client.beta.sessions.retrieve(session.id)
puts "Status: #{retrieved.status}"

Listing sessions

curl -fsSL "https://api.anthropic.com/v1/sessions?agent_id=$AGENT_ID" \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "anthropic-beta: managed-agents-2026-04-01" \
  | jq -r '.data[] | "\(.id): \(.status)"'
ant beta:sessions list --agent-id "$AGENT_ID"
for listed_session in client.beta.sessions.list(agent_id=agent.id):
    print(f"{listed_session.id}: {listed_session.status}")
for await (const session of client.beta.sessions.list({ agent_id: agent.id })) {
  console.log(`${session.id}: ${session.status}`);
}
var sessions = await client.Beta.Sessions.List(new SessionListParams { AgentID = agent.ID });
await foreach (var listedSession in sessions.Paginate())
{
    Console.WriteLine({{CONTENT}}quot;{listedSession.ID}: {listedSession.Status.Raw()}");
}
page := client.Beta.Sessions.ListAutoPaging(ctx, anthropic.BetaSessionListParams{
	AgentID: anthropic.String(agent.ID),
})
for page.Next() {
	session := page.Current()
	fmt.Printf("%s: %s\n", session.ID, session.Status)
}
if err := page.Err(); err != nil {
	panic(err)
}
var params = SessionListParams.builder().agentId(agent.id()).build();
for (var listed : client.beta().sessions().list(params).autoPager()) {
    IO.println(listed.id() + ": " + listed.status());
}
foreach ($client->beta->sessions->list(agentID: $agent->id)->pagingEachItem() as $listedSession) {
    echo "{$listedSession->id}: {$listedSession->status}\n";
}
client.beta.sessions.list(agent_id: agent.id).auto_paging_each do |session|
  puts "#{session.id}: #{session.status}"
end

Archiving a session

Archive a session to prevent new events from being sent while preserving its history:

curl -fsSL -X POST "https://api.anthropic.com/v1/sessions/$SESSION_ID/archive" \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "anthropic-beta: managed-agents-2026-04-01"
ant beta:sessions archive \
  --session-id "$SESSION_ID"
client.beta.sessions.archive(session.id)
await client.beta.sessions.archive(session.id);
await client.Beta.Sessions.Archive(session.ID);
_, err = client.Beta.Sessions.Archive(ctx, session.ID, anthropic.BetaSessionArchiveParams{})
if err != nil {
	panic(err)
}
client.beta().sessions().archive(session.id());
$client->beta->sessions->archive($session->id);
client.beta.sessions.archive(session.id)

Deleting a session

Delete a session to permanently remove its record, events, and associated container. A running session cannot be deleted; send an interrupt event if you need to delete it immediately.

Files, memory stores, vaults, skills, environments, and agents are independent resources and are not affected by session deletion.

curl -fsSL -X DELETE "https://api.anthropic.com/v1/sessions/$SESSION_ID" \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "anthropic-beta: managed-agents-2026-04-01"
ant beta:sessions delete \
  --session-id "$SESSION_ID"
client.beta.sessions.delete(session.id)
await client.beta.sessions.delete(session.id);
await client.Beta.Sessions.Delete(session.ID);
_, err = client.Beta.Sessions.Delete(ctx, session.ID, anthropic.BetaSessionDeleteParams{})
if err != nil {
	panic(err)
}
client.beta().sessions().delete(session.id());
$client->beta->sessions->delete($session->id);
client.beta.sessions.delete(session.id)