Voice lets you give your AI agent a real phone number. Callers interact with the same agent as on your website — same corpus, same tools, same personality — but through natural speech.
Voice calls use the exact same corpus, segments, system prompt, and tools as the chat widget. There is no separate configuration for voice content — changes to your knowledge base apply to both channels instantly.
Architecture
Phone call
→ Vapi (STT: Deepgram)
→ Animam Custom LLM endpoint (POST /voice/{slug}/chat)
→ SSE stream
→ Vapi (TTS)
→ Phone call
Animam is the brain, not the media stack. Animam acts as a Custom LLM: your voice orchestrator sends conversation turns as OpenAI-format messages, and Animam responds with an SSE stream. The hard real-time work — speech-to-text, text-to-speech, turn-taking, the telephony/SIP signalling — is handled by the voice layer. That separation is deliberate: it lets you choose how much you manage.
Three ways to connect telephony
Pick the level of control you want. All three use the same Animam brain.
Level 1 — Managed (no-code)
Animam creates the Vapi assistant and buys a phone number using the platform’s own Vapi key. Your tenant never touches Vapi.
curl -X POST https://api.animam.ai/tenants/your-slug/voice/setup \
-H "Authorization: Bearer ak_your_token" \
-H "Content-Type: application/json" \
-d '{
"language": "fr",
"voiceId": "aura-luna-fr",
"firstMessage": "Bonjour, comment puis-je vous aider ?",
"buyNumber": true,
"numberAreaCode": "33"
}'
# → { assistantId, phoneNumber, customLlmUrl, serverUrl }
Level 2 — Bring your own Vapi (and your own SIP / carrier)
You run your own Vapi account. Import your SIP trunk or phone numbers there (Vapi supports BYO carriers — Twilio, Telnyx, your own SIP), point the assistant’s Custom LLM URL at https://api.animam.ai/voice/your-slug, then link it to Animam:
curl -X PUT https://api.animam.ai/tenants/your-slug/voice/setup \
-H "Authorization: Bearer ak_your_token" \
-H "Content-Type: application/json" \
-d '{
"assistantId": "your_vapi_assistant_id",
"phoneNumber": "+33123456789",
"language": "fr"
}'
This is the “I manage my own telephony” path: your SIP lives in your Vapi, Animam stays the brain. There is no SIP endpoint to configure on Animam’s side — and there doesn’t need to be.
The Custom LLM endpoint is plain OpenAI-compatible — it isn’t Vapi-specific. Any orchestrator that supports a Custom LLM URL works: Vapi, LiveKit Agents, Pipecat, Retell, Bland, or your own stack. Point its model URL at https://api.animam.ai/voice/your-slug (it calls /chat/completions, SSE), and Animam answers with the same corpus, tools and personality. You own the SIP, the STT/TTS and the latency budget; Animam owns the reasoning.
Tenant Settings
| Field | Type | Description |
|---|
voiceEnabled | boolean | Enable/disable the voice channel |
voiceProvider | string | Always "vapi" for now |
voicePhoneNumber | string | E.164 format phone number |
voiceAssistantId | string | Vapi assistant ID |
voiceConfig | object | Voice behavior (see below) |
voiceConfig Fields
| Field | Type | Description |
|---|
voiceId | string | Vapi/Deepgram voice ID (e.g. "shimmer", "alloy") |
language | string | BCP-47 language code (e.g. "fr-FR", "en-US") |
firstMessage | string | First words spoken when a call connects |
endCallPhrases | string[] | Phrases that trigger call end (e.g. ["au revoir", "merci bonne journée"]) |
maxCallDuration | integer | Maximum call duration in seconds |
Endpoints
POST /voice//chat
Custom LLM endpoint for Vapi. Receives OpenAI-format messages and streams back a response in SSE format. Not intended for direct use — Vapi calls this automatically.
# Example of what Vapi sends:
curl -X POST https://api.animam.ai/voice/your-slug/chat \
-H "Authorization: Bearer ak_your_token" \
-H "Content-Type: application/json" \
-d '{
"messages": [
{ "role": "user", "content": "Bonjour, je voudrais prendre rendez-vous" }
],
"stream": true
}'
POST /voice//events
Webhook endpoint for Vapi events. Handles lifecycle events from Vapi:
| Event | Description |
|---|
assistant-request | Vapi requesting assistant config at call start |
tool-calls | Tool execution during a call (same tools as chat) |
status-update | Call state changes (ringing, in-progress, ended) |
end-of-call-report | Full call summary after hang-up |
Configure this URL in your Vapi dashboard under Assistant > Server URL:
https://api.animam.ai/voice/your-slug/events
GET /voice//recordings/
Download a call recording (if recording is enabled in Vapi).
curl https://api.animam.ai/voice/your-slug/recordings/call_abc123 \
-H "Authorization: Bearer ak_your_token" \
--output call.mp3
All tools configured for your tenant work during voice calls:
- SUBMIT_FORM — Agent collects info verbally, submits the form at end of call
- BOOK_MEETING — Agent checks availability and confirms a booking during the call
- CHECK_AVAILABILITY — Agent reads out available time slots
- ESCALATE_TO_HUMAN — Agent offers to transfer to a human operator
The agent adapts its language for voice — it reads out structured data (dates, prices, addresses) in a natural spoken format rather than displaying formatted text.
Verifying Your Setup
# Check voice is enabled
curl https://api.animam.ai/tenants/your-slug \
-H "Authorization: Bearer ak_your_token" \
| jq '.voiceEnabled, .voicePhoneNumber'
Then call your phone number. The firstMessage should play within 2 seconds of the call connecting.
Limitations
- Managed mode links one phone number per tenant; with your own Vapi/voice platform (Level 2–3) you can route as many numbers as you like
- Animam does not terminate SIP itself — the telephony/media layer is always your voice orchestrator’s responsibility (provisioning, audio quality, latency, fallback)
- Recording storage is managed by Vapi, not Animam
- Voice channel does not support file attachments
COLLECT_PAYMENT (Stripe) is not triggered during voice calls — the agent can describe payment options but cannot generate a checkout link mid-call