Age of AIAGE OF AI
Developers Docs
Scoreexl Voice API · v3.0

Build voice into anything

The Scoreexl Voice API is a single REST surface for text-to-speech, speech-to-text, conversational WebRTC voice agents, retrieval-augmented generation (RAG), phone calls, credits, and webhooks. Every endpoint speaks JSON, supports 53 languages, and is gated by a scoped API-key model — so you can ship a talking product without standing up your own speech stack.

Explore the API

Jump straight to the capability you need. Each card scrolls you to its reference.

Core Concepts

The mental model — how the pieces fit together.

Authentication

JWT sessions or sk_ API keys via Bearer.

Voices

Browse the multilingual voice catalog.

Text-to-Speech

Synthesize natural speech from text.

Speech-to-Text

Transcribe audio in 53 languages.

Agents

Build conversational WebRTC voice agents.

RAG / Knowledge Base

Ground agents in your documents.

Calls & Phone

Place outbound calls on phone numbers.

Webhooks

Receive HMAC-signed real-time events.

API Keys

Create and scope server-to-server keys.

Guides

End-to-end tutorials, step by step.

Core Concepts

Before you write any code, it helps to have a map of the platform. Everything in the API is built from a handful of primitives that compose together. Read this once and the rest of the reference will make sense.

The building blocks

Voices & Languages

A voice is a specific synthetic speaker (an example voice id looks like en-US-aria-hd) in one of 53+ languages. Voices are the raw material for every spoken word — TTS reads text in one, and agents speak in one.

Text-to-Speech (TTS)

Turn a string of text into an audio file using a voice. One-shot, stateless: submit text, get audio back. Use it for notifications, IVR prompts, audiobooks, anything you can pre-render.

Speech-to-Text (STT)

The inverse: upload recorded audio, get a transcript. Use it for call analysis, captions, voice notes, and search over spoken content.

Agents

A configurable, real-time voice bot. An agent ties together a voice, a language, a pipeline mode (how audio is processed), a system prompt (its personality and instructions), and optionally a knowledge base. Agents are conversational and stateful — they listen, think, and talk back.

RAG / Knowledge Bases

Documents you upload are chunked, embedded, and stored in a vector database. At conversation time an agent retrieves the most relevant passages and answers from them — so it can speak accurately about your product, policies, or data instead of hallucinating.

Calls & Phone Numbers

Put an agent on the telephone network. Import a Twilio-backed number, then place outbound calls or receive inbound ones. The same agent pipeline that powers the browser runs over the phone line.

Webhooks

Events the platform pushes to your server — e.g. a call finished, a lead was captured. HMAC-signed so you can trust them. This is how you react to things that happen asynchronously, without polling.

Credits & Usage

Metered operations (synthesis characters, transcription minutes, call seconds) debit a credit balance. You can inspect usage, estimate cost before running a job, and check your balance at any time.

How it all fits

Think of it as a stack. Voices are the bottom layer — every spoken output picks one. TTS and STT are the simplest products: text in / audio out, and audio in / text out. Agents sit on top and orchestrate both in real time — they transcribe what the caller says, reason with an LLM (optionally consulting a knowledge base), and speak the reply in your chosen voice. Attach a phone number and that same agent answers calls. While a conversation runs, webhooks notify your backend of key moments, and credits meter the whole thing.

A useful rule of thumb

If you need one-shot audio or text, reach for TTS or STT. If you need a back-and-forth conversation — in the browser or on the phone — you want an Agent. Agents are where voices, language, pipeline mode, prompt, and RAG all come together.

Quickstart

Get from zero to your first response in three steps. You only need an API key and a single HTTP request — no SDK install required.

1

Create an API key

Open the API Keys page, click Create Key, pick the scopes your integration needs (e.g. tts:generate), and copy the sk_ value. It is shown only once.

2

Make your first request

List the available voices — a simple authenticated GET that confirms your key works. Send your key as a Bearer token.

3

Handle the response

A 200 OK returns a JSON object with a voices array. Grab an id and feed it to to generate audio.

You're connected

A successful response means your key and scopes are valid. From here, head to or .

Base URL & Versioning

All requests are made to the versioned base URL below. Prefix every path you see in these docs with it.

Base URLhttps://voiceai.aicoworker.tech/api/v1

Conventions

ProtocolHTTPS only. Plain-HTTP requests are rejected (HSTS enforced).
VersionThe current major version is v1, embedded in the base URL path.
Content-TypeSend application/json for JSON bodies; multipart/form-data for file uploads.
IDsVoices use integer IDs; agents and API keys use opaque string IDs.
X-Request-IDEvery response carries a correlation ID — include it in support requests.

Authentication

The API supports two authentication methods, both passed via the Authorization: Bearer <token> header. Most data endpoints accept either. The same header shape works in every language:

Keep your secret key safe

Treat sk_ keys like passwords. Never commit them to source control, embed them in client-side/browser code, or paste them into logs. Store them in a secret manager and inject them as environment variables at runtime. If a key leaks, immediately.

Method 1 — JWT Bearer (user sessions)

Exchange email + password at /auth/login for an access token, then send it on every request. Tokens expire — use /auth/refresh to get a new one.

Method 2 — API Key (server-to-server)

API keys are prefixed with sk_ and sent in the same Authorization header as a JWT. The server recognises the sk_ prefix and authenticates the key. Each key is scoped to specific capabilities (see below).

How to create a key

  1. Open the API Keys page in the dashboard.
  2. Click Create Key, name it, and select scopes.
  3. Copy the full key immediately — it is shown only once and never again.
  4. Store it in a secret manager and send it as the Bearer token. Max 10 keys per account.

API Key Scopes

API keys carry a list of scopes that gate which endpoints they can call. New keys default to agent:connect and agent:view. Request only the scopes your integration needs. (Super Admin keys bypass all scope checks.)

11 API Key Scopes

agent:connectConnect to and interact with agents via WebRTC
agent:manageCreate, update, and delete agents
agent:viewView agent details and statistics
rag:manageManage RAG documents and knowledge bases
rag:queryQuery RAG knowledge bases
tts:generateGenerate text-to-speech audio
stt:transcribeTranscribe speech-to-text
phone:manageImport, assign, and delete phone numbers
phone:viewView imported phone numbers and call logs
calls:managePlace outbound calls and cancel active calls
calls:viewView call logs, statistics, and analytics

Retrieve the canonical list at runtime from .

Error Format

Most errors return a single human-readable message under detail:

Validation failures (HTTP 422) return detail as an array of field-level errors, each with loc, msg and type:

HTTP Status Codes

200OKSuccess
201CreatedResource created
204No ContentSuccess with empty body (e.g. delete)
400Bad RequestInvalid parameters or body
401UnauthorizedMissing or invalid credentials
403ForbiddenValid credentials but insufficient scope/role/plan
404Not FoundResource does not exist
422Validation ErrorPydantic schema violation — see the detail array
429Too Many RequestsRate limit exceeded — back off and retry
500Internal Server ErrorUnexpected server error (carries X-Request-ID)

Rate Limits & Quotas

Two independent limits protect the platform: short-term rate limits (requests per window) and plan-based quotas (monthly usage of TTS characters, STT minutes, etc.). Exceeding a rate limit returns 429; exceeding a plan quota returns 403 with an upgrade hint in detail.

What counts against you

Rate limitPer-route request throttling (e.g. synthesis, transcription, RAG uploads). Back off and retry on 429.
TTS charactersSynthesis input is capped at 10,000 characters per request and metered against your monthly plan quota.
STT minutesAudio length is metered (estimated at ~1 minute per MB) against your monthly plan quota. Max upload 100 MB.
API keysMaximum 10 keys per account.
CreditsPaid operations debit your credit balance — check it via /credits/account/balance.

Handling 429s

When you receive a 429 Too Many Requests, back off and retry with exponential delay (e.g. 1s, 2s, 4s) rather than retrying immediately. Spread bulk jobs over time and check your balance via before large batches.

Troubleshooting & FAQ

Quick answers to the issues developers hit most often.

POST/auth/login

Login

Exchange email + password for a JWT access token and refresh token.

Request Body

emailstringrequiredUser email address
passwordstringrequiredUser password

Response

POST/auth/refresh

Refresh Token

Exchange a valid refresh token for a fresh access token.

GET/users/me

Current User

Returns the authenticated user's profile.

Response

GET/voices

List Voices

A voice is a specific synthetic speaker — a named, gendered model in one language, served by the AgeOfAI Voice speech engine. Listing voices is almost always your first call: TTS needs a voice's numeric id, and when you build an agent you pick a voice too. The catalog spans 53+ languages, so filter the response by the language field to find the right speaker.

The field that identifies a voice to the speech engine is voice_key — an example value looks like hi-IN-isha-hd. The first part (hi-IN) is the BCP-47 language/region. Don't construct these by hand — use a real voice id from GET /voices.

Response

GET/voices/{id}

Get Voice

Returns a single voice by its numeric ID — useful for confirming a voice still exists and reading its metadata before synthesizing.

Two different kinds of voice ID

TTS's voice_id is the numeric id from this catalog (e.g. 1). An agent's voice_id is a different thing — a short string UUID for the agent voice. Don't mix them up. Also note: only premium voices (AgeOfAI HD) can be synthesized; standard voices are rejected with a 400.
POST/tts/synthesize

Synthesize Speech

Text-to-Speech follows an asynchronous job model, because rendering high-quality audio takes a moment. You don't get audio back from this call — you get a job record with a status of pending. The work happens in the background; you then poll until it's completed and download the file. This three-step rhythm — submit → poll → download — is the same for STT, so learn it once.

POST /tts/synthesizeGET /tts/syntheses/{id}(repeat until completed)GET …/download

Requires the tts:generate scope on an API key. The body is JSON; the only truly required fields are voice_id and one of input_text / input_file. The prosody knobs (speaking_rate, pitch, volume_gain_db) are optional — leave them out for natural defaults, or nudge them to fit your brand (e.g. speaking_rate: 0.9 for a calmer read).

Request Body (application/json)

voice_idintegerrequiredVoice ID from /voices
input_textstringText to synthesize (max 10,000 chars). Either input_text or input_file is required.
input_filestringServer-side path of a previously uploaded document to extract text from.
output_formatstringmp3 (default), wav, ogg, aac, or flac
speaking_ratefloatSpeaking rate multiplier (0.25–4.0)
pitchfloatPitch adjustment (−20 to +20)
volume_gain_dbfloatVolume gain in dB (−96 to +16)

Response

GET/tts/syntheses/{id}

Get Synthesis

Poll a synthesis job by ID to check its status (pending → processing → completed / failed).

GET/tts/syntheses/{id}/download

Download Audio

Download the finished audio file. Returns an audio/<format> binary stream once the synthesis is completed.

Don't download before it's ready

Calling download while the job is still pending / processing returns 400. Always poll until status === "completed" first, with a small delay between polls (e.g. 1s). Remember the hard limits: 10,000 characters per request, and premium voices only.
POST/stt/transcribe

Transcribe Audio

Speech-to-Text is the mirror image of TTS: you upload a recording (as multipart/form-data, max 100 MB) and get back a transcript. Like TTS it's an async job — this call returns a record with status PENDING, and you poll until COMPLETED to read the text. Requires the stt:transcribe scope.

Two engines back the service: AgeOfAI Speech (standard) (fast and private) and AgeOfAI Speech (enhanced) for the toughest audio. Leave provider_preference as default unless you have a reason to force one. If you know the spoken language, pass its ISO-639-1 code (e.g. en) — it improves accuracy and speed; omit it to auto-detect. Set diarize when you need "who said what" speaker labels.

Multipart Form Fields (multipart/form-data)

fileFilerequiredAudio file: wav, mp3, m4a, ogg, flac, webm, aac, wma, amr, 3gp
provider_preferencestringPreferred STT provider (default: "default")
languagestringISO 639-1 code (e.g. en, es). Auto-detected if omitted.
model_sizestringtiny, base (default), small, medium, large
diarizestringEnable speaker diarization (truthy string)

Response

GET/stt/transcriptions/{id}

Get Transcription

Poll a transcription job by ID. The transcript field is populated once status reaches COMPLETED; the response also tells you which engine actually ran (engine) and the detected language.

Response

Statuses are UPPERCASE for STT

Unlike TTS (whose statuses are lowercase like completed), STT reports PENDINGPROCESSING COMPLETED / FAILED in upper case. Compare case-insensitively to be safe. A handy rule for sizing jobs: audio length is metered at roughly one minute per megabyte.

What is an Agent?

An agent is a configurable, real-time voice bot. Where TTS and STT are one-shot, an agent holds a live conversation: it listens to the user, decides what to say with an LLM, and speaks back — over and over — until the call ends. It is the central object of the platform, and the one thing that pulls every other concept together.

A single agent bundles all of the following into one reusable configuration:

What an agent ties together

system_promptThe bot's brain — its persona, goals, tone, and rules, in plain language. Up to 50,000 characters, so you can encode detailed playbooks. This is the single biggest lever on behaviour.
voice_idThe agent voice (a string UUID) it speaks with. Determines the speaker's character and accent.
languageThe BCP-47 language the agent converses in (e.g. en, hi-IN). The agent will also follow a caller who switches languages mid-call.
pipeline_modeHow audio is processed end-to-end: cascade (Standard) or realtime (Realtime). See the next section — this is an important choice.
knowledge base (RAG)Optional documents the agent can retrieve facts from, so it answers from your content instead of guessing.
background_audio / emotion_profileOptional polish — ambient sound (office, cafe, …) and an emotional tone (friendly, calm, confident, empathetic, excited).
webhook_url + eventsOptional. Where the agent pushes events (connect, disconnect, error, idle, or a custom event like lead_captured).

Once created, the same agent can be used in three places with no extra setup: embedded in your web app over WebRTC, in the dashboard test consoles, and on the telephone by attaching a phone number. Create once, deploy everywhere.

Start with the prompt

90% of an agent's quality comes from its system_prompt. Be explicit about who it is, what it should and shouldn't do, how to handle edge cases, and when to end the call. You can iterate on the prompt with without recreating the agent.

Pipeline Modes — Standard (cascade) vs Realtime

Every agent processes audio through one of two pipelines, set by the pipeline_mode field. They produce the same kind of conversation but make very different trade-offs. Choosing the right one is the most consequential decision after the prompt.

Standard (cascade · default)

AgeOfAI Speech → AgeOfAI intelligence → AgeOfAI Voice

Three discrete stages: transcribe the user (AgeOfAI Speech), generate a reply (AgeOfAI intelligence), speak it (AgeOfAI Voice). Because each stage is separate, you get full control over the exact voice, language, and text — and access to conversation-intelligence processors.

Choose it for: precise voice/brand control, the widest language coverage, and pipelines where you want to inspect or post-process text.

Realtime (realtime)

audio → AgeOfAI Realtime → audio

A single AgeOfAI Realtime speech-to-speech model hears audio and replies in audio directly, with no separate STT or TTS step. Fewer hops means lower latency and a more natural, interruptible feel. The voice character is derived from the agent's configured voice.

Choose it for: the snappiest, most human-feeling conversations where end-to-end latency matters more than fine-grained text control.

Both modes work in the browser and on the phone, and both can use a knowledge base. You can switch a live agent between modes at any time with , so it's easy to A/B them on the same prompt.

When in doubt, start with Standard

The cascade (Standard) pipeline has the broadest compatibility and the most control over voice, language, and text. Switch to realtime when end-to-end latency matters more than fine-grained text control.
GET/agents

List Agents

Returns all voice agents in the authenticated workspace. Requires agent:view with an API key.

Response

POST/agents

Create Agent

Create a new voice agent. Requires the agent:manage scope. The voice_id is the agent voice's string UUID (not the numeric TTS voice ID).

Request Body (application/json)

namestringrequiredHuman-readable name (max 100 chars)
system_promptstringrequiredLLM system prompt (max 50,000 chars)
voice_idstringrequiredTTS voice UUID (6-character identifier)
modelstringAgeOfAI model (default: ageofai-ultra)
languagestringBCP-47 language code (e.g. hi-IN)
emotion_profilestringfriendly (default), calm, confident, empathetic, excited
pipeline_modestringcascade (default, Standard) or realtime (Realtime)
is_publicbooleanMake the agent publicly connectable (default: false)
max_concurrent_connectionsinteger1–100 (default: 10)
webhook_urlstringHTTPS endpoint for agent event webhooks
webhook_secretstringHMAC secret used to sign webhook payloads

Response

Field gotchas

system_prompt is required and capped at 50,000 characters — plenty for a detailed playbook, but a longer prompt will be rejected with 422. voice_id here is the agent-voice string UUID, not the numeric ID from /voices. Omit pipeline_mode to default to cascade.
GET/agents/{id}

Get Agent

Returns a single agent by ID. Requires agent:view.

PUT/agents/{id}

Update Agent

Update any field on an existing agent. All fields are optional. Requires agent:manage.

DELETE/agents/{id}

Delete Agent

Permanently delete an agent. Requires agent:manage.

Connect to an Agent (WebRTC)

Voice agents stream audio over WebRTC via Pipecat. The easiest integration is the @ageofai/vp-ui React component, which negotiates the peer connection for you. Connecting requires the agent:connect scope.

POST/rag/documents/upload

Upload Document

RAG (Retrieval-Augmented Generation) is how you make an agent knowledgeable about your specific content — your product docs, policies, price lists, FAQs — so it answers accurately instead of making things up. You don't fine-tune anything; you just upload documents into a knowledge base, and at conversation time the agent retrieves the passages most relevant to the question and grounds its answer in them.

Here's the lifecycle:

1. Upload / ingest2. Extract text (OCR for images)3. Chunk + embed → vector store4. Agent retrieves at answer time

This endpoint handles steps 1–3 for a single file. Requires rag:manage. Max file size 50 MB. It accepts a wide range of formats — PDF, Office, OpenDocument, CSV/TSV, JSON, HTML, RTF, EML, images (OCR), and plain text/markdown — so most source material works as-is.

Multipart Form Fields (multipart/form-data)

fileFilerequiredThe document to ingest (max 50 MB)
namestringrequiredDisplay name for the document
descriptionstringOptional description
POST/rag/documents/from-url

Ingest from URL

Fetch and ingest a document directly from a public URL — handy for web pages and hosted PDFs. Requires rag:manage.

GET/rag/documents

List Documents

List all documents in your knowledge base.

POST/rag/query

Query Knowledge Base

This is the retrieval step an agent performs automatically — but you can call it yourself to test what your documents will return before wiring them to an agent, or to build your own search experience. It runs a semantic (meaning-based, not keyword) search and returns the most relevant chunks with a similarity score and their source. Requires rag:query. To restrict the search to the documents attached to one agent, use POST /rag/agents/{agent_id}/query instead.

Request Body (application/json)

query_textstringrequiredNatural-language search query

Response

DELETE/rag/documents/{id}

Delete Document

Remove a document and its embeddings from the knowledge base. Deletion is immediate — the agent will no longer retrieve from it on the next turn — so use this to keep answers fresh when source content changes.

Uploading a document isn't enough — attach it

Uploading adds a document to your knowledge base, but an agent only retrieves from documents that are linked to it. After uploading, attach the document to your agent (in the dashboard, or via the agent RAG endpoints) so it actually informs answers. Keep documents focused and well-structured — clean headings and short sections retrieve far better than one giant blob.

Calls & Phone

Connect your voice agents to the telephone network. Import phone numbers (Twilio-backed), then place outbound calls that run an agent over the line, or receive inbound calls. Call audio is bridged through the same Standard or Realtime pipeline your agent uses. Number management requires phone:manage / phone:view; placing and viewing calls requires calls:manage / calls:view.

When a call ends, the platform fires a call-completed webhook (HMAC-signed like all webhooks) so you can store the recording, transcript, and outcome. See .
GET/phone-numbers

List Phone Numbers

Returns the phone numbers imported into the authenticated workspace. Requires phone:view.

Response

POST/calls

Place Outbound Call

Dial a destination number and connect it to one of your agents. The call runs asynchronously — poll /calls/{id} or listen for the call-completed webhook for the outcome. Requires calls:manage.

Request Body (application/json)

agent_idstringrequiredAgent that will handle the call
to_numberstringrequiredDestination number in E.164 format (e.g. +14155550123)
from_numberstringOne of your imported numbers. Defaults to the agent's assigned number.

Response

GET/calls

List Calls

Returns call logs for the workspace with status, duration, and recording references. Requires calls:view.

GET/credits/account/balance

Account Balance

Billing is usage-based and metered in credits. Every paid operation — TTS characters synthesized, STT minutes transcribed, call seconds, etc. — debits your workspace's credit balance. These four endpoints let you observe and predict that spend: check your balance, see an aggregate summary, drill into individual records, and estimate a job's cost before you run it.

This endpoint returns the current credit balance for the authenticated workspace.

Response

GET/credits/usage/summary

Usage Summary

Aggregated usage across services for the current billing window.

GET/credits/usage/records

Usage Records

Paginated log of individual metered operations and their credit cost.

Query Parameters

pageintegerPage number (default: 1)
sizeintegerItems per page (default: 20, max: 100)
POST/credits/usage/estimate

Estimate Cost

Ask "what would this cost?" before committing. Pass the service and the number of units (e.g. characters for TTS) and get back a credit estimate. This is the safe way to size a large batch — estimate first, confirm you have the balance, then run.

Guard your jobs against insufficient balance

For bulk work, the reliable pattern is: estimate → check balance → run. If an operation would exceed your plan quota you'll get a 403 (with an upgrade hint), and short bursts that trip the rate limiter return 429 — back off and retry those. Pace large batches rather than firing them all at once.
GET/auth/api-keys

List API Keys

Returns all API keys for the authenticated user. The full key value is never returned after creation.

Response

POST/auth/api-keys

Create API Key

Create a new API key. The full key value is returned only once — store it immediately. Maximum 10 keys per account.

Request Body (application/json)

namestringrequiredHuman-readable name (max 100 chars)
descriptionstringOptional description (max 500 chars)
scopesstring[]Permission scopes. Defaults to [agent:connect].
expires_in_daysintegerDays until expiry (1–365). Omit for no expiry.

Response

GET/auth/api-keys/scopes

Available Scopes

Returns the canonical list of all 11 scopes and their descriptions. Useful for building a key-creation UI.

POST/auth/api-keys/{id}/revoke

Revoke API Key

Revoke a key without deleting its record (keeps an audit trail). Revoked keys immediately fail authentication.

DELETE/auth/api-keys/{id}

Delete API Key

Permanently delete an API key. All requests using it fail immediately afterwards.

Response

Webhooks

Webhooks push real-time events to your server. Agents can fire events on connect, disconnect, error, idle, and on a custom event you define (e.g. lead_captured). The platform also fires a call-completed webhook when a phone call ends. Every payload is JSON and HMAC-signed so you can verify it came from us.

Signature Headers (sent on every webhook)

X-Webhook-Signaturesha256=<hex> — HMAC-SHA256 of "{timestamp}.{raw_body}" using your webhook secret.
X-Webhook-TimestampUnix epoch seconds when the request was signed. Reject if it is too old (replay protection).
Content-Typeapplication/json — the body is compact JSON (no extra whitespace).

Signature Verification

Recompute the HMAC over the exact string {timestamp}.{raw_body} (the literal timestamp, a dot, then the raw request body) with your shared secret, and compare it to the X-Webhook-Signature header using a constant-time comparison. Use the raw, un-parsed body — re-serializing JSON will change the bytes and break the signature.

POST/agents/{id}/webhooks

Agent Webhooks

Register a webhook on an agent (or set webhook_url + webhook_secret when creating the agent). Choose which events fire: connected, disconnect, error, idle, plus one custom event per agent.

Response

Guide: Synthesize your first speech

The smallest useful thing you can build: turn a sentence into an audio file. This walks the full async TTS rhythm — pick a voice, submit, poll, download.

1

Find a voice ID

Call and pick a premium voice in your target language. Note its numeric id.

2

Submit the synthesis job

POST your text and the voice_id. You'll get back a record with an id and status: "pending".

3

Poll until completed

Check the job every second or so until status is completed (or failed).

4

Download the audio

Done

You now have welcome.mp3. The same submit → poll → download pattern powers transcription — see the next guide.

Guide: Transcribe an audio file

Take a recording and get text back. Same async rhythm as TTS, but the upload is a multipart form.

1

Upload the audio

POST the file as multipart/form-data. Pass language if you know it (faster, more accurate); omit it to auto-detect. You get a record with status: "PENDING".

2

Poll for the transcript

Poll until status is COMPLETED (note: STT statuses are upper case), then read the transcript field.

3

Use the result

The response also tells you which engine ran (engine) and the detected language. Feed the transcript into search, summarization, or your own analytics.

Guide: Build & talk to a voice agent

Create a conversational agent and connect to it in the browser. This is the core of the platform — a real-time bot you can speak with.

1

Create the agent

Decide its persona in system_prompt, pick a voice_id (an agent-voice UUID) and language, and choose a (start with cascade). Requires the agent:manage scope.

2

Connect over WebRTC

Voice agents stream audio over WebRTC. The fastest path is the drop-in React component, which negotiates the peer connection for you. Connecting needs the agent:connect scope.

3

Iterate

Talk to it, then refine. Tweak the prompt, voice, or pipeline mode with — no need to recreate. When it's good, give it a knowledge base (next guide) or a phone number.

Guide: Give an agent a knowledge base

Make your agent answer accurately from your own content. You'll upload a document, verify retrieval, and attach it to the agent.

1

Upload a document

Send the file with a display name. It's extracted, chunked, and embedded into your knowledge base. Requires rag:manage.

2

Verify retrieval

Before relying on it, test what a question pulls back. Good results have high scores and relevant text.

3

Attach it to the agent

Link the document to your agent (in the dashboard, or via the agent RAG endpoints) so it's consulted during conversations. From then on the agent retrieves relevant passages on each turn and answers from your manual instead of guessing.

RAG works in both cascade (Standard) and realtime (Realtime) pipelines, and on phone calls too. Keep documents tidy — clear headings and short sections retrieve far better.

Guide: Place an outbound call & handle the webhook

Put an agent on the phone, dial a number, and reliably capture the outcome when the call ends — without polling — by handling the call-completed webhook.

1

Confirm you have a number

Outbound calls dial from one of your imported numbers. List them with (phone:view).

2

Place the call

Give the agent_id and a destination to_number in E.164 format. The call runs asynchronously; you get a record with status: "queued". Requires calls:manage.

3

Receive the completion webhook

When the call ends, the platform POSTs a call-completed event (recording, transcript, outcome) to your configured webhook URL — HMAC-signed. Verify the signature, then act.

4

Be idempotent

Webhooks may be retried (e.g. if your endpoint is slow or returns a 5xx), so the same event can arrive more than once. Key your processing on the event/call ID and ignore duplicates. Always ACK quickly (return 200 immediately) and do heavy work afterwards, or the delivery may be considered failed and retried.

Verify against the raw body

The HMAC covers the literal string {timestamp}.{raw_body}. If your framework parses JSON before you can read the raw bytes, re-serializing it will change the bytes and the signature check will fail. Capture the raw request body.