Orbitali Docs

Agents

Public API endpoints for configuring realtime voice agents.

Agents define prompt behavior, tool execution, voice settings, and phone number routing.

All endpoints on this page use API key authentication:

Authorization: Bearer $ORBITALI_API_KEY

Public agent endpoints

MethodPathDescription
GET/public/v1/agentsList agents
POST/public/v1/agentsCreate an agent
PUT/public/v1/agents/{agent_id}Replace an agent
PATCH/public/v1/agents/{agent_id}Partially update an agent
GET/public/v1/agents/{agent_id}/toolsList custom tools
POST/public/v1/agents/{agent_id}/toolsCreate a custom tool
POST/public/v1/agents/{agent_id}/realtime-sessionsCreate a short-lived WebSocket voice session

Active-agent limits

Agent limits apply to active agents only. Draft and inactive agents can be saved without consuming the active-agent allowance, but only active agents can receive calls or start realtime sessions.

The trial allowance is 1 active agent. Paid plan allowances are controlled by the account's current plan; current defaults are Launch: 2 active agents, Studio: 10 active agents, and Agency: unlimited active agents. If an activation would exceed the current allowance, PUT and PATCH return 409 with code: "AGENT_LIMIT_EXCEEDED".

Create an agent

Creates a draft static, webhook, or http agent and its prompt configuration.

The create endpoint always creates a draft agent. To make an agent available for calls or realtime sessions, update it later with status: "active" using PUT /public/v1/agents/{agent_id} or PATCH /public/v1/agents/{agent_id}.

curl https://api.orbitali.ai/public/v1/agents \
  -X POST \
  -H "Authorization: Bearer $ORBITALI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Receptionist",
    "agentType": "static",
    "language": "en-US",
    "voiceName": "Aoede",
    "phoneNumberAssignments": [
      {
        "phoneNumberId": "40000000-0000-4000-8000-000000000001",
        "handoffPhoneNumber": "+15551234567"
      }
    ],
    "serverUrl": null,
    "serverHeaders": {},
    "serverSecret": null,
    "handoffPhoneNumber": null,
    "promptType": "static",
    "identity": "You are the front desk receptionist for Acme Clinic.",
    "instructions": "Answer caller questions clearly and offer to take a message.",
    "greetingType": "static",
    "staticGreeting": "Thanks for calling Acme Clinic. How can I help?"
  }'

Response:

{
  "id": "9dbf0d0b-2b55-45de-8c41-7a2d9b0ce8e9"
}

Agent request fields

FieldTypeDescription
namestringDisplay name for the agent
agentTypestatic | webhook | httpAgent integration mode. Defaults to webhook when omitted
languagestringLocale used by the realtime session, for example en-US
voiceNamestringRealtime voice name used for generated speech
phoneNumberAssignmentsobject[]Claimed phone number assignments. Each item includes phoneNumberId and optional handoffPhoneNumber used when that inbound number transfers to a human
phoneNumberIdsstring[]Legacy-compatible claimed phone number IDs assigned to the agent. New integrations should use phoneNumberAssignments
serverUrlstring | nullWebhook agent endpoint. Required for dynamic prompts and webhook tools. Use null for static and HTTP agents
serverHeadersobjectExtra string headers sent to the Server URL
serverSecretstring | nullSecret used to sign Server URL webhook requests. When present, Orbitali sends x-orbitali-signature as sha256= plus the lowercase hex HMAC-SHA256 digest of the raw JSON body
handoffPhoneNumberstring | nullLegacy fallback phone number used by transfer_call when no per-number handoff applies
promptTypestatic | dynamicWhether instructions are stored directly or fetched from the Server URL. Dynamic prompts are only supported by webhook agents
identitystringWho the agent is and what role it should play
instructionsstringStatic prompt instructions. Required when promptType is static
greetingTypestatic | dynamic | noneHow the first assistant message is selected
staticGreetingstring | nullRequired when greetingType is static

Full PUT and partial PATCH updates also accept status, which can be draft, active, or inactive. Activating an agent counts against the account's active-agent allowance.

Agent types:

  • static: saved identity, instructions, and greeting only. Static agents do not support custom tools.
  • webhook: saved or dynamic prompt config. Dynamic prompts use serverUrl and agent:assistant-request. Custom tools use serverUrl and agent:tool-call events.
  • http: saved prompt config. Custom tools call their own toolUrl with toolMethod and toolHeaders.

Dynamic prompts require serverUrl and agentType: "webhook". Dynamic greetings require promptType to be dynamic.

Verify signed Server URL requests with the raw request body. Re-serialized or parsed JSON can produce a different HMAC.

Partially update an agent

Updates only the supplied fields and keeps the current phone assignments, prompt fields, greeting fields, and server config unless they are included in the request.

curl https://api.orbitali.ai/public/v1/agents/9dbf0d0b-2b55-45de-8c41-7a2d9b0ce8e9 \
  -X PATCH \
  -H "Authorization: Bearer $ORBITALI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "expectedUpdatedAt": "2026-05-14T12:00:00.000Z",
    "serverUrl": "https://crm.orbitali.ai/api/orbitali/agents"
  }'

The Server URL signing secret can also be updated without resending the full agent:

{
  "expectedUpdatedAt": "2026-05-14T12:00:00.000Z",
  "serverSecret": "..."
}

Response:

{
  "id": "9dbf0d0b-2b55-45de-8c41-7a2d9b0ce8e9"
}

PATCH accepts the same fields as a full update, but every field except expectedUpdatedAt is optional. Use the agent's current updatedAt value from GET /public/v1/agents as expectedUpdatedAt. If the agent changed after that timestamp, PATCH returns 409 so the client can refetch and retry. The merged result must still be valid. For example, promptType: "dynamic" still requires an existing or supplied serverUrl, and greetingType: "dynamic" still requires dynamic prompt mode.

If the update changes a draft agent to status: "active" and the account is already at its active-agent limit, the API returns 409:

{
  "error": "Active agent limit exceeded",
  "code": "AGENT_LIMIT_EXCEEDED",
  "maxAgents": 2
}

Deactivate another active agent or upgrade the account plan before retrying. maxAgents is the active-agent cap for the current plan or trial.

List agents

curl https://api.orbitali.ai/public/v1/agents \
  -H "Authorization: Bearer $ORBITALI_API_KEY"

Response:

[
  {
    "id": "9dbf0d0b-2b55-45de-8c41-7a2d9b0ce8e9",
    "name": "Receptionist",
    "status": "draft",
    "agentType": "webhook",
    "language": "en-US",
    "voiceName": "Aoede",
    "serverUrl": "https://example.com/orbitali/webhook",
    "serverHeaders": {},
    "serverSecret": null,
    "handoffPhoneNumber": null,
    "phoneNumber": null,
    "toolCount": 1,
    "knowledgeDocumentCount": 0,
    "callsToday": 0,
    "successRate": 0,
    "updatedAt": "2026-05-14T12:00:00.000Z"
  }
]

Create a tool

Creates a custom tool for an existing webhook or HTTP agent. Static agents do not support custom tools.

For webhook agents, the agent must have a saved serverUrl. Tool executions are delivered to that Server URL as agent:tool-call events.

For HTTP agents, each tool must include toolUrl. Tool executions call that URL with toolMethod and toolHeaders.

curl https://api.orbitali.ai/public/v1/agents/9dbf0d0b-2b55-45de-8c41-7a2d9b0ce8e9/tools \
  -X POST \
  -H "Authorization: Bearer $ORBITALI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "lookup_customer",
    "description": "Find a customer record by phone number.",
    "parameterSchema": {
      "type": "object",
      "properties": {
        "phone": { "type": "string" }
      },
      "required": ["phone"]
    },
    "responseSchema": null,
    "timeoutMs": 5000,
    "onError": "return_error",
    "enabled": true,
    "toolUrl": null,
    "toolMethod": "POST",
    "toolHeaders": {}
  }'

Response:

{
  "id": "df0ee766-7903-4c13-8547-f6bd65de392a"
}

Tool request fields

FieldTypeDescription
namestringTool name exposed to the model
descriptionstringWhat the tool does and when to call it
parameterSchemaobjectJSON Schema object for tool arguments
responseSchemaobject | nullOptional JSON Schema object for the tool response
timeoutMsnumberTimeout from 1000 to 30000 milliseconds
onErrorreturn_error | return_emptyBehavior when the Server URL returns an error
enabledbooleanWhether the tool is available during calls
toolUrlstring | nullRequired for HTTP agents. Use null for webhook tools
toolMethodGET | POST | PUT | DELETE | PATCH | HEAD | OPTIONSHTTP method used with toolUrl; defaults to POST
toolHeadersobjectString headers sent to toolUrl; defaults to {}

Webhook tool executions are delivered to the agent's Server URL as agent:tool-call events. HTTP tool executions call the tool's own toolUrl.

List tools

curl https://api.orbitali.ai/public/v1/agents/9dbf0d0b-2b55-45de-8c41-7a2d9b0ce8e9/tools \
  -H "Authorization: Bearer $ORBITALI_API_KEY"

Response:

[
  {
    "id": "df0ee766-7903-4c13-8547-f6bd65de392a",
    "name": "lookup_customer",
    "description": "Find a customer record by phone number.",
    "parameterSchema": {},
    "responseSchema": null,
    "timeoutMs": 5000,
    "onError": "return_error",
    "enabled": true,
    "toolUrl": null,
    "toolMethod": "POST",
    "toolHeaders": {}
  }
]

WebSocket voice sessions

Use WebSocket sessions when a website needs to talk to an active agent directly instead of calling through a phone number. Create the session from your backend with an Orbitali API key, then pass the returned websocketUrl to browser code. Do not expose long-lived API keys in the browser.

curl https://api.orbitali.ai/public/v1/agents/9dbf0d0b-2b55-45de-8c41-7a2d9b0ce8e9/realtime-sessions \
  -X POST \
  -H "Authorization: Bearer $ORBITALI_API_KEY"

Response:

{
  "token": "eyJ...signature",
  "expiresAt": "2026-05-15T12:00:00.000Z",
  "websocketUrl": "wss://agent.orbitali.ai/ws/agents/9dbf0d0b-2b55-45de-8c41-7a2d9b0ce8e9?token=eyJ...signature",
  "protocol": {
    "inputAudio": { "encoding": "pcm16", "sampleRate": 16000 },
    "outputAudio": { "encoding": "pcm16", "sampleRate": 24000 }
  }
}

The WebSocket accepts JSON messages:

{ "type": "input_audio", "audio": "<base64 pcm16 16kHz mono audio>" }

Close the conversation with:

{ "type": "stop" }

The server sends:

{ "type": "session.started", "callId": "..." }
{ "type": "output_audio", "audio": "<base64 pcm16 24kHz mono audio>", "encoding": "pcm16", "sampleRate": 24000 }
{ "type": "transcript", "role": "assistant", "text": "..." }
{ "type": "clear" }

Session tokens expire after 60 seconds. Once connected, the WebSocket remains active until the conversation ends or the socket closes.

Errors

StatusCodeMeaning
400-Invalid request body, invalid agent ID, unsupported static-agent tool, missing webhook serverUrl, or missing HTTP toolUrl
401-Invalid or missing API key
404-Agent not found
409AGENT_LIMIT_EXCEEDEDUpdating an agent to active would exceed the account's active-agent allowance. The response includes maxAgents
409-Agent update conflict, or agent must be active before creating a realtime session
500-Realtime WebSocket URL or token signing is not configured

On this page