Follow Discord
Sweep 10 Nov 2026 · 02:18Z Build v2.1.322 539 read Stable v2.1.311 Latest v2.1.322 Next v2.1.322 Feeds RSS JSON llms.txt llms-full.txt Unofficial
One change · api

then: histchars= HISTFILE=/dev/null ant beta:worker poll --workdir /workspace changedmanaged-agents/self-hosted/call-the-api

Recorded here
Lines+751added
Lines−0removed
From line — no hunk to open at
First seen 12 Nov 2026 this site's first read of the page
Recorded edits1to this page, all time

## Prerequisites ## Point your client at your server ## Start a session ## Send a message and read the reply ## Move data in and out of a session ## Find more examples in the hosted guides ## Run your own workers ### Create an environment and its key ### Run a local experiment ### Run workers in production ### Build your own sandbox image ### Move workers from the hosted service ## Next steps

The whole hunk

751 lines, new page
/
lines

A whole new page. There's nothing to diff it against, so here is what it says.

---
title: Call the API on a self-hosted server
url: https://platform.claude.com/docs/en/managed-agents/self-hosted/call-the-api
description: Point the official SDK, cURL, or the ant CLI at your self-hosted Claude Managed Agents server, start a session, and read the agent's reply. Then connect workers of your own, if you need them.
---

<Note>
  To request access to self-hosted Claude Managed Agents, contact your Anthropic account team.
</Note>

A self-hosted Claude Managed Agents server has the same API as Anthropic’s hosted [Managed Agents](https://platform.claude.com/docs/en/managed-agents/overview) service. Your code calls it with the official SDK, cURL, or the `ant` CLI. Two things change: the base URL is your server’s address, and the API key is your [server API key](https://platform.claude.com/docs/en/managed-agents/self-hosted#the-three-credentials) instead of a Claude API key.

To create agents and run sessions in a browser, see [Use the console on your server](https://platform.claude.com/docs/en/managed-agents/self-hosted/console).

## Prerequisites

* **A running server:** Start one with [Get started with self-hosted Claude Managed Agents](https://platform.claude.com/docs/en/managed-agents/self-hosted/quickstart) or [Deploy on Kubernetes](https://platform.claude.com/docs/en/managed-agents/self-hosted/kubernetes).
* **Access to the server:** If someone else runs the server, ask them for its address and how to authenticate. If they use single sign-on, see [Let developers log in from a terminal](https://platform.claude.com/docs/en/managed-agents/self-hosted/configure#let-developers-log-in-from-a-terminal).
* **The `ant` CLI:** Install the latest version, as the [CLI quickstart](https://platform.claude.com/docs/en/cli-sdks-libraries/cli/quickstart#installation) shows.

## Point your client at your server

The SDK and the `ant` CLI read the server address from `ANTHROPIC_BASE_URL` and the API key from `ANTHROPIC_API_KEY`. Set both variables in a terminal that you keep for this server.

For the [quickstart stack](https://platform.claude.com/docs/en/managed-agents/self-hosted/quickstart), run these commands from the directory that holds your `.env` file:

```bash
export ANTHROPIC_BASE_URL=http://127.0.0.1:8400
export ANTHROPIC_API_KEY=$(grep '^CMA_SERVER__API_KEY=' .env | cut -d= -f2)
```

On Kubernetes, set the two variables as [Run a session](https://platform.claude.com/docs/en/managed-agents/self-hosted/kubernetes#run-a-session) shows, and keep its port-forward running.

In that terminal, every `ant` command, such as `ant beta:agents list`, reaches your server. Don’t run Claude Code or `docker compose` in that terminal, because they read the same variables.

## Start a session

A session needs the ID of an agent and the ID of an environment:

* **Agent:** Create one as [Create an agent](https://platform.claude.com/docs/en/managed-agents/agent-setup#create-an-agent) shows, with your client pointed at your server. If you send raw HTTP requests, replace `https://api.anthropic.com` in the URL with `$ANTHROPIC_BASE_URL`.
* **Environment:** The quickstart stack creates one named `compose-sandbox`, and the Helm charts create one named `default`. `ant beta:environments list` prints each environment’s name and ID. For your own workers, it’s the ID that the admin CLI printed in [Run your own workers](https://platform.claude.com/docs/en/managed-agents/self-hosted/call-the-api#point-a-worker-at-your-server).

Put your two IDs in your shell, in place of these example IDs:

```bash
export AGENT_ID=agent_011CYm1BLqPXpQRk5khsSXrs
export ENVIRONMENT_ID=env_01595EKxaaTTGwwY3kyXdtbs
```

The following example creates a session and sends its first message in the same request:

<CodeGroup>
  ```bash cURL
  curl -sS --fail-with-body "$ANTHROPIC_BASE_URL/v1/sessions" \
    -H "x-api-key: $ANTHROPIC_API_KEY" \
    -H "anthropic-version: 2026-10-21" \
    -H "anthropic-beta: managed-agents-2026-04-01" \
    -H "content-type: application/json" \
    -d '{
      "agent": "'"$AGENT_ID"'",
      "environment_id": "'"$ENVIRONMENT_ID"'",
      "initial_events": [
        {
          "type": "user.message",
          "content": [{"type": "text", "text": "List the files in the working directory."}]
        }
      ]
    }'
  ```

  ```bash CLI
  ant beta:sessions create --agent "$AGENT_ID" --environment-id "$ENVIRONMENT_ID" \
    --initial-event '{type: user.message, content: [{type: text, text: "List the files in the working directory."}]}'
  ```

  ```python Python
  import os

  from anthropic import Anthropic

  client = Anthropic()

  session = client.beta.sessions.create(
      agent=os.environ["AGENT_ID"],
      environment_id=os.environ["ENVIRONMENT_ID"],
      initial_events=[
          {
              "type": "user.message",
              "content": [
                  {"type": "text", "text": "List the files in the working directory."}
              ],
          },
      ],
  )
  print(session.id)
  ```

  ```typescript TypeScript
  import Anthropic from "@anthropic-ai/sdk";

  const client = new Anthropic();

  const session = await client.beta.sessions.create({
    agent: process.env["AGENT_ID"]!,
    environment_id: process.env["ENVIRONMENT_ID"]!,
    initial_events: [
      {
        type: "user.message",
        content: [{ type: "text", text: "List the files in the working directory." }]
      }
    ]
  });
  console.log(session.id);
  ```

  ```csharp C#
  using System;
  using Anthropic;
  using Anthropic.Models.Beta.Agents;
  using Anthropic.Models.Beta.Sessions;
  using Anthropic.Models.Beta.Sessions.Events;

  AnthropicClient client = new();

  var session = await client.Beta.Sessions.Create(new()
  {
      Agent = Environment.GetEnvironmentVariable("AGENT_ID")!,
      EnvironmentID = Environment.GetEnvironmentVariable("ENVIRONMENT_ID")!,
      InitialEvents =
      [
          new BetaManagedAgentsUserMessageEventParams
          {
              Content =
              [
                  new BetaManagedAgentsTextBlock
                  {
                      Text = "List the files in the working directory.",
                  },
              ],
          },
      ],
  });
  Console.WriteLine(session.ID);
  ```

  ```go Go
  package main

  import (
  	"context"
  	"fmt"
  	"os"

  	"github.com/anthropics/anthropic-sdk-go/v2"
  )

  func main() {
  	client := anthropic.NewClient()

  	session, err := client.Beta.Sessions.New(context.Background(), anthropic.BetaSessionNewParams{
  		Agent: anthropic.BetaSessionNewParamsAgentUnion{
  			OfString: anthropic.String(os.Getenv("AGENT_ID")),
  		},
  		EnvironmentID: os.Getenv("ENVIRONMENT_ID"),
  		InitialEvents: []anthropic.BetaSessionNewParamsInitialEventUnion{{
  			OfUserMessage: &anthropic.BetaManagedAgentsUserMessageEventParams{
  				Content: []anthropic.BetaManagedAgentsUserMessageEventParamsContentUnion{{
  					OfText: &anthropic.BetaManagedAgentsTextBlockParam{
  						Text: "List the files in the working directory.",
  					},
  				}},
  			},
  		}},
  	})
  	if err != nil {
  		panic(err)
  	}
  	fmt.Println(session.ID)
  }
  ```

  ```java Java
  import com.anthropic.client.AnthropicClient;
  import com.anthropic.client.okhttp.AnthropicOkHttpClient;
  import com.anthropic.models.beta.sessions.SessionCreateParams;
  import com.anthropic.models.beta.sessions.events.BetaManagedAgentsUserMessageEventParams;

  void main() {
      AnthropicClient client = AnthropicOkHttpClient.fromEnv();

      var session = client.beta().sessions().create(SessionCreateParams.builder()
          .agent(System.getenv("AGENT_ID"))
          .environmentId(System.getenv("ENVIRONMENT_ID"))
          .addInitialEvent(BetaManagedAgentsUserMessageEventParams.builder()
              .addTextContent("List the files in the working directory.")
              .build())
          .build());
      IO.println(session.id());
  }
  ```

  ```php PHP
  <?php

  use Anthropic\Client;

  $client = new Client();

  $session = $client->beta->sessions->create(
      agent: (string) getenv('AGENT_ID'),
      environmentID: (string) getenv('ENVIRONMENT_ID'),
      initialEvents: [
          [
              'type' => 'user.message',
              'content' => [['type' => 'text', 'text' => 'List the files in the working directory.']],
          ],
      ],
  );
  echo $session->id, "\n";
  ```

  ```ruby Ruby
  require "anthropic"

  client = Anthropic::Client.new

  session = client.beta.sessions.create(
    agent: ENV.fetch("AGENT_ID"),
    environment_id: ENV.fetch("ENVIRONMENT_ID"),
    initial_events: [
      {
        type: :"user.message",
        content: [{type: :text, text: "List the files in the working directory."}]
      }
    ]
  )
  puts session.id
  ```
</CodeGroup>

The response holds the session’s ID, which starts with `sesn_`. The agent starts work at once. Its built-in tools, such as `bash`, run on a worker that serves the environment.

To watch the session, open the [console on your server](https://platform.claude.com/docs/en/managed-agents/self-hosted/console) in a browser, select **Sessions**, and then select the session. A session that you started with the server API key, as on this page, appears only to administrators.

To follow the session in your terminal instead, pass its ID to [`ant beta:sessions connect`](https://platform.claude.com/docs/en/cli-sdks-libraries/cli/sessions-connect):

```bash
ant beta:sessions connect sesn_011CZkZAtmR3yMPDzynEDxu7
```

For what else a session can do, such as pinning an agent version, see [Start a session](https://platform.claude.com/docs/en/managed-agents/sessions).

## Send a message and read the reply

Put your session’s ID in your shell, in place of this example ID:

```bash
export SESSION_ID=sesn_011CZkZAtmR3yMPDzynEDxu7
```

Wait until the session is idle before you run the next example. The example stops reading when a turn ends. If an earlier turn is still running, its end can stop the example before the reply to your message arrives. The console and `ant beta:sessions connect` both show the session’s status.

The following example sends a message and prints the agent’s reply. It opens the session’s event stream first, because a stream delivers only the events that come after it opens:

<CodeGroup exclude="shell">
  <CodeGroupItem language="cURL">
    This workflow needs more logic than a single shell command. Use the [Anthropic SDK](https://platform.claude.com/docs/en/cli-sdks-libraries/overview) to run it.
  </CodeGroupItem>

  <CodeGroupItem language="CLI">
    This workflow needs more logic than a single shell command. To send messages and read the replies in your terminal, use [`ant beta:sessions connect`](https://platform.claude.com/docs/en/cli-sdks-libraries/cli/sessions-connect).
  </CodeGroupItem>

  ```python Python
  import os

  from anthropic import Anthropic

  client = Anthropic()
  session_id = os.environ["SESSION_ID"]

  with client.beta.sessions.events.stream(session_id) as stream:
      client.beta.sessions.events.send(
          session_id,
          events=[
              {
                  "type": "user.message",
                  "content": [
                      {"type": "text", "text": "Summarize what you did in one sentence."}
                  ],
              },
          ],
      )

      for event in stream:
          match event.type:
              case "agent.message":
                  for block in event.content:
                      if block.type == "text":
                          print(block.text, end="")

Cut at 300 lines. The page has the rest.

Feedback