Hey! How can we help?

How to Build an AI Voice Agent with Callsavvy Call Control API

Introduction

Callsavvy's Call Control Webhook API allows you to build intelligent, interactive voice agents that can handle inbound calls, process DTMF inputs, recognize speech, and control call flows in real time. This guide walks you through setting up a Callsavvy account, obtaining your API credentials, and building your first AI-powered voice agent.


Step 1: Create a Callsavvy Account and Get Your API Credentials

Before you can use the Call Control API, you need to sign up for a Callsavvy account and retrieve your API keys.

1.1 Sign Up

Visit the Callsavvy website and create a new account. You will need administrative privileges to access API settings.

1.2 Locate Your API Credentials

Once logged in as an Admin:

  • Navigate to SettingsAPI & Integration from your Callsavvy workplace dashboard.
  • Your credentials will be displayed here, including:
    • Public Key – Used to identify your account
    • Private Key – Used to authenticate API requests

1.3 Security Best Practices

For added security, Callsavvy recommends restricting access to your API credentials by whitelisting only trusted IP addresses and domains. You can configure this under Whitelisted Domains in the same API settings section.

1.4 Authentication

All API requests require authentication via HTTP headers over TLS (HTTPS). Include the following headers in every request:

Header Value
Public-Key Your API Public Key
Private-Key Your API Private Key

Step 2: Understanding the Call Control Webhook Architecture

Callsavvy uses a webhook-based architecture where your server responds to incoming call events with JSON instructions that control the call flow.

How It Works

Caller → Callsavvy → Your Webhook URL → Your Server → JSON Response → Callsavvy executes action
  • An inbound call triggers a POST request to your callback URL
  • Your server responds with a JSON payload specifying what action to take
  • Callsavvy executes that action (play audio, gather DTMF, bridge call, etc.)
  • Subsequent events (DTMF, speech completion) trigger additional webhook calls

Required Webhook Endpoints

You need to implement a publicly accessible HTTPS endpoint that can receive and respond to these event types:

Event Trigger
inboundCall New incoming call received
callProgress Call status changes (ringing, answered, ended, etc.)
dtmfReceived Caller presses digits on their keypad
speechCompleted AI speech recognition finishes processing

Step 3: Building Your AI Voice Agent

3.1 Basic Webhook Response Structure

All webhook responses must follow this JSON format:

{
    "action": "call_control_action",
    "action_parameters": {
        "parameter_name": "parameter_value"
    },
    "next_action": "next_call_control_action",
    "next_action_parameters": {
        "parameter_name": "parameter_value"
    }
}

3.2 Creating an AI-Powered Voice Agent

The voiceAI action connects the call to Callsavvy's native AI voice agent. Here's a complete example that handles an inbound call with an AI agent:

Inbound Call Webhook Response:

{
    "action": "voiceAI",
    "action_parameters": {
        "speech_timeout": 3,
        "language": "en-US",
        "voice": "female",
        "branding_name": "My Business",
        "branding_description": "A customer support AI assistant",
        "workflows": {
            "workflow_id_1": true,
            "workflow_id_2": true
        },
        "Knowledgebase_category": {
            "category_id_1": "support",
            "category_id_2": "sales"
        }
    }
}

Parameter Reference:

Parameter Description Constraints
speech_timeout Seconds to wait for speech input Number between 1 and 5
language Language for speech recognition See supported languages
voice TTS voice gender/style See supported voices
workflows Object of workflow IDs to associate Object format
Knowledgebase_category Object of knowledge base categories Object format
branding_name Business name for AI context String
branding_description AI role description String

3.3 Handling DTMF Input (Menus)

Use gatherDTMF to collect keypad input from callers, such as menu selections or account numbers.

Example: Collect a 1-digit menu selection

{
    "action": "gatherDTMF",
    "action_parameters": {
        "dtmf_digits": "1"
    }
}

Example: Collect a 4-digit extension

{
    "action": "gatherDTMF",
    "action_parameters": {
        "dtmf_length": 4
    }
}

When digits are received, Callsavvy sends a dtmfReceived webhook containing the digits.

3.4 Playing Audio and Text-to-Speech

Play an MP3 file:

{
    "action": "playAudio",
    "action_parameters": {
        "audio_url": "https://your-server.com/welcome.mp3"
    },
    "next_action": "gatherDTMF",
    "next_action_parameters": {
        "dtmf_length": 1
    }
}

Read text aloud using TTS:

{
    "action": "readText",
    "action_parameters": {
        "text": "Thank you for calling. Please hold while I connect you.",
        "language": "en-US",
        "voice": "female"
    }
}

3.5 Bridging Calls

Dial an external number:

{
    "action": "dialNumber",
    "action_parameters": {
        "phone_number": "+14155551234"
    }
}

Dial a SIP endpoint (only as next_action):

{
    "action": "playAudio",
    "action_parameters": {
        "audio_url": "https://your-server.com/connecting.mp3"
    },
    "next_action": "dialSIP",
    "next_action_parameters": {
        "sip_host": "sip.example.com",
        "sip_port": 5060,
        "sip_username": "user",
        "sip_password": "password"
    }
}

Step 4: Call Progress and Disposition Tracking

The callProgress webhook provides real-time updates about call state. Here's an example payload:

{
    "event": "callProgress",
    "call_status": "answered",
    "call_disposition": "answered",
    "cost": 0.025,
    "call_duration": 45,
    "recording_url": "https://callsavvy.com/recordings/abc123.mp3",
    "from": "+14155551234",
    "to": "+14155556789",
    "session_id": "session_123",
    "call_id": "encrypted_call_id_456",
    "call_direction": "inbound"
}

Call Status Values

StatusDescription
ringingCall is ringing
answeredCall was answered
endedCall has ended
enqueuedCall placed in queue
dequeuedCall removed from queue
agent_leftAgent disconnected
audio_playback_completedAudio finished playing

Call Disposition Values

DispositionDescription
answeredCall was successfully answered
not answeredCaller did not answer
failedCall failed due to error
no responseNo response from called party
busyLine was busy
canceledCall was canceled

Step 5: Important Rules and Limitations

⚠️ CRITICAL WARNING: If your webhook returns an invalid or unprocessable JSON response, Callsavvy will play an error message to the caller and the call will fail to continue. Always validate your response format.

Actions that CANNOT have a next_action

These actions are terminal or blocking:

  • voiceAI
  • dialNumber
  • hangup
  • silence
  • dialSIP
  • gatherDTMF

Actions that CANNOT be used as next_action

These can only be primary actions:

  • readText
  • playAudio

Valid Action Combinations

Primary Action Can have next_action? Allowed next_action values
readText ✅ Yes readText, playAudio, hangup, silence
playAudio ✅ Yes readText, playAudio, hangup, silence
voiceAI ❌ No None
dialNumber ❌ No None
hangup ❌ No None
silence ❌ No None
dialSIP ❌ No None
gatherDTMF ❌ No None
enqueue ✅ Yes readText, playAudio, hangup, silence

Complete Example: IVR Menu with AI Fallback

Here's a complete call flow that:

  1. Plays a welcome message
  2. Collects a 1-digit menu selection
  3. Routes to AI agent for selections 1-2, or loops back for invalid input

Initial Webhook Response (inboundCall)

{
    "action": "playAudio",
    "action_parameters": {
        "audio_url": "https://your-server.com/welcome.mp3"
    },
    "next_action": "gatherDTMF",
    "next_action_parameters": {
        "dtmf_digits": "1,2,3"
    }
}

Handling dtmfReceived Webhook

When DTMF is received, your webhook should respond based on the digits:

{
    "action": "voiceAI",
    "action_parameters": {
        "speech_timeout": 3,
        "language": "en-US",
        "voice": "female",
        "branding_name": "Support Center",
        "branding_description": "Customer support AI assistant"
    }
}

Handling callProgress for Call Tracking

{
    "action": "silence",
    "action_parameters": {}
}

Step 6: Testing Your Implementation

  1. Use a tool like Postman to mock webhook requests and test your JSON responses
  2. Set up a staging endpoint with a publicly accessible HTTPS URL (use ngrok for local testing)
  3. Configure your callback URL in Callsavvy under Settings → API & Integration
  4. Place a test call to your Callsavvy number and monitor your server logs
  5. Verify proper JSON formatting – invalid responses will cause call failures with error messages

Full List of Call Control Actions

Action Description Parameters
voiceAI Native AI voice agent speech_timeout, language, voice, workflows, Knowledgebase_category, branding_name, branding_description
readText Text-to-speech playback text, language, voice
playAudio Play MP3 file audio_url
dialNumber Bridge to phone number phone_number
dialSIP Bridge to SIP endpoint (next_action only) sip_host, sip_port, sip_username, sip_password
enqueue Place call in queue hold_music_url
gatherDTMF Collect DTMF input dtmf_digits OR dtmf_length
hangup End the call None
silence Do nothing None

Conclusion

The Callsavvy Call Control Webhook API provides a flexible foundation for building sophisticated AI voice agents. By implementing the webhook endpoints described in this guide and following the response formatting rules, you can create interactive phone systems that handle menus, speech recognition, call routing, and AI-powered conversations.

For a complete reference of supported languages and voices, visit the Callsavvy API documentation.

Still can't find what you are looking for?

Here are other ways to get help!

Phone

Speak to one of our customer care agent

Ticket

Open a ticket to our support team>

Chat

Have a chat with our support team<

Video

Request a video chat with our team<

Meeting

Book a virtual meeting on our calendar<

Chat with us