oag_ User API Key — see
Authentication & API Keys for how to obtain one),
the same agent identifier (agentId), and the same task lifecycle
semantics — only the wire shape differs.
| Mode | Endpoint | When to use |
|---|---|---|
| Blocking invoke | POST /api/v1/agents/{agentId}/invoke | Short prompt, expect reply within seconds; you want a single JSON response. |
| Streaming invoke (SSE) | POST /api/v1/agents/{agentId}/invoke with Accept: text/event-stream | Long-running prompt, you want token-by-token rendering. |
| Async task | POST /api/v1/agents/{agentId}/tasks + poll / SSE /events | Fire-and-forget, agent may take minutes to hours, you need a task_id for cancel / resume / audit. |
chatinvoke core (see ADR
0017) so result
shape, status semantics, and SSE wire format are consistent across
modes.
1. Blocking invoke
The simplest mode. Returns a single JSON response once the agent finishes (or the gateway times out, default 120s).Request
Response (200)
TypeScript SDK
Go SDK
2. Streaming invoke (SSE)
Same endpoint, differentAccept header. The response body is an SSE
stream with delta events (incremental text) and a terminal done
event.
Request
Response (SSE)
The stream is one of three frame shapes, modelled in the contract asInvokeEventStream (a oneOf of InvokeAgentSSEDelta /
InvokeAgentSSEError / InvokeAgentSSEDone). Unlike the
/tasks/{id}/events stream, the invoke endpoint does NOT name the
SSE event — every frame is a bare data: line and clients
discriminate via the JSON type field:
error frame is
emitted before the final done:
timeout_ms is server-clamped at 115 s (see the OpenAPI spec’s
InvokeAgentRequest.timeout_ms.maximum). Above that the clamp is
silent — the gateway still emits service_timeout if the agent
doesn’t reply within the effective window. For work that may exceed
~2 minutes, switch to the async task API
which returns immediately and lets you observe progress over SSE.
SSE frame fields
| Frame | Field | Type | Description |
|---|---|---|---|
delta | type | "delta" | Frame discriminator |
delta | text | string | Incremental token chunk; concatenate in order |
error | type | "error" | Frame discriminator |
error | code | string | Stable machine code (see Error code reference) |
error | status_code | integer | Equivalent HTTP status if this were a blocking call |
error | message | string | Human-readable explanation |
done | type | "done" | Frame discriminator; always the terminal frame |
done | text | string | Full concatenated reply (matches blocking response) |
done | context_id | string | MS channel id; reuse to keep a conversation pinned |
done | is_error | boolean | true if the run ended in error; error / code populated then |
done | error | string | Human-readable error message when is_error=true |
done | code | string | Stable error code (mirrors error.code for streamed errors, or maps from a synchronous apierror for never-streamed-an-error cases) |
Error code reference
The same codes show up inerror.code / done.code and in blocking
JSON error envelopes. Use them as your switch keys — the
status_code / message fields are presentation, not contract.
The full table lives in Error Reference —
one source of truth for HTTP status × wire code × SSE frame across
the entire OpenAPI surface. Common ones you’ll need to handle on the
invoke path:
agent_not_found(404) — verify ownership / visibilityagent_service_unavailable/agent_offline(503) — retry brieflyconflict(409) — agent busy / refused / duplicate idempotency key (inspectmessageto discriminate)service_timeout(504) — switch to asynctasksforbidden(403) — use a credential that owns the agentrate_limited(429) — honourRetry-After
TypeScript (raw fetch)
The generated SDK’s blockinginvokeAgent cannot stream — for SSE use
fetch directly:
3. Async task (recommended for long work)
The canonical task core. Submit returns 202 immediately with atask_id. Use GET /tasks/{taskId} to poll, or subscribe to
GET /tasks/{taskId}/events (SSE) for live updates. The lifecycle
supports cancel and continue.
3a. Submit
3b. Poll for state
status flips to one of
succeeded / failed / canceled / timeout / rejected and
result (success) or error (failure) is populated. Terminal states
are leaf nodes in the state machine — polling can short-circuit.
3c. Live SSE event stream
event: end always fires once. Its reason field is one
of:
reason | Meaning |
|---|---|
task_terminal | Task reached a terminal TaskStatus (succeeded / failed / canceled / timeout / rejected). The preceding event: message is the terminal reply. |
channel_closed | Underlying Message Service channel was closed externally (e.g. by an admin or reaper). Treat as terminal. |
stream_closed | Client-side close, or gateway dropping the stream due to idle timeout. Re-subscribe to resume. |
TaskEventStream
schema for the full
list of type values inside individual event: message frames.
3d. Cancel
3e. Continue (resume input_required / auth_required)
Some agents pause mid-task to request additional input or an OAuth-style permission grant. The state flips toinput_required (or
auth_required). Resume with:
auth_required pause set "auth_grant": true to send the
user.auth_grant envelope instead.
TypeScript SDK
3f. List your tasks
Page through tasks you’ve submitted to a particular agent. The list is backed by Message Service channel metadata, so it is consistent with theGetTask snapshot you get from §3b.
| Name | Type | Default | Description |
|---|---|---|---|
state | active | closed | all | active | Filter by channel lifecycle. active matches open tasks; closed matches terminal tasks. |
since | RFC3339 timestamp | unset | Only return tasks created on or after this instant. Combine with the next_since cursor for forward pagination. |
limit | integer | 50 (max 200) | Maximum rows per page. |
protocol is openapi — conversation channels live under
GET /api/v1/agents/{agentId}/conversations.
Cross-agent variant — GET /api/v1/tasks
If you’ve submitted tasks to multiple agents and want a unified
“my tasks” view (common for multi-agent UIs), call the
cross-agent endpoint instead:
tasks[] rows, same next_since cursor — so SDKs can share the
decode + pagination code. The optional agent_id query param
narrows back down to a single agent without forcing a different
endpoint path. Use this when you don’t know in advance which
agents the caller has submitted against.
3g. Replay task messages
Fetch the full message log for a single task. Useful for surfacing the agent’s intermediate steps after the SSE event stream has already closed.| Name | Type | Default | Description |
|---|---|---|---|
since | integer (offset) | 0 | Only return messages with offset > since. Page forward by passing the last returned row’s offset; when the response’s latest_offset equals that value the caller is caught up. |
limit | integer | 200 (max 500) | Maximum rows per page. |
TypeScript SDK (list helpers)
Comparison summary
invoke (blocking) | invoke (SSE) | tasks (async) | |
|---|---|---|---|
| HTTP shape | Single JSON | SSE stream | 202 + poll / SSE |
| Cancel | No (caller disconnects) | No (caller disconnects) | Yes (explicit) |
| Continue | No | No | Yes (input_required / auth_required) |
| Server timeout | 120s default | 120s default | deadline_ms (max 7 days) |
| Status visibility | Only final | Streaming + final | Per-poll + per-event |
task_id to track | No (use context_id) | No (use context_id) | Yes |
| Idempotency | No | No | Yes (idempotency_key) |
| Best for | Quick lookup, RAG | Chat UX | Long jobs, batch, headless |
Status reference (ADR-0017)
| status | terminal | meaning |
|---|---|---|
queued | no | Submitted, not yet picked up |
running | no | Agent producing output |
input_required | no | Paused, waiting for user.continue |
auth_required | no | Paused, waiting for user.auth_grant |
succeeded | yes | Terminal success; result populated |
failed | yes | Terminal error; error populated |
canceled | yes | Cancelled by caller |
timeout | yes | Deadline elapsed before terminal |
rejected | yes | Agent refused (e.g. agent_busy on single-turn devices) |
See also
- Conversations vs Tasks — multi-turn dialog
API, when to reach for it instead of
invoke/tasks, and the full SSEsince-cursor contract - Streaming (SSE) — canonical SSE framing / reconnect / drop-compensation reference for the three streaming surfaces
- Error Reference — every wire
codethis surface can return - Authentication & API Keys — JWT vs
oag_and the scope table - OpenAPI contract — the source of truth
- ADR 001 — openapi-gateway as the sole OpenAPI implementer
- ADR 0017 — Unified Task Core
- ADR 0017 follow-up — audit-v4 quick wins + pre-existing bug fixes
- ADR 0013 — MS is IM, not a task state machine
- SDK validation runbook
- Operator validation matrix
- @beeos-ai/sdk on npm
- github.com/beeos-ai/sdk-go