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.