Skip to main content

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

Python (same call via the SDK’s escape hatch):
The Python SDK is core-scope — it wraps the 8 core resources (messaging, voice, contacts, campaigns, verify, numbers) and reaches everything else through the generic 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, archived

Get 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.
Response: 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 dedicated pause 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 endpointPOST /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). data is { "status": "...", "detail": "..." }; detail may be omitted.
  • event: token — one incremental fragment of the assistant response. data is { "content": "..." }. Concatenate every content value in order to reconstruct the streamed reply.
  • event: tool_start — the agent invoked a tool. data is { "tool": "...", "input": { ... } }.
  • event: tool_end — a tool returned. data is { "tool": "...", "input": { ... }, "output": ... }, where output is the tool result (a string or JSON value).
  • event: response — the completed turn. data is { "response": "...", "tokensUsed": <number>, "promptTokensUsed": <number>, "completionTokensUsed": <number>, "apiCallsUsed": <number>, "escalated": <boolean>, "conversation_id": "..." }. tokensUsed is the scalar total token count for the turn; promptTokensUsed and completionTokensUsed split it, and conversation_id is the id to reuse for follow-up turns.
  • event: error — a terminal failure (upstream reset, timeout, provider error). data is { "code": "...", "message": "..." }. Treat this as stream completion.
The 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.
On failure:
Node.js consumer (no SDK required — fetch + a line splitter over the ReadableStream):
Python consumer (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. data is { "text": "..." }. The response is split on whitespace and each word and each run of whitespace is sent as its own token event, so concatenating every text value in order reconstructs the original response, spacing included.
  • event: done — the turn completed. data is { "totalTokens": <number>, "costCents": <number>, "conversationId": "..." }. Read conversationId to continue a multi-turn conversation.
  • event: error — a terminal failure. data is { "code": "...", "message": "..." }. No further events follow.
Every successful stream ends with a single 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.
On failure:
Consume it with any SSE client: concatenate every 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.
Call 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.
Read the persisted packet back at any time (for example, to render the screen-pop before the call is answered) with 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 packet takeover() persists.
  • status / end / error — stream lifecycle.
Break out of the loop (or call .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 the owner 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 the owner, 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).
Returns the servers registered for the agent, newest first, with cursor-based pagination. Each entry carries 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.
The response reports the outcome. 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.
The response uses the same verdict fields as the probe (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.