Async & Background Runs
Base URL: https://agent-api.auteryn.ai
There are two ways to run an agent without holding an SSE connection open:
| Approach | When to use |
|---|---|
POST /api/run with stream: false |
Interactive clients that will reconnect to the stream. Returns 202 and runs in the background. See Run an Agent. |
POST /api/run/async |
Server-to-server / webhook-driven background work. Returns 202 immediately; you read the result with the follow-up endpoints. Documented below. |
POST /api/run/async
Section titled “POST /api/run/async”Accepts a run, returns 202 Accepted immediately, then executes in the
background. Auteryn’s Loops use it for messaging Channels (Telegram, WhatsApp,
etc.), and external systems use it for async processing.
Not available to guests. Guests must use
POST /api/run. Messaging trigger sources (telegram,twilio,sms) require a customer-facing agent.
With an agent token, send X-Agent-Id for the agent the token was exchanged for,
leave out flow_id and customer_id, and give each new task_id a fresh UUID.
See Agent token scope.
Request
Section titled “Request”POST https://agent-api.auteryn.ai/api/run/asyncAuthorization: Bearer <jwt>X-Agent-Id: your-agent-uuidContent-Type: application/jsonBody:
{ "query": "Summarize today's new support tickets", "messages": [], "task_id": "3f0e6c1a-8d52-4b77-9a41-6c2d5e7f1a90", "mode": "auto", "async_callback_context": { "connection_id": "", "customer_id": null, "trigger_source": "internal", "job_id": "job_456" }}| Field | Required | Description |
|---|---|---|
query |
✅* | The user’s message. *If empty, it is taken from the last user message in messages. |
messages |
❌ | Conversation history ([{role, content}]). |
task_id |
✅ | Task/thread ID. If no task has this ID, one is created, so use a fresh UUID for a new task. An ID that another organization already holds answers 409 (That task_id is unavailable.) to every caller. |
run_id |
❌ | Provide to set the run ID; auto-generated if omitted. An ID already in use answers 409. |
mode |
❌ | auto, fast, or deep (default: auto). |
flow_id |
❌ | The Loop this run belongs to. A new task keeps it, so a reply on a messaging Channel goes to the customer. An agent token must leave it out (403). |
async_callback_context |
✅ | Who the run is for and, for a Channel run, where the reply goes (see below). |
user_timezone |
❌ | IANA timezone (e.g. America/New_York) used for date-aware answers. |
attachments |
❌ | Files for the agent: [{id, url, filename, mimetype, size}], where url is a link the agent can download. |
async_callback_context:
| Field | Required | Description |
|---|---|---|
connection_id |
✅ | The Connection a Channel reply goes out on when the Loop does not set one. An agent token run has no Channel to reply on; send an empty string. |
customer_id |
❌ | Customer identifier. null when the run doesn’t serve a customer (identity comes from the JWT). An agent token must leave it null (403). |
trigger_source |
❌ | Source that triggered the run (e.g. telegram, internal). Default unknown. |
job_id |
❌ | External job-tracking ID. |
metadata |
❌ | Arbitrary passthrough (chat_id, etc.). |
Response — 202 Accepted
Section titled “Response — 202 Accepted”{ "id": "run_abc123", "task_id": "3f0e6c1a-8d52-4b77-9a41-6c2d5e7f1a90", "status": "accepted", "execution_mode": "fast", "routing_reason": "Customer-facing agent → fast", "message": "Request accepted for background processing"}The final agent result is not in this response, and Auteryn does not call
you back with it: read it with the endpoints below. A run that belongs to a Loop
on a messaging Channel (it has a flow_id and a customer_id) also sends its
reply to that customer on the Channel.
If a person on your team has taken over the conversation, nothing runs: the
response is 200 with "status": "skipped", and the message is saved to the
task.
Following a background run
Section titled “Following a background run”These work for any background run, whether started via /api/run/async or
/api/run with stream: false.
GET /api/run/{task_id}/status
Section titled “GET /api/run/{task_id}/status”Is there an active run for this task, and what’s its progress? Used by clients to decide whether to reconnect after a refresh.
{ "active": true, "run_id": "run_abc", "status": "running", "progress": { "tools_count": 2, "thoughts_count": 5, "has_content": true, "content": "…partial answer…", "started_at": "1783080000000", "agent_mode": "deep" }}status may be running, pending, planning, executing, cancelling,
complete, or error. started_at comes either as milliseconds since the
epoch or as an ISO 8601 timestamp, so accept both. When nothing is active you get
{"active": false}.
GET /api/run/{task_id}/reconnect
Section titled “GET /api/run/{task_id}/reconnect”Reconnect to an in-progress or recently completed run. Behaves in four ways:
- Active run → returns current state and an SSE stream of the remaining events.
- Pending run (not started yet) → returns an SSE stream that waits, then streams.
- Complete run → returns the final state as JSON.
- No run →
404.
Supports resuming from a cursor: send the standard Last-Event-ID header (what a
browser EventSource sends automatically on reconnect), or the last_event_id
query param for hand-built clients.
GET /api/tasks/{task_id}/stream
Section titled “GET /api/tasks/{task_id}/stream”SSE stream of the task’s live events (same
AG-UI event types as POST /api/run). See
Tasks & Runs.
GET /api/runs/{run_id}/events
Section titled “GET /api/runs/{run_id}/events”Paginated JSON history of a run’s events (durable). Good for polling clients that can’t hold an SSE connection. See Tasks & Runs.
Choosing an approach
Section titled “Choosing an approach”- Interactive UI, may refresh →
POST /api/run(stream: true), orstream: falsethenGET /api/run/{task_id}/reconnect. - Webhook / worker that does not wait for the result →
POST /api/run/async. - Polling without SSE →
GET /api/runs/{run_id}/eventswithcursor.
See also the Errors & rate limits reference.

