Table of Contents
- Agent and Session — The Core Two-Stage Structure of Claude Managed Agents API
- Creating an Agent with the Python SDK
- Creating a Session and Connecting an Environment
- Implementing SSE Event Streaming
- API Endpoints and Beta Header Configuration
- Handling SSE Disconnects and Event Polling
- Claude Managed Agents API Starter Checklist
- Next Steps — MCP Server Integration and NestJS Modularization
agent = client.beta.agents.create(
name="Coding Assistant",
model="claude-opus-4-8",
tools=[{"type": "agent_toolset_20260401", "default_config": {"enabled": True}}],
)
session = client.beta.sessions.create(
agent={"type": "agent", "id": agent.id, "version": agent.version},
environment_id=environment.id,
)
These two code blocks are essentially the entire Claude Managed Agents API in a nutshell. Create an Agent, spin up a Session, and the agent starts running. In practice, however, connecting this structure to a production system requires handling SSE streaming, Beta header configuration, and disconnect recovery — a non-trivial amount of additional work. From a data pipeline perspective, Agent maps to a pipeline definition (DAG definition), while Session corresponds to a pipeline execution (DAG run).
This article walks through the full flow from Agent creation to event streaming, based on Anthropic’s Managed Agents Python SDK guide.
Agent and Session — The Core Two-Stage Structure of Claude Managed Agents API
The first concept to grasp in this Claude Managed Agents API guide is the Agent-Session separation pattern. Managed Agents provisions a container per session and runs the agent loop within Anthropic’s orchestration layer.
The core flow consists of two stages:
- Agent: A config object created once. It’s an immutable configuration containing the model, tools, and system prompt. Version control is applied, so a created Agent config stays unchanged by design.
- Session: An execution instance created per run. Each Session is pinned to the Agent version at the time of creation.
Managing Agents as immutable configs guarantees configuration consistency even when hundreds of Sessions are spawned from the same Agent. This follows the same design philosophy as separating DAG definitions from DAG runs in data pipelines.
One important constraint exists in this pattern: Sessions cannot directly include model, system, or tools fields. They must reference an Agent object. When creating a Session, only the Agent’s id and version are passed — the Agent handles the rest.
Agent Version Pinning and Flexible References
The Session’s agent field accepts two forms. The first is passing just a string ID, which automatically uses the latest version. The second is passing a {"type": "agent", "id": "...", "version": "..."} object to pin a specific version.
For production environments, explicitly pinning the version is recommended. This follows the same principle as pinning a specific DAG version for execution in a data pipeline. It prevents existing Sessions from unexpectedly running on a new version right after an Agent config update.
| Reference Type | Format | Version Behavior | Recommended for Production |
|---|---|---|---|
| String ID | "agent_id_123" |
Always uses latest version | ❌ |
| Object Reference | {"type": "agent", "id": "...", "version": "..."} |
Uses pinned version | ✅ |
This is analogous to the difference between fetching the latest DAG definition by dag_id in Airflow versus pinning to a specific execution_date.
Creating an Agent with the Python SDK
Using the Claude Managed Agents API starts with installing the Anthropic Python SDK. All API calls go through the client.beta.* namespace.
pip install anthropic
After installation, the code to create an Agent looks like this:
agent = client.beta.agents.create(
name="Coding Assistant",
model="claude-opus-4-8",
tools=[{"type": "agent_toolset_20260401", "default_config": {"enabled": True}}],
)
The client.beta.agents.create call requires three fields:
name: An identifier for the agent, used for differentiation in the management console.model: The Claude model to use. The example above specifiesclaude-opus-4-8.tools: The list of tools to grant the agent. Theagent_toolset_20260401type enables the default toolset.
A system field can also be specified. The system prompt controls the agent’s behavioral scope and response style. Since Agents are versioned immutable configs, changing the system prompt creates a new version.
All Managed Agents API calls must go through `client.beta.*`. Calling `client.agents.create` without beta will fail to find the endpoint. This namespace automatically sets the `anthropic-beta: managed-agents-2026-04-01` header internally.
Design Principles for Agent Creation
From a data pipeline design perspective, deciding how to split Agents requires clear criteria. One option is putting all tools into a single general-purpose Agent; another is separating Agents by purpose, each with optimized system prompts and tool combinations.
A general-purpose Agent is easier to manage but tends toward longer system prompts and reduced tool selection accuracy. Purpose-specific Agent separation improves response quality per Agent but increases version management overhead as the number of Agents grows. This mirrors the tradeoff between monolithic DAGs and micro DAGs in pipeline architecture.
Creating a Session and Connecting an Environment
Once the Agent is ready, create a Session to start actual execution. Session creation only requires two fields: agent and environment_id.
session = client.beta.sessions.create(
agent={"type": "agent", "id": agent.id, "version": agent.version},
environment_id=environment.id,
)
The environment_id specifies the container environment where the Session runs. Managed Agents provisions an isolated container per session, and the Environment config controls the runtime.
Setting model, system, or tools directly on a Session isn’t possible. These three can only be configured at the Agent level — Sessions inherit them indirectly through the Agent reference. This constraint is the crux of the Agent-Session separation pattern.
MCP Server Authentication — Vault Integration
When integrating with external MCP servers, create Credentials in a Vault and link them to the Session via vault_ids. This pattern injects authentication data like API keys and tokens safely through the Vault, rather than hardcoding them in Session code.
Session-hour-based billing has been reported, but a detailed pricing page hasn’t been confirmed on the official domain. Check the Anthropic official pricing page before deploying to production.
From a data pipeline perspective, the Vault pattern is similar to Airflow’s Connections/Variables. Just as database passwords aren’t embedded directly in pipeline code but managed through Airflow Connections, Managed Agents separates Credentials into a Vault and injects them into Sessions.
Implementing SSE Event Streaming
The section requiring the most attention in this Claude Managed Agents API guide is SSE (Server-Sent Events) streaming. Event streaming is SSE-based, and the stream-first pattern is recommended — open the stream first, then send the message to avoid missing initial events.
The reason this ordering matters is clear: sending a message before opening the stream risks missing initial events that fire while the Agent begins processing.
with client.beta.sessions.events.stream(
session_id=session.id,
) as stream:
client.beta.sessions.events.send(
session_id=session.id,
events=[{"type": "user.message", "content": [{"type": "text", "text": "..."}]}],
)
for event in stream:
if event.type == "agent.message":
for block in event.content:
if block.type == "text":
print(block.text, end="", flush=True)
The code structure opens the stream first with a with block, sends the message via events.send inside the block, then iterates through events in the for event in stream loop.
Key Event Types
The event types available on the SSE stream are as follows:
| Event Type | Description | How to Handle |
|---|---|---|
agent.message |
Agent’s text response | Iterate content blocks and output text |
agent.custom_tool_use |
Agent invokes a custom tool | Execute the tool and return the result via events.send |
session.status_idle |
Session enters idle state | Send additional messages or decide to terminate |
session.status_terminated |
Session terminated | Clean up resources and close connections |
When an agent.custom_tool_use event is received, the client side must execute the corresponding tool and send the result back via events.send. This process is the core of the agent loop — an asynchronous handshake pattern similar to how an External Task Sensor in data pipelines waits for external task completion.
This is identical to subscribing a Kafka Consumer first, then having the Producer send messages. Just as a late-connecting Consumer misses initial messages, the SSE stream must be connected before sending messages to capture all initial events.
API Endpoints and Beta Header Configuration
The Python SDK auto-configures the necessary headers on client.beta.* calls, but when making direct REST API calls or using HTTP clients in other languages, headers must be set manually.
The required header set for all Managed Agents API requests:
x-api-key: <your-api-key>
anthropic-version: 2023-06-01
anthropic-beta: managed-agents-2026-04-01
The anthropic-beta header value is managed-agents-2026-04-01. If this value is missing or incorrect, the API returns a 400 error. The full endpoint specification is available in the Managed Agents API reference.
Four Core Endpoints
The Claude Managed Agents API has four core endpoints:
POST /v1/agents: Creates an agent. Includename,model,tools, andsystemfields in the body.POST /v1/sessions: Creates a session. Passagentandenvironment_id.GET /v1/sessions/{id}/events/stream: Opens an SSE streaming connection for real-time event reception.POST /v1/sessions/{id}/events: Sends messages and tool results. Used to deliver user messages or custom tool execution results to the Agent.
When integrating this API in NestJS, use HttpModule or @nestjs/axios to build a service module that calls these endpoints. For SSE streaming, wrapping the connection in an EventSource pattern or an rxjs Observable fits naturally with NestJS’s reactive patterns.
Handling SSE Disconnects and Event Polling
In production, SSE connections can drop due to network instability, load balancer timeouts, or client restarts. The Claude Managed Agents API’s SSE stream does not support replay. This is the most critical reliability concern from a data pipeline perspective.
The recovery procedure after a disconnect:
- Poll existing events via
GET /v1/sessions/{id}/events - Deduplicate against previously received events using event IDs
- Open a new SSE stream connection to receive subsequent events
This pattern resembles Kafka’s offset-based reprocessing, but unlike Kafka where the broker manages offsets, the client must track event IDs directly. Recording received event IDs in local storage (memory, Redis, DB, etc.) is therefore an essential implementation requirement.
Deduplication Strategy
Event reception flow:
┌─────────────────────────────────────────┐
│ SSE Stream (1st connection) │
│ event_001 → event_002 → event_003 │
│ ↓ disconnected │
├─────────────────────────────────────────┤
│ Polling (GET /events) │
│ event_001, event_002, event_003, │
│ event_004 ← missed event │
├─────────────────────────────────────────┤
│ SSE Stream (2nd connection) │
│ event_005 → event_006 → ... │
└─────────────────────────────────────────┘
From the polling results, event_001 through event_003 have already been processed and should be skipped. Only event_004 gets processed before switching to the second stream. Missing this implementation can lead to duplicate message processing or event loss during the disconnection window.
Since the SSE stream doesn’t support replay, production deployments must implement event-ID-based deduplication logic. Omitting this risks duplicate agent responses or double-executed tool calls.
Claude Managed Agents API Starter Checklist
Based on the preceding sections, here’s a checklist of items to verify when applying this in practice. Areas not yet clearly covered in the official documentation are also noted.
Required Implementation Items
- SDK installed via
pip install anthropic model,tools, andnamefields specified during Agent creation- Agent version pinning applied during Session creation (
{"type": "agent", "id": ..., "version": ...}) - Stream-first pattern applied — SSE stream opened before sending messages
anthropic-beta: managed-agents-2026-04-01header included when making direct REST API calls- Event-ID-based deduplication logic implemented
Gaps in Official Documentation
Even after reviewing the Managed Agents architecture overview, the following items remain unaddressed in official documentation:
- No official guide is available in Korean.
docs.anthropic.comredirects toplatform.claude.com, making direct access difficult in some cases. - The detailed pricing page for the reported
$0.08/session-hourbilling structure hasn’t been confirmed on the official domain. - Multi-agent coordination and self-evaluation are in research preview status and require separate access requests.
- Practical examples for self-hosted environment configuration (EnvironmentWorker) are limited.
Given these gaps, verifying the latest information through official Anthropic channels before production deployment is the safe approach.
Next Steps — MCP Server Integration and NestJS Modularization
With the basics of the Claude Managed Agents API flow understood, the next step is MCP server integration. Storing Credentials in a Vault and linking them to Sessions via vault_ids enables secure authentication with external services. In NestJS, separating Vault Credential management into a dedicated VaultModule and injecting it into AgentService via DI is a fitting pattern.
When integrating the Anthropic Python SDK agent with a NestJS backend, the choice comes down to two approaches: running the Python process as a sidecar, or calling the REST API endpoints directly. The former leverages the SDK’s convenience features but adds process management complexity; the latter eliminates language dependencies but requires implementing Beta headers and SSE handling manually.
Connecting the Claude API agent session’s event streaming to NestJS’s @Sse() decorator enables building a pipeline that delivers real-time responses to clients. When the managed-agents-2026-04-01 beta phase transitions to GA, migration from client.beta.* to client.agents.* namespace may be required — adding an abstraction layer during module design is advisable. Mapping the Claude Managed Agents API’s Agent-Session pattern to NestJS module structure extends naturally from NestJS custom providers and the factory pattern.
Related Posts
- Comparing 3 NestJS Clean Architecture Patterns — Hexagonal, Onion, and Layered Selection Guide – Breaks down applicable Clean Architecture patterns in NestJS into three categories: Hexagonal, Onion, and Layered…
- Getting Started with NestJS — From Installation to Configuration – Starting with NestJS begins with the first step. This post provides a NestJS starter guide covering installation through initial configuration…