Telephony primitives via simple HTTP APIs.
VAD, conferencing, call control, DTMF - the building blocks for voice applications.
Telephony primitives. Simple APIs. No hidden complexity.
No DSL - just REST endpoints
Your code, your rules
Bring any carrier, any AI, any stack
MonkeyDial gives you the primitives: inbound/outbound calls, voice activity detection, conferencing, DTMF, and call control.
Compose them into AI voice agents, call centers, dynamic routing, warm transfers - whatever your application needs.
We handle the hard telephony stuff. You build your app logic with simple HTTP APIs.
Call control, audio webhooks (WAV segments), VAD modes, and conference bridges
POST /v1/dial
Authorization: Bearer YOUR_API_KEY
{
"to": "+13105551234",
"from": "+17025559999",
"amd_enabled": true,
"amd_timeout": 10
}
{
"success": true,
"message": "Call initiated successfully",
"call_uuid": "86fd19ef-d17d-482f-bbda-65287272ac22",
"details": {
"to_number": "+13105551234",
"from_did": "+17025559999",
"customer_slug": "your-company-abc123"
},
"response_time_ms": 154
}
When AMD is enabled, webhook events will be sent to your DID's configured webhook URL with early and final detection results.
GET /v1/calls
Authorization: Bearer YOUR_API_KEY
{
"success": true,
"count": 1,
"calls": [
{
"call_id": "bc1473dd-73b9-42c6-8a88-11518ff615c6",
"status": "active",
"direction": "outbound",
"caller_id": "17029860828",
"caller_name": "unknown",
"did": "+17029860828",
"started_at": "2025-11-05 17:00:28"
}
]
}
GET /v1/call/{call_uuid}
Authorization: Bearer YOUR_API_KEY
{
"success": true,
"call_id": "bc1473dd-73b9-42c6-8a88-11518ff615c6",
"status": "completed",
"direction": "outbound",
"caller_id": "17029860828",
"caller_name": "unknown",
"did": "+17029860828",
"initiated_at": "2025-11-05 17:00:28",
"hangup_at": "2025-11-05 17:00:30",
"duration": 2
}
POST /v1/call/{call_uuid}/hangup
Authorization: Bearer YOUR_API_KEY
{
"success": true,
"message": "Hangup request sent",
"call_uuid": "86fd19ef-d17d-482f-bbda-65287272ac22"
}
POST /v1/pre-answer/{call_uuid}
Authorization: Bearer YOUR_API_KEY
{
"action": "answer"
}
{
"success": true,
"message": "Pre-answer action set to answer",
"call_uuid": "86fd19ef-d17d-482f-bbda-65287272ac22",
"action": "answer"
}
action: "answer" (accept call) or "reject" (hang up without answering). Used during pre-answer webhook timeout window to control call before it's answered. Only effective for inbound calls with pre-answer screening enabled.
POST /v1/calls/join
Authorization: Bearer YOUR_API_KEY
{
"call_ids": [
"call_550e8400-e29b-41d4-a716-446655440000",
"call_550e8401-e29c-41d4-a716-446655440001"
]
}
{
"success": true,
"message": "Bridge established",
"bridge_type": "same-server",
"response_time_ms": 45
}
Connect two active calls. Works across servers automatically. Both calls must be active.
POST /v1/calls/unjoin
Authorization: Bearer YOUR_API_KEY
{
"call_ids": [
"call_550e8400-e29b-41d4-a716-446655440000",
"call_550e8401-e29c-41d4-a716-446655440001"
]
}
{
"success": true,
"message": "Cross-server unjoin complete",
"unjoin_type": "cross-server",
"call1": {
"unjoined": true,
"status": "active"
},
"call2": {
"unjoined": true,
"status": "active"
},
"response_time_ms": 78
}
Disconnect two bridged calls and return them to AudioSocket. Both calls must be active.
curl -X POST https://api.monkeydial.com/v1/call/{call_uuid}/record/start \
-H "X-API-Key: YOUR_API_KEY"
const response = await fetch(
`https://api.monkeydial.com/v1/call/${callUuid}/record/start`,
{
method: 'POST',
headers: { 'X-API-Key': 'YOUR_API_KEY' }
}
);
const data = await response.json();
import requests
response = requests.post(
f"https://api.monkeydial.com/v1/call/{call_uuid}/record/start",
headers={"X-API-Key": "YOUR_API_KEY"}
)
data = response.json()
{
"success": true,
"recording_id": "call_rec_550e8400_2511071430_1",
"call_uuid": "550e8400-e29b-41d4-a716-446655440000",
"status": "recording",
"hub_server": "audiobot-asterisk-1"
}
Starts recording an active call. Multiple recordings can be started per call (sequence numbers: _1, _2, _3). Recording captures both sides (caller + system audio) mixed into a single MP3 file. Recording automatically stops when call ends.
curl -X POST https://api.monkeydial.com/v1/call/{call_uuid}/record/stop \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"recording_id": "call_rec_550e8400_2511071430_1"}'
const response = await fetch(
`https://api.monkeydial.com/v1/call/${callUuid}/record/stop`,
{
method: 'POST',
headers: {
'X-API-Key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
recording_id: 'call_rec_550e8400_2511071430_1' // Optional
})
}
);
const data = await response.json();
import requests
response = requests.post(
f"https://api.monkeydial.com/v1/call/{call_uuid}/record/stop",
headers={"X-API-Key": "YOUR_API_KEY"},
json={"recording_id": "call_rec_550e8400_2511071430_1"} # Optional
)
data = response.json()
{
"success": true,
"recording_id": "call_rec_550e8400_2511071430_1",
"status": "processing"
}
Stops active recording and triggers MP3 conversion. If recording_id is not provided, stops the most recent recording. Processing typically completes within 1-2 seconds. Webhook "call_recording_ready" is sent when MP3 is available.
curl -X GET https://api.monkeydial.com/v1/call/recording/{recording_id} \
-H "X-API-Key: YOUR_API_KEY" \
-o recording.mp3
const response = await fetch(
`https://api.monkeydial.com/v1/call/recording/${recordingId}`,
{ headers: { 'X-API-Key': 'YOUR_API_KEY' } }
);
const arrayBuffer = await response.arrayBuffer();
const buffer = Buffer.from(arrayBuffer);
fs.writeFileSync('recording.mp3', buffer);
import requests
response = requests.get(
f"https://api.monkeydial.com/v1/call/recording/{recording_id}",
headers={"X-API-Key": "YOUR_API_KEY"}
)
with open('recording.mp3', 'wb') as f:
f.write(response.content)
Content-Type: audio/mpeg
Content-Disposition: attachment; filename="{recording_id}.mp3"
Content-Length: 1480000
Downloads MP3 recording file. Only available when status is "ready" (check webhook or poll status). Returns 404 if recording is still processing or not found.
{
"event": "call_recording_ready",
"call_uuid": "550e8400-e29b-41d4-a716-446655440000",
"recording_id": "call_rec_550e8400_2511071430_1",
"customer_id": "acme-corp",
"duration_seconds": 185,
"file_size_bytes": 1480000,
"format": "mp3",
"download_url": "https://api.monkeydial.com/v1/call/recording/call_rec_550e8400_2511071430_1",
"started_at": "2025-11-07T14:30:00Z",
"stopped_at": "2025-11-07T14:33:05Z"
}
Sent when MP3 conversion completes and file is ready for download. Triggered after manual stop or automatic stop on call hangup.
{
"event": "call_start",
"call_id": "86fd19ef-d17d-482f-bbda-65287272ac22",
"customer_id": "acme-corp-x7k2mn",
"did": "+17029860828",
"caller_id": "+13105551234",
"caller_name": "John Doe",
"direction": "inbound",
"timestamp": "2025-11-05T19:14:06+00:00"
}
{
"event": "call_end",
"call_uuid": "86fd19ef-d17d-482f-bbda-65287272ac22",
"customer_id": "acme-corp-001",
"did": "+17029860828",
"caller_id": "+13105551234",
"caller_name": "John Doe",
"status": "completed",
"error_reason": null,
"duration": 120,
"timestamp": "2025-11-05T10:32:00+00:00"
}
status: "completed" or "failed" | duration: total call duration in seconds
{
"event": "call_pre_answer",
"timestamp": "2025-11-10T04:28:56Z",
"call_uuid": "4ea15232-5384-41dd-9291-805f18995211",
"customer_slug": "acme-corp-x7k2mn",
"did": "+17029860828",
"caller_id": "+14073461117",
"caller_name": "John Doe",
"direction": "inbound"
}
Fired before answering inbound calls when pre-answer screening is enabled. Gives you a configurable timeout window (1-60 seconds) to decide whether to accept or reject the call. Use POST /v1/pre-answer/{call_uuid} with {"action": "answer"} or {"action": "reject"} to control the call. If no action is taken within the timeout, the configured default action (answer or reject) is applied. Perfect for spam filtering, business hours validation, or caller screening.
POST /v1/vad/{call_uuid}/playback_audio
Authorization: Bearer YOUR_API_KEY
Content-Type: multipart/form-data
audio_file: [binary audio file]
{
"success": true,
"message": "Audio routed successfully",
"call_uuid": "call_550e8400-e29b..."
}
Upload audio file - queues multiple files. Supports WAV, MP3, μ-law.
POST /v1/vad/{call_uuid}/playback_audio/replace
Authorization: Bearer YOUR_API_KEY
Content-Type: multipart/form-data
audio_file: [binary audio file]
{
"success": true,
"message": "Audio routed successfully",
"call_uuid": "call_550e8400-e29b..."
}
Stops current playback and plays immediately.
POST /v1/vad/{call_uuid}/playback_audio/stop
Authorization: Bearer YOUR_API_KEY
{
"success": true,
"message": "Playback stopped",
"call_uuid": "call_550e8400..."
}
Stops current playback and clears queue.
POST /v1/vad/{call_uuid}/vad_mode
Authorization: Bearer YOUR_API_KEY
{
"vad_mode": "block"
}
DTMF detection works in all VAD modes. VAD automatically switches to mode 2 (blocked) during playback to prevent echo.
POST /v1/vad/{call_uuid}/record
Authorization: Bearer YOUR_API_KEY
{
"duration": 30
}
{
"success": true,
"message": "Recording started",
"uuid": "call_550e8400...",
"duration": 30
}
Record 1-60 seconds. Webhook sent when complete.
POST https://your-app.com/webhook
Content-Type: application/json
{
"event": "audio",
"call_id": "call_550e8400-e29b...",
"audio_url": "https://storage.md.com/seg_001.wav",
"duration_ms": 1500,
"caller_id": "+13105551234",
"did": "+17025559999"
}
Audio segments delivered in real-time as VAD detects speech. WAV format, 8kHz-48kHz.
{
"event": "dtmf",
"uuid": "86fd19ef-d17d-482f-bbda-65287272ac22",
"digit": "1",
"customer_id": "acme-corp-001",
"did": "+17029860828",
"caller_id": "+13105551234",
"timestamp": "2025-11-05T10:31:30+00:00"
}
Supports digits 0-9, *, #, A-D
event: recording
uuid: 86fd19ef-d17d-482f-bbda-65287272ac22
customer_id: acme-corp-001
did: +17029860828
duration: 5
actual_duration: 5.2
partial: false
audio_data: [WAV file - 8kHz, 16-bit, mono]
Sent when timed recording completes. Contains full audio as WAV.
POST /v1/conference/create
Authorization: Bearer YOUR_API_KEY
{
"name": "support-call-123",
"webhook_url": "https://yourdomain.com/webhooks/conference"
}
{
"success": true,
"conference_id": "conf_550e8400-e29b-41d4-a716-446655440000",
"name": "support-call-123",
"created_at": "2025-11-06T21:27:56+00:00"
}
POST /v1/conference/{conf_id}/join
Authorization: Bearer YOUR_API_KEY
{
"call_ids": ["call_550e8400-e29b...", "call_abc123..."]
}
{
"success": true,
"conference_id": "conf_550e8400-e29b-41d4-a716-446655440000",
"joined": [
{"call_id": "call_550e8400-e29b...", "status": "joined"}
],
"failed": [],
"participant_count": 2
}
GET /v1/conference/{conf_id}/list
Authorization: Bearer YOUR_API_KEY
{
"success": true,
"conference": {
"conference_id": "conf_550e8400-e29b...",
"name": "Sales Call",
"status": "active",
"created_at": "2025-11-06T21:27:56Z",
"max_participants": 10,
"participant_count": 2,
"hub": "audiobot-asterisk-2"
},
"participants": [
{
"call_uuid": "call_abc123",
"caller_id": "+13105551234",
"did": "+17025559999",
"joined_at": "2025-11-06T21:28:15Z",
"duration_in_conference": 145,
"is_muted": false
}
]
}
Get conference metadata and real-time participant list with join times and durations. Perfect for dashboards.
POST /v1/conference/{conf_id}/leave/{call_uuid}
Authorization: Bearer YOUR_API_KEY
{
"post_conference_action": "VAD"
}
{
"success": true,
"message": "Participant redirected to VAD",
"call_id": "call_550e8400-e29b-41d4-a716-446655440000",
"conference_id": "conf_550e8400-e29b-41d4-a716-446655440000",
"action": "VAD"
}
Remove a single participant from conference. Choose whether to return to VAD mode or hang up.
POST /v1/conference/{conf_id}/kick/{call_uuid}
Authorization: Bearer YOUR_API_KEY
{
"success": true,
"message": "Participant kicked from conference",
"call_id": "call_550e8400-e29b-41d4-a716-446655440000",
"conference_id": "conf_550e8400-e29b-41d4-a716-446655440000"
}
Forcibly remove and hang up a participant. Use /leave to return to VAD instead.
POST /v1/conference/{conf_id}/record/start
Headers: x-api-key: YOUR_API_KEY
Response:
{
"success": true,
"conference_id": "conf_550e8400-e29b-41d4-a716-446655440000",
"recording_id": "conf_rec_a1b2c3d4_2511071030",
"status": "recording",
"hub_server": "audiobot-asterisk-2"
}
Start recording conference audio. Only one recording per conference at a time. Supports multiple segments (stop/start creates separate files). MP3 format, ~190kbps VBR.
POST /v1/conference/{conf_id}/record/stop
Headers: x-api-key: YOUR_API_KEY
Response:
{
"success": true,
"recording_id": "conf_rec_a1b2c3d4_2511071030",
"conference_id": "conf_550e8400-e29b-41d4-a716-446655440000",
"status": "ready",
"file_size_bytes": 1810000,
"duration_seconds": 1205,
"format": "mp3"
}
Stop recording and convert WAV to MP3. Triggers conference_recording_ready webhook. File available for download immediately.
GET /v1/conference/recording/{recording_id}
Headers: x-api-key: YOUR_API_KEY
Response:
Content-Type: audio/mpeg
Content-Disposition: attachment; filename="conf_rec_a1b2c3d4_2511071030.mp3"
[Binary MP3 data]
Download conference recording MP3 file. Customer-isolated access. Supports Range requests for partial downloads.
POST /v1/conference/{conf_id}/play
Headers: x-api-key: YOUR_API_KEY
Content-Type: multipart/form-data
Body:
file: [audio file - MP3, WAV, OGG, M4A]
Response:
{
"success": true,
"playback_id": "conf_playback_690e6ea1261050_72120897",
"conference_id": "conf_abc123",
"duration_seconds": 29.57
}
Play audio file into active conference. All participants hear the audio. Supports MP3, WAV, OGG, M4A formats. Auto-converts to Asterisk format (16kHz mono). Temporary channel joins conference, plays audio, then leaves.
{
"event": "conference_created",
"conference_id": "conf_550e8400-e29b-41d4-a716-446655440000",
"name": "support-call-123",
"customer_id": "acme-corp-x7k2mn",
"max_participants": 10,
"created_at": "2025-11-06T21:27:56+00:00"
}
Sent when a new conference room is created.
{
"event": "conference_participant_joined",
"conference_id": "conf_550e8400-e29b-41d4-a716-446655440000",
"call_id": "call_abc123",
"caller_id": "+13105551234",
"participant_count": 2,
"timestamp": "2025-11-06T21:28:15+00:00"
}
Sent when a participant joins the conference.
{
"event": "conference_participant_left",
"conference_id": "conf_550e8400-e29b-41d4-a716-446655440000",
"call_id": "call_abc123",
"reason": "left",
"duration_in_conference": 295,
"participant_count": 1,
"timestamp": "2025-11-06T21:33:10+00:00"
}
Sent when a participant leaves the conference. Includes reason and duration.
{
"event": "conference_ended",
"conference_id": "conf_550e8400-e29b-41d4-a716-446655440000",
"reason": "deleted",
"duration": 610,
"total_participants": 3,
"timestamp": "2025-11-06T21:38:06+00:00"
}
Sent when conference is deleted or ends. Includes total duration and participant count.
{
"event": "conference_recording_ready",
"conference_id": "conf_550e8400-e29b-41d4-a716-446655440000",
"recording_id": "conf_rec_a1b2c3d4_2511071030",
"customer_id": "acme-corp-x7k2mn",
"duration_seconds": 1205,
"file_size_bytes": 1810000,
"format": "mp3",
"download_url": "https://api.monkeydial.com/v1/conference/recording/conf_rec_a1b2c3d4_2511071030",
"started_at": "2025-11-07T10:30:00Z",
"stopped_at": "2025-11-07T10:50:05Z"
}
Sent after recording is stopped and MP3 conversion completes. File ready for download. Use for archival, transcription, or analytics.
Answering Machine Detection (AMD) uses AI-powered speech recognition to distinguish between human answers and voicemail/IVR systems. Enable via the amd_enabled parameter on /dial.
{
"event": "amd_result",
"call_uuid": "86fd19ef-d17d-482f-bbda-65287272ac22",
"customer_id": "acme-corp-x7k2mn",
"did": "+17025559999",
"caller_id": "+13105551234",
"amd": {
"label": "human",
"confidence": 0.92,
"transcript": "Hello?",
"elapsed_ms": 1850,
"type": "early"
},
"timestamp": 1764571986
}
Sent immediately after initial speech is detected (~2 seconds). Use for fast routing decisions. May be less accurate than final result.
{
"event": "amd_result",
"call_uuid": "86fd19ef-d17d-482f-bbda-65287272ac22",
"customer_id": "acme-corp-x7k2mn",
"did": "+17025559999",
"caller_id": "+13105551234",
"amd": {
"label": "machine",
"confidence": 0.98,
"transcript": "Hi, you've reached John. Please leave a message after the beep.",
"elapsed_ms": 4250,
"type": "final"
},
"timestamp": 1764571988
}
Sent after complete audio analysis. Higher accuracy than early detection. Use for logging, analytics, or confirming early detection decisions.
Inbound + Outbound + VAD + Conference + DTMF = Endless possibilities
Works with any SIP carrier that supports URI routing with IP auth or SIP credentials
No migration. No downtime. No risk.