Help Center › Agents Developer Help › Developer API
Call your agent — the streaming API
Availability: All plans. Requires a deployed agent and an agent token.
POST /v3/agent/stream is the one endpoint that runs your agent. You send the user's message; the agent streams back everything it does — tokens as they're generated, sub-agent activity, and a final completion event with token usage — over Server-Sent Events (SSE) in native LangChain format, directly compatible with LangChain.js deserialization.
Request
POST https://api.agentman.ai/v3/agent/stream
Authorization: Bearer <AGENT_TOKEN>
Content-Type: application/json
| Field | Type | Description |
|---|---|---|
user_input |
string or array | The user's message. A plain string for text, or an array of content parts for multimodal input. |
conversation_id |
string | Your conversation key. Same ID = same conversation; the agent loads its own history server-side. Always send one you generated. |
model_name |
string | Override the agent's configured model for this request (must be a model from /v3/agent/models). |
attachment_file_ids |
string[] | IDs of files you uploaded via the Files API — the recommended way to attach files. |
attachment_urls |
string[] | Publicly fetchable file URLs to attach instead of (or alongside) file IDs. |
debug |
boolean | Default false. When true, tool-call payloads are kept in the streamed messages and extra debug detail is included. When false, tool calls are stripped so end users never see them. |
reasoning_effort |
"low" | "medium" | "high" |
Reasoning depth for thinking models that support it. |
verbosity |
"low" | "medium" | "high" |
Output verbosity for models that support it. |
environment_overrides |
object | Runtime values that override the agent's stored environment variables — used for {{variable}} substitution in the agent's HTTP/MCP tools. |
channel |
"tester" | "previewer" |
Skill-loading channel: prioritizes draft skill versions. Omit in production to use published versions only. |
You can also pass optional session metadata for analytics — user_id, user_email_address, session_id, device_id, browser_language, browser_timezone, page_url, referer_url, custom_tags (object), and similar — all of which flow into conversation logging and AgentLens.
Attachments are validated against the agent's model before the run starts: a MIME type the model can't read is rejected up front rather than failing mid-answer. Check what the model accepts with GET /v3/agent/capabilities.
The response stream
The response is text/event-stream. Each event is one line of data: {json} followed by a blank line. Your parser must also tolerate two kinds of keep-alive noise:
- Comment lines starting with
:(heartbeats sent during long tool runs) — ignore them. - Empty data frames sent periodically to detect disconnected clients — ignore those too.
Every real event is a JSON object with a type field:
langchain_message_chunk — tokens, as they're generated
The event you render in real time. content_text is the ready-to-use plain text; data is the full serialized LangChain message chunk (a JSON string — parse it only if you want tool-call structure, IDs, or to rehydrate with LangChain.js).
{
"type": "langchain_message_chunk",
"message_class": "AIMessageChunk",
"content_text": "Hello! I can help you with",
"data": "{\"lc\": 1, \"type\": \"constructor\", \"id\": [\"langchain\", \"schema\", \"messages\", \"AIMessageChunk\"], \"kwargs\": {...}}",
"metadata": { "event_number": 4, "stream_mode": "messages", "debug": false }
}
langchain_message — complete messages, per workflow node
Emitted when a workflow node finishes, carrying the full message rather than a token. Useful for reconciling final state; most UIs render chunks and use these as checkpoints. metadata.node_name says which node produced it and metadata.is_sub_agent_response flags sub-agent output.
sub_agent_chunk and thought — sub-agent activity
If your agent delegates to sub-agents, their streamed content arrives as sub_agent_chunk (with metadata.sub_agent_name and metadata.tool_call_id) and their reasoning as thought. Render them if you want a "working…" panel; skip them for a plain chat UI.
error — something went wrong mid-stream
Streams don't fail with HTTP status codes once started; they emit an error event and end:
{
"type": "error",
"data": {
"error": "Stream processing timeout",
"error_code": "TIMEOUT_ERROR",
"details": "The request took too long to complete"
}
}
Error codes you may see: TIMEOUT_ERROR / STREAM_TIMEOUT (no model event for 5 minutes), RATE_LIMIT_ERROR, AUTH_ERROR, INVALID_REQUEST_ERROR, SUB_AGENT_ERROR, LLM_CALLBACK_ERROR.
stream_complete — always the last event
{
"type": "stream_complete",
"metadata": {
"usage": { "input_tokens": 812, "output_tokens": 96, "total_tokens": 908 },
"duration_ms": 2340,
"model_name": "gpt-4o",
"total_events": 41
}
}
When you see it, the turn is done. If the connection drops without one, treat the turn as failed and retry with the same conversation_id.
A minimal JavaScript client
const res = await fetch('https://api.agentman.ai/v3/agent/stream', {
method: 'POST',
headers: {
Authorization: `Bearer ${AGENT_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
user_input: 'Summarize my last order',
conversation_id: conversationId,
}),
});
const reader = res.body.pipeThrough(new TextDecoderStream()).getReader();
let buffer = '';
while (true) {
const { value, done } = await reader.read();
if (done) break;
buffer += value;
let sep;
while ((sep = buffer.indexOf('\n\n')) !== -1) {
const frame = buffer.slice(0, sep);
buffer = buffer.slice(sep + 2);
if (!frame.startsWith('data:')) continue; // heartbeat comment
const payload = frame.slice(5).trim();
if (!payload) continue; // keep-alive frame
const event = JSON.parse(payload);
switch (event.type) {
case 'langchain_message_chunk':
renderToken(event.content_text);
break;
case 'error':
showError(event.data.error);
break;
case 'stream_complete':
finishTurn(event.metadata.usage);
break;
}
}
}
The same parsing works server-side in Node, or in Python with httpx.stream() — split on blank lines, skip : comments and empty payloads, JSON-parse the rest.
Conversations
State lives server-side, keyed by conversation_id. Send a message with the same ID and the agent remembers everything from earlier turns; send a new ID and you start fresh. There is no separate "create conversation" call — the first message with a new ID creates it. The response doesn't echo the ID back, which is why you should always generate it yourself rather than omitting it.
Availability
All plans. Requires a deployed agent and an agent token.