Skip to content

Build an AI Agent That Calls People on the Phone

April 6, 2026 · Tutorial · 10 min read


What if your AI agent could pick up the phone and actually call people?

Not a robocall. Not a pre-recorded message. A real, natural conversation — powered by Amazon Nova Sonic — that can answer questions, collect information, and adapt in real-time based on what the person says.

That's exactly what we're going to build. By the end of this tutorial, you'll have an AI voice agent that can call any phone number, have a conversation, and handle use cases like:

  • Lead qualification — "Hi, I'm calling from Acme Corp. You signed up for a demo — are you still interested?"
  • Appointment scheduling — "I'd like to confirm your appointment for Thursday at 2pm. Does that still work?"
  • Customer surveys — "On a scale of 1-10, how satisfied are you with our service?"
  • Payment reminders — "This is a friendly reminder that your invoice is due on Friday."
  • Event RSVPs — "We're hosting a product launch next week. Can we count you in?"

Let's build it.

What You'll Need

  1. A Universal API account — Sign up at universalapi.co and grab a Bearer token from the Credentials page
  2. A Twilio account — Sign up at twilio.com (free trial works)
  3. A Twilio phone number — $1/month for a local number
  4. ~10 minutes

Step 1: Create Your Voice Agent

First, we need an AI agent that knows how to have a phone conversation. On Universal API, voice agents use Amazon Nova Sonic for real-time speech-to-speech AI — it hears the caller, thinks, and responds with natural speech.

Here's a lead qualification agent. Create it via the API:

bash
curl -X POST https://api.universalapi.co/agent/create \
  -H "Authorization: Bearer YOUR_UAPI_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "agentName": "lead-qualifier",
    "agentType": "bidi",
    "description": "AI voice agent that qualifies leads via outbound phone calls",
    "visibility": "private",
    "sourceCode": "from strands.experimental.bidi.agent import BidiAgent\nfrom strands.experimental.bidi.models.nova_sonic import BidiNovaSonicModel\n\ndef create_bidi_agent():\n    model = BidiNovaSonicModel(\n        region=\"us-east-1\",\n        model_id=\"amazon.nova-sonic-v1:0\",\n        provider_config={\n            \"audio\": {\n                \"input_sample_rate\": 16000,\n                \"output_sample_rate\": 24000,\n                \"voice\": \"tiffany\"\n            }\n        }\n    )\n    system_prompt = \"\"\"You are a friendly, professional sales development representative calling on behalf of Acme Corp.\n\nYour goal is to qualify leads who signed up on our website. Be conversational and natural — not robotic.\n\nFollow this flow:\n1. Introduce yourself: Hi, this is [your name] from Acme Corp. You recently signed up for more info about our platform.\n2. Ask what prompted their interest\n3. Ask about their current solution and pain points\n4. Ask about their timeline and budget range\n5. If qualified, offer to schedule a demo with a solutions engineer\n6. Thank them for their time\n\nKeep responses concise — this is a phone call, not an essay. Listen more than you talk.\nIf they say they are busy, offer to call back at a better time.\nIf they are not interested, thank them politely and end the call.\"\"\"\n    return BidiAgent(model=model, system_prompt=system_prompt)"
  }'

Save the agentId from the response — you'll need it in Step 3.

Voice Options

Nova Sonic supports multiple voices: tiffany, matthew, ruth, gregory, and more. Pick one that fits your brand. tiffany is warm and professional — great for sales calls.

Customize the System Prompt

The system prompt is everything. It controls how your agent behaves on the call. Here are templates for other use cases:

Appointment Confirmation:

You are calling to confirm an upcoming appointment. Be brief and friendly.
State the appointment date/time, ask if it still works, and offer to reschedule if needed.

Customer Survey:

You are conducting a brief customer satisfaction survey. Ask 3-5 questions,
listen to their responses, and thank them for their feedback. Keep it under 2 minutes.

Payment Reminder:

You are calling about an outstanding invoice. Be polite but clear about the amount
and due date. Offer to help if they have questions about the charge.

Step 2: Set Up Twilio

If you haven't already, create a Twilio account:

  1. Go to twilio.com/try-twilio and sign up
  2. From the Twilio Console, note your Account SID and Auth Token (visible on the dashboard)
  3. Go to Phone Numbers → Manage → Buy a Number
  4. Buy a local phone number ($1/month) — this is the number your agent will call from

Twilio Trial Limitations

On a Twilio trial account, you can only call verified phone numbers (numbers you've added to your account). To call any number, upgrade to a paid Twilio account ($20 minimum).

Step 3: Create a Twilio Voice Channel

Now connect your voice agent to Twilio by creating a channel on Universal API. This links your agent, your Twilio credentials, and your phone number together:

bash
curl -X POST https://api.universalapi.co/channels \
  -H "Authorization: Bearer YOUR_UAPI_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "lead-qualifier-phone",
    "platform": "twilio-voice",
    "agentId": "YOUR_AGENT_ID",
    "platformConfig": {
      "accountSid": "ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
      "authToken": "your_twilio_auth_token",
      "phoneNumber": "+15551234567"
    }
  }'

Replace:

  • YOUR_AGENT_ID — the agentId from Step 1
  • ACxxx... — your Twilio Account SID
  • your_twilio_auth_token — your Twilio Auth Token
  • +15551234567 — the Twilio phone number you bought (E.164 format)

Save the channelId from the response.

Step 4: Make Your First Outbound Call 🎉

This is the moment of truth. Tell your agent to call someone:

bash
curl -X POST https://api.universalapi.co/channels/YOUR_CHANNEL_ID/call \
  -H "Authorization: Bearer YOUR_UAPI_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "+15559876543"
  }'

Your phone will ring. When you pick up, you'll be talking to your AI agent. It will introduce itself, ask questions, and have a natural conversation — all in real-time.

The phone number must be in E.164 format (e.g., +15559876543 for US numbers).

What Happens Behind the Scenes

When you trigger the call:

Your API call
    → Universal API creates a Twilio call via REST API
    → Twilio dials the target phone number
    → When they pick up, Twilio opens a Media Stream (WebSocket)
    → Media Stream connects to your voice agent on ECS Fargate
    → Amazon Nova Sonic processes speech in real-time
    → Agent responds with natural voice
    → Conversation continues until someone hangs up

The entire pipeline runs in real-time with sub-second latency. The person on the other end has no idea they're talking to an AI (unless you tell them — which you should, for compliance).

Step 5: Scale It Up — Batch Calling

One call is cool. But the real power is calling a list of leads programmatically. Here's a simple Python script:

python
import requests
import time

UAPI_TOKEN = "YOUR_UAPI_TOKEN"
CHANNEL_ID = "YOUR_CHANNEL_ID"

leads = [
    "+15551111111",
    "+15552222222",
    "+15553333333",
]

for phone in leads:
    print(f"Calling {phone}...")
    resp = requests.post(
        f"https://api.universalapi.co/channels/{CHANNEL_ID}/call",
        headers={"Authorization": f"Bearer {UAPI_TOKEN}"},
        json={"to": phone}
    )
    print(f"  Status: {resp.status_code}")
    
    # Wait between calls (be respectful + Twilio rate limits)
    time.sleep(30)

Compliance Matters

Always comply with TCPA, GDPR, and local regulations when making outbound calls. Get consent before calling, identify yourself as AI when required, and honor do-not-call requests immediately.

Bonus: Accept Inbound Calls Too

Your Twilio phone number can also receive calls. When someone dials your number, they'll be connected to the same AI agent.

To enable this, configure Twilio's webhook:

  1. Go to Twilio Console → Phone Numbers → Manage → Active Numbers
  2. Click your phone number
  3. Under Voice Configuration → A Call Comes In, set:
    • Webhook URL: The webhookUrl from your channel (visible via GET /channels/YOUR_CHANNEL_ID)
    • HTTP Method: POST

Now your number works both ways — your agent can call out, and people can call in.

How Much Does It Cost?

Universal API: 50 credits/minute for voice sessions (~$0.05/min)

Twilio: ~$0.014/min for outbound calls + $1/month for the phone number

Total: About $0.064/minute for a fully autonomous AI phone agent. Compare that to:

  • A human SDR: ~$0.50-1.00/minute (salary + overhead)
  • Vapi: $0.05/min + LLM costs
  • Bland AI: $0.09/min
  • Retell: $0.07/min + LLM costs

What's Next?

We're actively building more voice capabilities:

  • Conference calling — Your agent calls someone, then merges in a human teammate for a warm handoff
  • Browser voice chat — Talk to your agent from a web page (no phone needed)
  • Tool use during calls — Agent looks up CRM data, checks calendars, or creates tickets mid-conversation
  • Call recordings & transcripts — Automatic post-call summaries

Get Started

  1. Sign up at universalapi.co
  2. Create a Bearer token on the Credentials page
  3. Create a voice agent with agentType: "bidi"
  4. Connect Twilio with a twilio-voice channel
  5. Start calling with POST /channels/{channelId}/call

Your AI agent is ready to pick up the phone. The question is — who should it call first?


Have questions? Check out our docs or reach out on GitHub.

Universal API — The agentic entry point to the universe of APIs