Kaphila API Documentation
Complete reference with multi-language examples in Python, Node.js, PHP, Java, C#, and cURL.
Authentication
All API requests must include an Authorization
header with your API key.
Header
Authorization: Bearer ak_your_api_key_here
Get Your API Key
- Log in to your Dashboard
- Click "Generate Key"
- Copy the key and use it in your requests
Make a Call — POST /makecall
Initiate an outbound call to a phone number.
Important:
- Phone numbers must be in 10-15 digit format WITHOUT the
+
prefix (e.g.,16089270862
). callerId
must be a verified/whitelisted number from your account. Invalid or unverified numbers will be ignored or cause failure.
Request Body
{ "number": "16089270862", "webhookUrl": "https://your-server.com/webhook", "useAmd": true, "callerId": "19876543210", // Must be whitelisted "voiceName": "en-US-Neural2-A", "ringTimeout": 30 }
Response
{ "success": true, "callId": "1758549398.181", "status": "ringing", "amdEnabled": true, "voiceName": "en-US-Neural2-A", "credits": 10, "ringTimeoutSeconds": 30, "timestamp": "2025-09-22T13:56:38.365Z" }
Forward a Call — POST /forwardcall
Forward an active call to another number.
Request Body
{ "callId": "1758549398.181", "forwardNumber": "19876543210" }
Response
{ "success": true, "message": "Call forwarded to 19876543210", "forwardedCallId": "1758549447.186" }
Text-to-Speech — POST /voice
Play synthesized speech to a call.
Request Body
{ "callId": "1758549398.181", "text": "Hello, this is a test message.", "playTo": "bridge" }
Response
{ "success": true, "message": "TTS played successfully", "playbackId": "tts-1758549398.181-123456" }
Gather DTMF — POST /gather
Prompt user for DTMF input.
Request Body
{ "callId": "1758549398.181", "text": "Press 1 for sales, 2 for support.", "numDigits": 1, "timeout": 10000 }
Webhook Events
gather.started
gather.progress
gather.complete
gather.timeout
Webhooks
Receive real-time events about your calls.
Events
call.initiated
call.answered
call.ended
call.timeout
dtmf.received
gather.*
recording.*
Example Webhook Payload
{ "callId": "1758549398.181", "event": "call.answered", "status": "answered", "amd": { "status": "HUMAN", "confidence": 0.9 }, "timestamp": "2025-09-20T19:44:29Z" }
Code Examples — Make a Call
Examples in multiple languages. Replace ak_your_api_key_here
and URLs with your own.
curl -X POST "https://kaphila.com/makecall" \ -H "Authorization: Bearer ak_your_api_key_here" \ -H "Content-Type: application/json" \ -d '{ "number": "16089270862", "callerId": "19876543210", // Must be whitelisted "webhookUrl": "https://kaphila.com/call-handler", "useAmd": true, "voiceName": "en-US-Neural2-A", "ringTimeout": 30 }'
import requests API_KEY = "ak_your_api_key_here" BASE_URL = "https://kaphila.com" headers = { "Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json" } data = { "number": "16089270862", # No '+' prefix "callerId": "19876543210", # Must be whitelisted "webhookUrl": "https://kaphila.com/call-handler", "useAmd": True, "voiceName": "en-US-Neural2-A", "ringTimeout": 30 } response = requests.post(f"{BASE_URL}/makecall", json=data, headers=headers) print(response.json())
const axios = require('axios'); const API_KEY = 'ak_your_api_key_here'; const BASE_URL = 'https://kaphila.com'; const data = { number: '16089270862', callerId: '19876543210', // Must be whitelisted webhookUrl: 'https://kaphila.com/call-handler', useAmd: true, voiceName: 'en-US-Neural2-A', ringTimeout: 30 }; axios.post(`${BASE_URL}/makecall`, data, { headers: { 'Authorization': `Bearer ${API_KEY}`, 'Content-Type': 'application/json' } }) .then(response => console.log(response.data)) .catch(error => console.error(error));
'16089270862', 'callerId' => '19876543210', // Must be whitelisted 'webhookUrl' => 'https://kaphila.com/call-handler', 'useAmd' => true, 'voiceName' => 'en-US-Neural2-A', 'ringTimeout' => 30 ]; $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Authorization: Bearer ' . $apiKey, 'Content-Type: application/json' ]); $response = curl_exec($ch); curl_close($ch); echo $response; ?>
import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.nio.charset.StandardCharsets; public class MakeCall { public static void main(String[] args) throws Exception { String apiKey = "ak_your_api_key_here"; String url = "https://kaphila.com/makecall"; String json = """ { "number": "16089270862", "callerId": "19876543210", // Must be whitelisted "webhookUrl": "https://kaphila.com/call-handler", "useAmd": true, "voiceName": "en-US-Neural2-A", "ringTimeout": 30 } """; HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(url)) .header("Authorization", "Bearer " + apiKey) .header("Content-Type", "application/json") .POST(HttpRequest.BodyPublishers.ofString(json, StandardCharsets.UTF_8)) .build(); HttpClient client = HttpClient.newHttpClient(); HttpResponseresponse = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.body()); } }
using System; using System.Net.Http; using System.Text; using System.Threading.Tasks; using Newtonsoft.Json; public class CallRequest { public string number { get; set; } public string callerId { get; set; } // Must be whitelisted public string webhookUrl { get; set; } public bool useAmd { get; set; } public string voiceName { get; set; } public int ringTimeout { get; set; } } public class Program { public static async Task Main() { var client = new HttpClient(); client.DefaultRequestHeaders.Add("Authorization", "Bearer ak_your_api_key_here"); var request = new CallRequest { number = "16089270862", callerId = "19876543210", // Must be whitelisted webhookUrl = "https://kaphila.com/call-handler", useAmd = true, voiceName = "en-US-Neural2-A", ringTimeout = 30 }; var json = JsonConvert.SerializeObject(request); var content = new StringContent(json, Encoding.UTF8, "application/json"); var response = await client.PostAsync("https://kaphila.com/makecall", content); var result = await response.Content.ReadAsStringAsync(); Console.WriteLine(result); } }
IVR Demos — Interactive Voice Response
Combine /voice
and /gather
to build powerful IVR menus. Below are complete, real-world examples.
All IVR flows start with a call initiated via
/makecall
. After the call is answered, use /voice
to speak and /gather
to collect input.
1. “Press 1 for Sales, 2 for Support”
Play prompt → Gather 1 digit → Route based on input.
# Step 1: Play prompt curl -X POST "https://kaphila.com/voice" \ -H "Authorization: Bearer ak_your_api_key_here" \ -H "Content-Type: application/json" \ -d '{ "callId": "1758549398.181", "text": "Welcome to our company. Press 1 for Sales, 2 for Support.", "playTo": "bridge" }' # Step 2: Gather input curl -X POST "https://kaphila.com/gather" \ -H "Authorization: Bearer ak_your_api_key_here" \ -H "Content-Type: application/json" \ -d '{ "callId": "1758549398.181", "numDigits": 1, "timeout": 10000 }'
import requests API_KEY = "ak_your_api_key_here" BASE_URL = "https://kaphila.com" CALL_ID = "1758549398.181" headers = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"} # Step 1: Speak menu requests.post(f"{BASE_URL}/voice", json={ "callId": CALL_ID, "text": "Welcome to our company. Press 1 for Sales, 2 for Support.", "playTo": "bridge" }, headers=headers) # Step 2: Gather input response = requests.post(f"{BASE_URL}/gather", json={ "callId": CALL_ID, "numDigits": 1, "timeout": 10000 }, headers=headers) print("Gather started:", response.json())
const axios = require('axios'); const API_KEY = 'ak_your_api_key_here'; const BASE_URL = 'https://kaphila.com'; const CALL_ID = '1758549398.181'; const headers = { 'Authorization': `Bearer ${API_KEY}`, 'Content-Type': 'application/json' }; // Step 1: Speak menu await axios.post(`${BASE_URL}/voice`, { callId: CALL_ID, text: "Welcome to our company. Press 1 for Sales, 2 for Support.", playTo: "bridge" }, { headers }); // Step 2: Gather input const res = await axios.post(`${BASE_URL}/gather`, { callId: CALL_ID, numDigits: 1, timeout: 10000 }, { headers }); console.log("Gather started:", res.data);
Expected Webhook Events
{ "event": "gather.complete", "callId": "1758549398.181", "digits": "1", "timestamp": "2025-09-22T14:30:00Z" }
💡 Logic Tip: On your webhook server, check
digits
:
if digits == "1"
→ Transfer to salesif digits == "2"
→ Transfer to supportelse
→ Replay menu or say “Invalid option”
2. “Please enter your 6-digit PIN code”
Useful for authentication or account access.
curl -X POST "https://kaphila.com/voice" \ -H "Authorization: Bearer ak_your_api_key_here" \ -d '{ "callId": "1758549398.181", "text": "Please enter your 6-digit PIN code, followed by the pound key.", "playTo": "bridge" }' curl -X POST "https://kaphila.com/gather" \ -H "Authorization: Bearer ak_your_api_key_here" \ -d '{ "callId": "1758549398.181", "numDigits": 6, "finishOnKey": "#", "timeout": 15000 }'
requests.post(f"{BASE_URL}/voice", json={ "callId": CALL_ID, "text": "Please enter your 6-digit PIN code, followed by the pound key.", "playTo": "bridge" }, headers=headers) requests.post(f"{BASE_URL}/gather", json={ "callId": CALL_ID, "numDigits": 6, "finishOnKey": "#", "timeout": 15000 }, headers=headers)
Webhook Payload on Success
{ "event": "gather.complete", "callId": "1758549398.181", "digits": "123456", "timestamp": "2025-09-22T14:31:00Z" }
3. “Say YES to confirm, NO to cancel”
Use speech recognition (if supported) or map keypad: YES=1, NO=2.
curl -X POST "https://kaphila.com/voice" \ -H "Authorization: Bearer ak_your_api_key_here" \ -d '{ "callId": "1758549398.181", "text": "To confirm your appointment, press 1. To cancel, press 2.", "playTo": "bridge" }' curl -X POST "https://kaphila.com/gather" \ -H "Authorization: Bearer ak_your_api_key_here" \ -d '{ "callId": "1758549398.181", "numDigits": 1, "validDigits": "12", "timeout": 10000 }'
Handle in Webhook
// Pseudo-code for your webhook endpoint if (event === 'gather.complete') { if (digits === '1') { playTTS("Confirmed! Thank you."); // Trigger business logic: send email, update DB, etc. } else if (digits === '2') { playTTS("Cancelled. Goodbye."); hangupCall(); } else { playTTS("Invalid input. Goodbye."); hangupCall(); } }
Pro Tip: Chain multiple
/voice
and /gather
calls to build complex IVR trees. Always handle gather.timeout
and gather.failed
events for fallbacks.