curl --request POST \
--url https://api.example.com/api/v1/voice/webhook \
--header 'Content-Type: application/json' \
--data '
{
"sessionId": "<string>",
"phoneNumber": "<string>",
"recordingUrl": "<string>",
"duration": 123,
"status": "<string>"
}
'{
"status": "<string>",
"session_id": "<string>",
"error": "<string>"
}Webhook endpoint to receive call status updates and recording URLs from Africa’s Talking
curl --request POST \
--url https://api.example.com/api/v1/voice/webhook \
--header 'Content-Type: application/json' \
--data '
{
"sessionId": "<string>",
"phoneNumber": "<string>",
"recordingUrl": "<string>",
"duration": 123,
"status": "<string>"
}
'{
"status": "<string>",
"session_id": "<string>",
"error": "<string>"
}https://api.voicepact.com/api/v1/voice/webhookcompleted, failed, busy, no-answerPOST /api/v1/voice/webhook HTTP/1.1
Host: api.voicepact.com
Content-Type: application/x-www-form-urlencoded
sessionId=ATVoice_a1b2c3d4e5f6&phoneNumber=%2B254712345678&recordingUrl=https%3A%2F%2Fvoice.africastalking.com%2Frecordings%2Fa1b2c3d4e5f6.mp3&duration=420&status=completed
{
"sessionId": "ATVoice_a1b2c3d4e5f6",
"phoneNumber": "+254712345678",
"recordingUrl": "https://voice.africastalking.com/recordings/a1b2c3d4e5f6.mp3",
"duration": 420,
"status": "completed"
}
POST /api/v1/voice/webhook HTTP/1.1
Host: api.voicepact.com
Content-Type: application/x-www-form-urlencoded
sessionId=ATVoice_x9y8z7w6v5u4&phoneNumber=%2B254787654321&status=no-answer
{
"sessionId": "ATVoice_x9y8z7w6v5u4",
"phoneNumber": "+254787654321",
"status": "no-answer"
}
webhook_processed or webhook_errorwebhook_error){
"status": "webhook_processed",
"session_id": "ATVoice_a1b2c3d4e5f6"
}
{
"status": "webhook_error",
"error": "Database connection timeout"
}
| Status | Description | Recording Available |
|---|---|---|
completed | Call successfully completed | Yes |
failed | Call failed due to technical error | No |
busy | Called party was busy | No |
no-answer | Called party didn’t answer | No |
rejected | Called party rejected the call | No |
VoiceRecording table:
recording_url: Set to the provided recording URLduration: Set to call duration in secondsprocessing_status: Set to the call statusprocessed_at: Set to current timestampcurl -X GET https://api.voicepact.com/api/v1/voice/recordings/ATVoice_a1b2c3d4e5f6 \
-H "Authorization: Bearer YOUR_API_KEY"
{
"recording_id": "ATVoice_a1b2c3d4e5f6",
"status": "completed",
"duration": 420,
"recording_url": "https://voice.africastalking.com/recordings/a1b2c3d4e5f6.mp3",
"created_at": "2026-03-06T14:00:00Z",
"processed_at": "2026-03-06T14:07:00Z"
}
52.47.190.2203.127.102.70import hmac
import hashlib
def verify_webhook(payload, signature, secret):
expected = hmac.new(
secret.encode(),
payload.encode(),
hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, signature)
# Start ngrok tunnel
ngrok http 8000
# Use the ngrok URL in Africa's Talking dashboard
https://abc123.ngrok.io/api/v1/voice/webhook
curl -X POST http://localhost:8000/api/v1/voice/webhook \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "sessionId=test_session_123&phoneNumber=%2B254712345678&recordingUrl=https%3A%2F%2Fexample.com%2Ftest.mp3&duration=300&status=completed"