Voice API
Build powerful voice applications with programmable calls, text-to-speech, speech recognition, call recording, and interactive IVR systems.
🚀 Quick Start
curl -X POST https://api.afriroute.ai/api/v1/voice/calls \
-H "Authorization: Bearer $AFRIROUTE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"to": "+251911234567",
"from": "+251912000000",
"answer_url": "https://yourapp.com/voice/answer"
}'
📞 Making Calls
Initiate Call
POST /v1/voice/calls
const response = await fetch('https://api.afriroute.ai/api/v1/voice/calls', {
method: 'POST',
headers: {
'Authorization': 'Bearer $AFRIROUTE_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
to: '+251911234567',
from: '+251912000000',
answer_url: 'https://yourapp.com/voice/answer',
event_url: 'https://yourapp.com/voice/events'
})
});
const data = await response.json();
console.log(data.call_id); // call_abc123
🎙️ NCCO (Call Control)
Control calls using Nexus Call Control Objects (JSON instructions).
Text-to-Speech
[
{
"action": "talk",
"text": "Welcome to AfriRoute. Please hold while we connect you.",
"language": "en-US",
"style": 1,
"premium": false
}
]
Play Audio
[
{
"action": "stream",
"streamUrl": ["https://yourapp.com/audio/welcome.mp3"],
"loop": 1
}
]
Connect to Phone
[
{
"action": "connect",
"endpoint": [
{
"type": "phone",
"number": "+251911234567"
}
]
}
]
IVR Menu
app.post('/voice/answer', (req, res) => {
const ncco = [
{
action: 'talk',
text: 'Welcome to customer support. Press 1 for sales, 2 for support, or 3 for billing.'
},
{
action: 'input',
eventUrl: ['https://yourapp.com/voice/dtmf'],
maxDigits: 1,
timeOut: 10
}
];
res.json(ncco);
});
app.post('/voice/dtmf', (req, res) => {
const digit = req.body.dtmf;
const departments = {
'1': { number: '+251911111111', name: 'Sales' },
'2': { number: '+251922222222', name: 'Support' },
'3': { number: '+251933333333', name: 'Billing' }
};
const dept = departments[digit];
if (dept) {
res.json([
{
action: 'talk',
text: `Connecting you to ${dept.name}`
},
{
action: 'connect',
endpoint: [{ type: 'phone', number: dept.number }]
}
]);
} else {
res.json([
{
action: 'talk',
text: 'Invalid selection. Goodbye.'
}
]);
}
});
🎤 Speech Recognition
Convert speech to text in real-time.
[
{
"action": "talk",
"text": "Please say your account number after the beep."
},
{
"action": "input",
"type": ["speech"],
"speech": {
"uuid": ["call_abc123"],
"endOnSilence": 2.0,
"language": "en-US",
"context": ["account", "number", "digits"]
},
"eventUrl": ["https://yourapp.com/voice/speech"]
}
]
app.post('/voice/speech', (req, res) => {
const { speech } = req.body;
if (speech.results && speech.results.length > 0) {
const transcript = speech.results[0].text;
console.log(`User said: ${transcript}`);
res.json([
{
action: 'talk',
text: `You said: ${transcript}. Is that correct?`
}
]);
}
});
📼 Call Recording
[
{
"action": "record",
"eventUrl": ["https://yourapp.com/voice/recording"],
"endOnSilence": 3,
"endOnKey": "#",
"beepStart": true
}
]
📥 Inbound Calls
app.post('/voice/inbound', (req, res) => {
const { from, to, conversation_uuid } = req.body;
console.log(`Inbound call from ${from} to ${to}`);
res.json([
{
action: 'talk',
text: 'Thank you for calling. Your call is important to us.'
},
{
action: 'connect',
endpoint: [
{
type: 'phone',
number: '+251911234567' // Your support line
}
]
}
]);
});
🔔 Webhooks
Call Events
app.post('/voice/events', (req, res) => {
const { status, duration, from, to } = req.body;
console.log(`Call ${status}: ${from} → ${to} (${duration}s)`);
// Update database
await updateCallLog({
status,
duration,
from,
to,
timestamp: new Date()
});
res.sendStatus(200);
});
Event Types
| Event | Description |
|---|---|
started | Call initiated |
ringing | Phone is ringing |
answered | Call answered |
completed | Call ended normally |
failed | Call failed |
rejected | Call rejected by recipient |
busy | Recipient busy |
timeout | No answer |
📞 Advanced IVR
Multi-Level Menu
function buildMainMenu() {
return [
{
action: 'talk',
text: 'Main menu. Press 1 for account information, 2 for technical support, or 0 for operator.'
},
{
action: 'input',
eventUrl: ['https://yourapp.com/voice/main-menu'],
maxDigits: 1
}
];
}
function buildAccountMenu() {
return [
{
action: 'talk',
text: 'Account menu. Press 1 for balance, 2 for recent transactions, or 9 to go back.'
},
{
action: 'input',
eventUrl: ['https://yourapp.com/voice/account-menu'],
maxDigits: 1
}
];
}
Call Queuing
[
{
"action": "talk",
"text": "All agents are currently busy. You are number 3 in the queue."
},
{
"action": "stream",
"streamUrl": ["https://yourapp.com/audio/hold-music.mp3"],
"loop": 0
}
]
🌍 Available Languages
Text-to-Speech: 40+ languages and accents
- English (US, UK, AU, IN, etc.)
- French, Portuguese, Arabic, Swahili
- Amharic (Ethiopia), Hausa (Nigeria), Yoruba
- View all languages →
Speech Recognition: 20+ languages
- English, French, Portuguese, Arabic
- Swahili, Amharic, Yoruba, Zulu
💡 Best Practices
IVR Design
- Keep menus simple - max 5 options per level
- Repeat options - add "Press 9 to hear options again"
- Provide escape hatch - "Press 0 for operator" on every menu
- Use familiar patterns - 1-9 for options, 0 for operator, * to go back
Voice Quality
- Use premium TTS voices for professional sound
- Optimize audio files - 8kHz mono WAV or 16kbps MP3
- Test on real phones - sound quality varies by carrier
- Implement fallbacks - if speech recognition fails, use DTMF
Performance
- Cache NCCO responses for static menus
- Use webhooks for events - track all call states
- Implement timeouts - 10s for input, 30s for speech
- Log all interactions for debugging and analytics
User Experience
- Speak clearly and slowly in TTS
- Provide progress updates - "Please hold while we look that up"
- Confirm actions - "Press 1 to confirm, 2 to cancel"
- Offer callback option - save waiting time
💰 Pricing
| Type | Price/Minute | Notes |
|---|---|---|
| Outbound (Local) | $0.05 | Within same country |
| Outbound (International) | $0.15 | Cross-border |
| Inbound | $0.02 | Receive calls |
| TTS (Standard) | $0.01 | Basic voices |
| TTS (Premium) | $0.03 | Neural voices |
| Recording | $0.005 | Per minute recorded |
📊 Call Analytics
Track performance in dashboard:
- ✅ Answer rate
- ⏱️ Average call duration
- 🔄 Call outcomes (completed, failed, busy)
- 📈 Peak hours analysis
- 💬 Menu selections
🛠️ SDKs
// JavaScript
const afriroute = require('@afriroute/sdk');
const voice = new afriroute.Voice('$AFRIROUTE_API_KEY');
const call = await voice.createCall({
to: '+251911234567',
from: '+251912000000',
answerUrl: 'https://yourapp.com/voice/answer'
});
# Python
from afriroute import Voice
voice = Voice(api_key='$AFRIROUTE_API_KEY')
call = voice.create_call(
to='+251911234567',
from_='+251912000000',
answer_url='https://yourapp.com/voice/answer'
)
📚 Related Resources
- IVR Design Best Practices
- Call Center Setup Tutorial
- Speech Recognition Guide
- Call Recording & Compliance
Need help? Contact Support → | View Code Examples →