Call Control API

Programmatically control active calls — play TTS, transfer, hang up, and more.

The Call Control API provides programmatic control over active calls. Use it to play TTS, hang up, transfer calls, send DTMF, or put calls on hold — all via RESTful HTTP/JSON endpoints. This is the imperative counterpart to the declarative dialog FSM.

Base URL

All endpoints are relative to your voicetyped host:

https://gateway.example.com/v1/calls/{id}/...

Replace {id} with the active call session ID. All request and response bodies use JSON with Content-Type: application/json.

Authentication

Include your API token in the Authorization header:

Authorization: Bearer <token>

Endpoints

Play TTS

Render text to speech and play it on an active call.

POST /v1/calls/{id}/tts

Request body:

FieldTypeRequiredDescription
textstringyesText to speak
voicestringnoVoice model (default: server-configured)
speedfloatnoPlayback speed (default 1.0)
barge_inbooleannoAllow caller to interrupt (default true)

Response body:

FieldTypeDescription
playback_idstringID to track this playback
estimated_duration_msintegerEstimated playback duration in milliseconds

Example:

curl -X POST https://gateway.example.com/v1/calls/call-abc-123/tts \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "Your ticket has been created. The ticket number is 45678.",
    "voice": "en_US-amy-medium",
    "speed": 1.0,
    "barge_in": true
  }'
{
  "playback_id": "pb-9f2a-4e71",
  "estimated_duration_ms": 3200
}

Hangup

Terminate an active call.

POST /v1/calls/{id}/hangup

Request body:

FieldTypeRequiredDescription
reasonstringnoReason for hangup: normal, busy, rejected, or error (default normal)

Response body:

FieldTypeDescription
call_duration_secondsintegerTotal call duration in seconds

Example:

curl -X POST https://gateway.example.com/v1/calls/call-abc-123/hangup \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "reason": "normal"
  }'
{
  "call_duration_seconds": 142
}

Transfer

Transfer an active call to another SIP endpoint.

POST /v1/calls/{id}/transfer

Request body:

FieldTypeRequiredDescription
target_uristringyesSIP URI to transfer to
typestringnoTransfer type: blind or attended (default blind)
headersobjectnoCustom SIP headers as key-value pairs

Response body:

FieldTypeDescription
successbooleanWhether the transfer was initiated
transfer_idstringID to track this transfer

Blind Transfer

The call is immediately redirected to the target URI:

curl -X POST https://gateway.example.com/v1/calls/call-abc-123/transfer \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "target_uri": "sip:support@pbx.internal",
    "type": "blind",
    "headers": {
      "X-Transfer-Reason": "escalation",
      "X-Original-Caller": "+15551234567"
    }
  }'
{
  "success": true,
  "transfer_id": "xfer-7c3d-88a1"
}

Attended Transfer

The system first establishes a call to the target, then bridges the caller:

curl -X POST https://gateway.example.com/v1/calls/call-abc-123/transfer \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "target_uri": "sip:agent@pbx.internal",
    "type": "attended",
    "headers": {}
  }'

Send DTMF

Send DTMF digits on an active call. Useful for navigating external IVR systems.

POST /v1/calls/{id}/dtmf

Request body:

FieldTypeRequiredDescription
digitsstringyesDigits to send (0-9, *, #)
duration_msintegernoTone duration per digit in milliseconds (default 100)
gap_msintegernoGap between digits in milliseconds (default 50)

Example:

curl -X POST https://gateway.example.com/v1/calls/call-abc-123/dtmf \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "digits": "12345",
    "duration_ms": 100,
    "gap_ms": 50
  }'
{
  "success": true
}

Hold

Put an active call on hold.

POST /v1/calls/{id}/hold

Request body:

FieldTypeRequiredDescription
music_filestringnoPath to hold music file (WAV, MP3)

Example:

curl -X POST https://gateway.example.com/v1/calls/call-abc-123/hold \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "music_file": "/path/to/music.wav"
  }'
{
  "success": true
}

Resume

Resume a held call.

POST /v1/calls/{id}/resume

Request body:

Empty object or omitted.

Example:

curl -X POST https://gateway.example.com/v1/calls/call-abc-123/resume \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'
{
  "success": true
}

Play Audio

Play a pre-recorded audio file on an active call.

POST /v1/calls/{id}/play-audio

Request body:

FieldTypeRequiredDescription
file_pathstringyesPath to audio file (WAV, MP3)
loopbooleannoLoop playback (default false)
barge_inbooleannoAllow caller to interrupt (default true)

Response body:

FieldTypeDescription
playback_idstringID to track this playback

Example:

curl -X POST https://gateway.example.com/v1/calls/call-abc-123/play-audio \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "file_path": "/var/audio/greeting.wav",
    "loop": false,
    "barge_in": true
  }'
{
  "playback_id": "pb-4a8e-c312"
}

Stop Playback

Stop any currently playing audio or TTS.

POST /v1/calls/{id}/stop-playback

Request body:

FieldTypeRequiredDescription
playback_idstringnoStop a specific playback by ID. If omitted, stops all active playback on the call.

Example:

curl -X POST https://gateway.example.com/v1/calls/call-abc-123/stop-playback \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "playback_id": "pb-9f2a-4e71"
  }'
{
  "success": true
}

Error Handling

All endpoints return standard HTTP status codes:

CodeMeaning
200 OKSuccess
404 Not FoundSession ID does not exist or call has ended
409 ConflictCall is in wrong state (e.g., already on hold)
400 Bad RequestMissing or malformed parameters
503 Service UnavailableService is temporarily unavailable
500 Internal Server ErrorUnexpected error

Error responses include a JSON body with details:

{
  "error": {
    "code": 404,
    "status": "NOT_FOUND",
    "message": "Call session call-abc-123 not found or has already ended."
  }
}

Usage Pattern

A common pattern is combining the Call Event Stream API with the Call Control API for reactive call management. Subscribe to a server-sent event stream for real-time call events, then issue control commands in response.

#!/usr/bin/env bash

TOKEN="your-api-token"
BASE="https://gateway.example.com"

# 1. Subscribe to speech events via SSE (runs in the background)
curl -N -H "Authorization: Bearer $TOKEN" \
  "$BASE/v1/events?types=speech_final" | while read -r line; do

  # Parse the event data (assumes each line is a JSON event)
  session_id=$(echo "$line" | jq -r '.session_id // empty')
  transcript=$(echo "$line" | jq -r '.speech.transcript // empty')

  [ -z "$session_id" ] && continue

  # 2. If the caller says "transfer", announce and transfer
  if echo "$transcript" | grep -qi "transfer"; then
    # Play a TTS announcement
    curl -s -X POST "$BASE/v1/calls/$session_id/tts" \
      -H "Authorization: Bearer $TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "text": "Transferring you now. Please hold.",
        "barge_in": false
      }'

    # Wait briefly for the announcement, then transfer
    sleep 3

    curl -s -X POST "$BASE/v1/calls/$session_id/transfer" \
      -H "Authorization: Bearer $TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "target_uri": "sip:agent@pbx.internal",
        "type": "blind",
        "headers": {}
      }'
  fi
done

For production use, consider implementing this pattern in your application language with a proper HTTP client and SSE parser rather than shell scripting.

Next Steps