Agents API
Build AI-powered conversational and task agents. Create agents with custom tools and guardrails, deploy them to messaging and voice channels, run conversations programmatically, and access interaction history. Base path:/api/v1/agents
Using the SDKs
client.request() escape hatch above. See the Python SDK.
Returns the typed ApiResponse envelope. See the SDK index at SDK quickstart.
CRUD Operations
Create Agent
POST /api/v1/agents
string
required
Agent display name
string
default:"custom"
Agent type. One of
custom, chatbot, router, voice, workflow. Optional — defaults to custom when omitted.string
default:"claude-sonnet-4-6"
Anthropic Claude model id. Orbit is Anthropic-only. Supported values:
claude-opus-4-7, claude-sonnet-4-6, claude-haiku-4-5-20251001, claude-fable-5. Note: claude-fable-5 is temporarily unavailable (export-suspended); requests pinned to it fall back to claude-opus-4-7. This list can change as models are added or availability shifts — call GET /api/v1/agents/models for the live, authoritative set.Optional. When you omit model, the agent record is created with claude-sonnet-4-6 stored as its model — this is the create-time field default, and it is the model that agent runs on.Do not confuse this with the platform default model, which the runtime resolves separately (admin pin → auto-discovery → boot fallback) for agents left on the platform default rather than pinned here. That chain can settle on a different id, so the model serving a platform-default agent need not match this field’s default. See Agent model selection.string
System instructions that define the agent’s behavior and personality. Optional.
object[]
Tool definitions the agent can invoke
Channel binding is not set at create time.
POST /api/v1/agents does not
accept a channels field — pass it and it is silently ignored. Bind an agent
to channels when you activate it via Deploy Agent.object
Guardrail configuration enforced by Orbit’s agent runtime. There is no separate guardrails endpoint — send this on create or update.
object[]
Conditions that hand a conversation off to a human. Each entry is one of
{ "type": "keyword", "value": "<string>" }, { "type": "sentiment_below", "value": <0–1> }, or { "type": "turn_count_above", "value": <positive integer> }.string[]
IDs of knowledge bases (Qdrant collections) to attach for RAG
number
default:"0.7"
LLM temperature (0.0–2.0)
integer
default:"4096"
Maximum tokens per LLM response
List Agents
GET /api/v1/agents
Retrieve all agents with cursor-based pagination.
string
Cursor for pagination
integer
default:"25"
Results per page (max 200)
string
Filter by status:
draft, active, paused, archivedGet Agent
GET /api/v1/agents/{id}
Retrieve full configuration of an agent including tools, guardrails, and deployment status.
Update Agent
PUT /api/v1/agents/{id}
Update an agent’s configuration. Changes take effect for new conversations immediately.
The body is a partial update: send only the fields you are changing — omitted fields are left exactly as persisted. The same fields as Create Agent are accepted, including status (used to pause and resume an agent), tools, safety_config, and knowledge_base_ids. The response is the full updated agent record.
Delete Agent
DELETE /api/v1/agents/{id}
Delete an agent. Active conversations are terminated gracefully.
204 No Content
Deploy
Deploy Agent
POST /api/v1/agents/{id}/deploy
Activate an agent and make it available on its configured channels. The agent must have a valid system_prompt.
string
required
Agent ID
string
required
The channel to deploy the agent to. One of
webhook, sms, whatsapp, voice, rcs.string
HTTPS callback URL for the
webhook channel. Must be a valid HTTPS URL. An empty string is ignored and leaves any previously set URL unchanged.string
E.164 phone number to bind the agent to. Required when
channel is voice.Undeploy Agent
POST /api/v1/agents/{id}/undeploy
Remove an agent’s channel deployment. This clears the config.deployment
metadata and sets the agent’s status to paused. For a voice deployment
it also releases the bound phone number, so that number becomes available to
deploy to another agent.
No request body is required. To bring the agent back, call
Deploy Agent again — redeploying flips the status back to
active regardless of its previous state.
This is distinct from pausing an agent: pausing stops
new conversations but keeps the channel binding, whereas undeploying removes
the binding entirely.
This endpoint is rate limited to 5 requests per minute per API key, the same
budget as Deploy Agent.
string
required
Agent ID
Pause / Resume Agent
There are no dedicatedpause or resume endpoints. An agent’s lifecycle is
controlled through its status field via Update Agent.
To pause an agent, send PUT /api/v1/agents/{id} with { "status": "paused" }.
Existing conversations are completed but no new ones are started.
To resume a paused agent, send PUT /api/v1/agents/{id} with { "status": "active" }.
To fully remove an agent’s channel deployment (rather than just pause it), use
Undeploy Agent above.
Valid status values are draft, active, paused, and archived.
Chat
Send Chat Message
POST /api/v1/agents/{id}/chat
Send a message to an agent and receive a response. Supports both stateless single-turn and stateful multi-turn conversations.
string
required
Agent ID
string
required
User message text
string
Existing conversation ID to append onto, for multi-turn. Omit to start a new conversation.
object[]
Optional conversation history to seed the agent, additive on top of any persisted state. Each item is
{ "role": "user" | "assistant" | "system", "content": string }. Use this to inject prior turns or context instead of a separate context field.boolean
default:"false"
Run the message in sandbox mode (does not persist the conversation).
string
Associate the conversation with a contact record.
string
Channel the message originates from (e.g.,
whatsapp, sms, web).Streaming is a separate endpoint —
POST /api/v1/agents/{id}/chat/stream — not a stream: true flag on this request. See Streaming Responses below.Streaming Responses
POST /api/v1/agents/{id}/chat/stream
Streaming uses a dedicated endpoint rather than a flag on the chat request. It accepts the same request body as POST /api/v1/agents/{id}/chat (message, conversationId, history, sandbox, contactId, channel) and returns the response as Server-Sent Events (SSE) with Content-Type: text/event-stream. The runtime emits six event types as the turn progresses, each carrying a single JSON data payload:
event: status— a progress update while the turn runs (for example, retrieval or routing).datais{ "status": "...", "detail": "..." };detailmay be omitted.event: token— one incremental fragment of the assistant response.datais{ "content": "..." }. Concatenate everycontentvalue in order to reconstruct the streamed reply.event: tool_start— the agent invoked a tool.datais{ "tool": "...", "input": { ... } }.event: tool_end— a tool returned.datais{ "tool": "...", "input": { ... }, "output": ... }, whereoutputis the tool result (a string or JSON value).event: response— the completed turn.datais{ "response": "...", "tokensUsed": <number>, "promptTokensUsed": <number>, "completionTokensUsed": <number>, "apiCallsUsed": <number>, "escalated": <boolean>, "conversation_id": "..." }.tokensUsedis the scalar total token count for the turn;promptTokensUsedandcompletionTokensUsedsplit it, andconversation_idis the id to reuse for follow-up turns.event: error— a terminal failure (upstream reset, timeout, provider error).datais{ "code": "...", "message": "..." }. Treat this as stream completion.
status, token, tool_start, and tool_end events are progress frames and may arrive zero or more times in any order as the turn runs. The stream terminates with exactly one response (success) or error (failure) event, after which the connection closes.
fetch + a line splitter over the ReadableStream):
httpx — works with the async client too):
Legacy streaming (POST //stream)
POST /api/v1/agents/{id}/stream
A compatibility shim for SDK runtimes that cannot consume the preferred POST /api/v1/agents/{id}/chat/stream endpoint. It runs the same blocking turn as POST /api/v1/agents/{id}/chat, then replays the completed response over Server-Sent Events word by word, with a short gap between words, so a client gets a token-by-token render without the runtime producing true incremental tokens. Prefer chat/stream for new integrations; reach for this endpoint only when your client already expects a token / done SSE shape.
It accepts the same request body as POST /api/v1/agents/{id}/chat (message, conversationId, history, sandbox, contactId, channel) and returns Content-Type: text/event-stream. The endpoint is rate limited to 20 requests per minute per tenant, the same budget as chat/stream.
Three event types are emitted:
event: token— one fragment of the response.datais{ "text": "..." }. The response is split on whitespace and each word and each run of whitespace is sent as its owntokenevent, so concatenating everytextvalue in order reconstructs the original response, spacing included.event: done— the turn completed.datais{ "totalTokens": <number>, "costCents": <number>, "conversationId": "..." }. ReadconversationIdto continue a multi-turn conversation.event: error— a terminal failure.datais{ "code": "...", "message": "..." }. No further events follow.
done event after the last token; a failed stream ends with one error event instead. The connection then closes. If the client disconnects mid-stream, the server stops sending tokens.
token event’s data.text and stop on
done (or error). The simple line-splitting consumers shown for
Streaming Responses above work here unchanged.
Agent Connect (AI ↔ human voice handoff)
Agent Connect is the Node SDK’s typed surface for embedding the AI↔human voice-agent bridge — attach an AI agent to a live conference, hand a live session to a human agent with full context, and watch the session’s turns, tool calls, and handoff in real time — without hand-rolling the underlying route strings.Connect an AI agent to a live call
POST /api/v1/voice/conferences/{conferenceId}/ai-agent
Attaches agentId to a live conference as a participant. The agent leg is dialed back into the tenant’s own conference bridge — this never opens a new outbound leg.
orbit.agents.disconnect(conferenceId) to remove the AI agent from the conference (DELETE /api/v1/voice/conferences/{conferenceId}/ai-agent).
Hand a live AI session to a human
POST /api/v1/voice/calls/{callId}/ai-handoff
Warm-transfers a live call from an AI voice agent to a human agent: generates (or reuses) an AI call summary, persists a context packet (summary, sentiment, topics, action items, and any structured fields the agent collected) for the human agent’s screen-pop, bridges the caller into an ACD queue, then drops the AI leg once the caller is safely queued. The caller is never dropped and never dialed out — it’s routed back into the tenant’s own queueing infrastructure.
orbit.agents.getHandoff(callId) (GET /api/v1/voice/calls/{callId}/ai-handoff). handoff is null when the call was never escalated.
Watch a session in real time
orbit.agents.session.attach(callId) returns an async iterator of typed session events, merging the call’s live transcript with its assist feed:
turn— a caller/agent speech turn (partial or final).tool-call— a one-click-executable action the agent’s assist loop proposed.handoff— the session was just handed off to a human; carries the same packettakeover()persists.status/end/error— stream lifecycle.
.return() on the iterator) to close both underlying connections.
Conversations
List Conversations
GET /api/v1/agents/{id}/conversations
Retrieve conversation history for an agent.
string
Cursor for pagination
integer
default:"25"
Results per page (max 200)
string
Search conversations by message content (case-insensitive substring match, max 200 characters)
Get Conversation Messages
GET /api/v1/agents/{id}/conversations/{conversationId}/messages
Retrieve the full message history of a specific conversation.
Rate Limits
Bound how often an agent can be invoked — independent of the cost controls that bound spend. Configure an agent-wide ceiling plus a separate ceiling for a single caller, so one caller looping or retrying can’t use up the invocation budget meant for everyone else. Management requires theowner or admin role; writes are audit-logged.
Get Rate Limits
GET /api/v1/agents/{id}/rate-limits
Resolve an agent’s current rate-limit configuration together with live usage counters. Pass caller_id to also get that caller’s live usage and remaining headroom.
string
required
Agent ID
string
Caller/end-user identity to report live per-caller usage for (the caller number on voice, or the widget session’s contact ID on chat).
Set Rate Limits
PUT /api/v1/agents/{id}/rate-limits
Set or clear one or more rate-limit axes. Only the fields present in the request body change — an omitted field is left untouched, and an explicit null clears that axis back to unlimited. Provide at least one field.
string
required
Agent ID
integer
Agent-wide short-burst requests-per-minute ceiling across all callers.
0 blocks all invocations; null clears the limit.integer
Agent-wide invocations allowed per UTC calendar day.
integer
Agent-wide invocations allowed per UTC calendar month.
integer
Short-burst requests-per-minute ceiling for a single caller/end-user identity, so one abusive caller doesn’t throttle everyone else.
integer
Invocations allowed per UTC calendar day for a single caller/end-user identity.
MCP Servers
Register your own Model Context Protocol (MCP) servers so an agent can discover and call tools you host, without Devotel adding a built-in integration for each one. At inference time the agent runtime fetches each enabled server, lists its tools, and adds them to the agent’s tool catalog alongside built-in tools. Servers are scoped to a single agent and to your organization. Management endpoints require theowner, admin, or developer role; listing a server’s configuration is available to any authenticated member.
Register MCP Server
POST /api/v1/agents/{agentId}/mcp-servers
string
required
Agent ID the server is registered against.
string
required
Display name for the server. Must be unique within the agent — registering a second server with the same name returns
409 MCP_SERVER_NAME_CONFLICT.string
required
The server’s endpoint. Must be a public
https:// URL. URLs that resolve to private, loopback, link-local, or cloud-metadata addresses are rejected with 422 INVALID_MCP_SERVER_URL.string
required
Transport. Only
http_sse is supported.string
A static bearer token or API key sent to your server, stored encrypted at rest. Mutually exclusive with
oauth2.object
An OAuth2 grant the runtime exchanges for a live access token before calling your server. Mutually exclusive with
auth_credentials. The interactive authorization-code (browser redirect) flow is not supported.string[]
Restrict which of the server’s tools the agent can see and call. Omit to expose every discovered tool. Pass an array to expose only those tool names. Pass
[] to expose none without removing the server.object
Free-form key/value metadata stored with the server.
boolean
default:"true"
Whether the agent loads tools from this server.
Credentials are never returned over the wire. Responses expose only a
has_auth_credentials boolean and auth_type (bearer, oauth2, or none).List MCP Servers
GET /api/v1/agents/{agentId}/mcp-servers
string
required
Agent ID.
string
Cursor for the next page. Pass back the
meta.pagination.cursor value from the previous response; omit for the first page.integer
default:"100"
Results per page (max 200).
id, organization_id, agent_id, name, server_url, server_type, metadata, enabled, created_at, updated_at, has_auth_credentials, and tool_allowlist (null when no allowlist is set). Use meta.pagination.cursor with has_more: true to fetch the next page.
Update MCP Server
PATCH /api/v1/agents/{agentId}/mcp-servers/{id}
Change a registered server’s tool allowlist and/or enabled state. Send at least one field.
string
required
Agent ID.
string
required
MCP server ID.
string[] | null
An array replaces the allowlist (
[] exposes no tools); null clears it so every discovered tool is exposed again; omit to leave it unchanged.boolean
Toggle the server on or off without deleting it.
Delete MCP Server
DELETE /api/v1/agents/{agentId}/mcp-servers/{id}
Remove a registered server. The call is idempotent: deleting an id that no longer exists returns 200 with deleted: 0 rather than a 404, so retries are safe.
string
required
Agent ID.
string
required
MCP server ID.
Probe MCP Server
POST /api/v1/agents/{agentId}/mcp-servers/probe
Test a candidate URL and credentials before registering. The probe runs the same tools/list request the runtime uses at discovery time, so a successful probe predicts the server will register cleanly. Nothing is persisted.
string
required
Agent ID.
string
required
Server endpoint to probe. Same
https://-only, public-address validation as on register.string
Transport.
http_sse if provided.string
Static bearer token to test. Mutually exclusive with
oauth2.object
OAuth2 grant to test (same shape as on register). Mutually exclusive with
auth_credentials.status is one of ok, ssrf_blocked, timeout, unreachable, auth_failed, http_error, or protocol_error. On success tools lists the discovered tool names; otherwise error carries a short, safe explanation.
Test MCP Server
POST /api/v1/agents/{agentId}/mcp-servers/{id}/test
Health-check an already-registered server using its stored credentials, and save the result so the dashboard can show a health status without re-probing.
string
required
Agent ID.
string
required
MCP server ID.
ok, status, tool_count, tools, http_status, error, checked_at), plus the server id and agent_id.
Agent Statuses
Examples
Node.js
A first-party Python SDK is on the roadmap but not yet shipped. Call the REST endpoints above with
requests / httpx / any HTTP client.