Skip to main content

Build Your First Voice Agent

The end-to-end path: mint a key, configure a tenant, create an agent with a custom tool, attach a phone number, register a webhook, place a test call, and watch it live.

Prerequisites

  • A running voice server β€” see Overview for the Docker Compose stack
  • Twilio credentials and a phone number
  • An OpenAI key (and an ElevenLabs key if you want its TTS)

1. Mint a tenant API key

Tenant credentials are the unit of access. Every subsequent call uses one as a Bearer token.
The key is returned once. Store it before moving on β€” it can be revoked and reissued, not retrieved.

2. Configure the tenant account

Set the tenant’s provider credentials and defaults β€” audio output provider, VAD tuning, and handoff workflow. See Configuration.

3. Create the agent

An agent version carries its prompt, model settings, and tools[]. Each tool is a JSON-schema function plus your HTTPS endpoint.

How your tool endpoint is called

Mid-call, the server POSTs to your endpoint with:
  • Authorization passthrough
  • An X-Webhook-Signature HMAC over the raw body β€” the same scheme as webhooks
Your JSON reply becomes the tool result the model sees.
Verify that signature with the same helper you use for webhooks. One implementation covers both β€” see Verifying signatures.

4. Attach a phone number

Route a number to the agent with direction and agent_id. Inbound calls to that number now reach this agent.

5. Register a webhook for call results

Point an endpoint at the events you care about. For a first agent, voice.call.started, voice.call.ended, and voice.session.completed are enough β€” the last one carries persisted transcripts. See the full event catalog.

6. Place a test call

Either call the number, or place an outbound call with POST /make-call.
Faster still: POST /voice/web-calls gives you a browser call with no phone number needed, on the same pipeline. It’s the tightest loop while iterating on a prompt.
Send an Idempotency-Key on make-call β€” 24-hour replay protection means a retried request won’t place a second real call.

7. Inspect the session afterwards

Session records and transcripts are persisted. voice.session.completed delivers them to your webhook, and the session APIs let you fetch them directly.

8. Watch a live call

monitor listens; whisper speaks to the agent only; barge joins the caller; escalate hands to a human; end terminates.

Troubleshooting

Next

SDKs

TypeScript, Python, browser calls.

Configuration

Auth transport, providers, VAD, readiness.

Webhooks

Events and signature verification.

MCP server

Build and tune agents from Claude.