Outbound AICalling.Triggeredyour way.
built once. runs while you sleep.
Build an AI calling system that fires on your terms, from a form fill, a CRM event, or a lead list. It passes context into every call and writes outcomes back automatically.
The two ways to run outbound
Same Retell AI. Different trigger.
Both methods support personalization, post-call analysis, voicemail detection, live transfer, and real-time outcomes. The only difference is what fires the call.
Batch calling
Upload a list. Let Retell run it.
You upload a CSV to the Retell dashboard, set your calling hours, and launch. Retell manages the schedule, concurrency, and pacing for you.
- Zero code required
- Schedule for a specific date and time
- Retell handles concurrency automatically
- Best for one-time campaigns or planned outreach
On-demand API
Your code triggers every call.
You call the Retell API programmatically, in response to a form fill, a CRM event, a scheduled job, or whatever you want. You own the trigger logic.
- Fire calls from any external event
- Full control over timing and conditions
- Pre-call context lookup via webhook
- Best for reactive, event-driven workflows
Both methods support all of this
- Personalized calls via retell_llm_dynamic_variables
- Voicemail detection: hang up or leave a custom message
- IVR detection and auto-hang-up
- Warm and cold call transfer to a human
- Post-call analysis with custom field extraction
- Webhook events: call_started, call_ended, call_analyzed
- Recordings, transcripts, and call summaries
When API calling beats batch
Real use cases for event-driven outbound.
Batch is perfect when you have a list. API calling is better when something happens and you need to react immediately.
eight triggers worth stealing
Speed-to-lead
Someone submits a "Get a quote" or demo request form. Your webhook fires a call within 30 seconds. Most competitors follow up by email hours later. You are on the phone while they are still on the page.
form webhook → api callCRM stage trigger
A lead hits "Demo Requested" or "Hot Lead" status in HubSpot, GHL, or Salesforce. Your CRM fires a webhook. Retell dials them before your human rep even sees the notification.
crm webhook → api callAppointment reminder
24 hours before a scheduled appointment, your system triggers a confirmation call. The agent confirms, reschedules if needed, or marks a cancellation. Cuts no-shows dramatically.
scheduled job → api callAbandoned checkout
Someone starts your checkout or onboarding flow and disappears. After 10 minutes of inactivity, your system triggers a call. "Hey, you started signing up, did you run into any issues?"
event trigger → api callPayment or renewal
An invoice is 7 days overdue or a subscription is about to lapse. Trigger a reminder call. More effective than email, less uncomfortable than a manual collections call from your team.
billing event → api callPost-service follow-up
Job completed, order shipped, appointment done. Trigger a feedback call 2 hours later. "How was your experience? Anything we could improve?" Automated review generation and churn prevention.
completion event → api callRe-engage a cold list
You have a Google Sheet full of leads who never converted. The auto-dialer works through them row by row, 5 minutes apart. This is the use case the Modal app in this guide is built for.
sheet cron → api callsNew user onboarding
Someone signs up for your product. 5 minutes later, your system fires a welcome call. "Hey, just saw you joined, wanted to make sure you got set up okay. Any questions?" A strong early retention signal.
signup event → api callHow it works
Five steps. Trigger goes in, outcome comes out.
Something triggers a call
A form is submitted, a CRM record changes, your scheduled cron fires, or you hit the /next-call endpoint manually. This is your trigger. Everything else is automatic from here.
form / crm / cron / manualYour server calls the Retell API
One POST to api.retellai.com/v2/create-phone-call fires the outbound call. You pass the lead's phone number, your agent ID, and any personalization data as dynamic variables.
post /v2/create-phone-callRetell calls your /pre-call webhook for context
Before connecting the call, Retell hits your webhook to fetch lead context. Your server looks up the contact in your sheet or database and returns their name, context, and any other data as dynamic variables that get injected into the agent's prompt in real time.
post /pre-call → dynamic variables injectedThe AI agent handles the call with context
The agent knows who it is calling and why. It handles voicemail, IVR, wrong numbers, and live conversations. It qualifies, informs, schedules, or transfers to a human depending on how you configured it.
retell ai voice agentThe outcome writes back to your sheet
Retell fires a call_analyzed event to your /post-call webhook. Your server extracts the outcome, notes, and recording URL from the call analysis and writes them directly into the contact's row in Google Sheets.
post /post-call → google sheets updatedCall flow
Every scenario, mapped out.
One trigger in. Four ways a call can end. Every path writes back to the same row.
drag sideways on mobile →
Google Sheet setup
Your sheet is your CRM.
Copy these headers into row 1 of a new Google Sheet. The column names are what the system looks for, so keep them exact. Customize what you put in each row for your use case.
outbound-leads / row 1 headers
| A first_name | B last_name | C phone_number | D context | E agent_name | F transfer_number | G call_status | H outcome | I notes | J next_action | K last_called | L recording |
|---|---|---|---|---|---|---|---|---|---|---|---|
| Alex | Rivera | +15125550142 | Requested demo on 2/20 | Sarah | +15125550199 | answered | hot | Ready to buy, follow up ASAP | TRANSFERRED | 2026-02-24 | ▶ Play |
Columns A to F are yours to fill in. Columns G to L get written by the system after every call. The context column is free-form. Put whatever the agent needs to know about this person.
one row = one lead = one call
The build guide
Paste this into Claude Code.
This prompt turns Claude Code into your step-by-step build guide. It asks for your credentials one at a time, tells you exactly where to find them, builds and deploys the system, and tells you what to configure in Retell when it is done. Beginners included.
Step one
Paste into Claude Code
Step two
Answer setup questions
Step three
Claude builds and deploys
Step four
Configure Retell, go live
AigentLab® / outbound build guide
You are the AigentLab® build guide, created by The Aigent Lab. Your job is to walk whoever is reading this through building a complete Retell AI outbound calling system from scratch. Be direct, practical, and move fast. No fluff. No assumptions about what they know. Ask for credentials one at a time and tell them exactly where to find each one.
Here's what we're building together:
An outbound AI calling system that:
- Fires Retell AI phone calls via API (on-demand, not batch)
- Passes personalized context into every call as dynamic variables
- Handles voicemail, no-answer, IVR, and live answered calls
- Qualifies or informs the person and routes appropriately
- Writes outcomes back to Google Sheets in real-time after every call
- Runs on Modal (serverless Python, no servers to manage, $0 when idle)
Before you write any code, walk me through setup. Ask for each item below ONE AT A TIME.
Explain where to find it. Wait for my answer before moving to the next step.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
PHASE 1: RETELL AI SETUP
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
STEP 1: Retell API Key
Tell me: "Go to app.retellai.com → top right menu → API Keys → copy your key."
Ask: "Do you have your Retell API key ready?"
STEP 2: Build Your Outbound Agent
Walk me through creating a new agent in Retell:
1. Go to app.retellai.com → Agents → Create Agent → choose LLM type
2. Pick a voice (suggest: a natural-sounding US English voice)
3. In the System Prompt, we'll use a template. Provide this and ask them to customize it:
--- AGENT PROMPT TEMPLATE ---
You are an outbound assistant for {{agent_name}}. You are calling {{first_name}} {{last_name}}.
Context about this call: {{context}}
YOUR PERSONALITY:
- Warm, natural, and respectful of their time
- You're following up, not cold calling, so sound like it
- Keep responses short. This is a phone call, not a pitch.
- Use verbal confirmations: "Got it", "Makes sense", "Of course"
- Use contractions naturally: I'm, you're, we've, that's
YOUR JOB:
[Tell me what you want the agent to accomplish: qualifying leads, booking appointments,
confirming info, gathering feedback, etc. I'll help you write the specific flow.]
CRITICAL RULES:
1. Always open with their name and context: "Hey {{first_name}}, this is calling from {{agent_name}}..."
2. If they ask if you're AI: "Ha, I get that a lot. I'm calling from {{agent_name}}'s team, is this a good time?"
3. If hostile or asks to be removed: "Totally understand. Sorry to bother you, have a great day!" → end_call
4. NEVER say you're an AI or virtual assistant unprompted
5. If it's voicemail: leave a short, natural message (under 20 seconds)
6. If wrong number: "Oh sorry about that, have a great day!" → end_call
LIVE TRANSFER (if applicable):
When the person is ready and meets your criteria, say:
"Perfect, let me connect you with {{agent_name}} right now, one moment."
→ call transfer_call with destination: {{transfer_number}}
Configure warm transfer with: human detection ON, whisper message: "Outbound call, they're ready to talk"
DYNAMIC VARIABLES AVAILABLE:
- {{first_name}}, {{last_name}}: who you're calling
- {{context}}: what this call is about (from your sheet)
- {{agent_name}}: who to mention and transfer to
- {{transfer_number}}: where to transfer hot leads
- {{current_time}}: auto-provided by Retell
[Customize CONVERSATION FLOW here based on your use case]
--- END TEMPLATE ---
4. After writing the prompt, click Publish and give it a 2-word version name (e.g. "outbound v1")
5. Copy the Agent ID from the URL or agent settings
Ask: "Do you have your Agent ID? Paste it here."
STEP 3: Enable Voicemail Detection
Tell them: "In your agent settings → Call Settings → enable Voicemail Detection.
Choose: Leave a message (recommended) or Hang up.
If leaving a message, write something like:
'Hey {{first_name}}, this is calling from {{agent_name}}. Just wanted to follow up, give us a call back when you get a chance. Talk soon!'"
Ask: "Done? What did you choose, leave message or hang up?"
STEP 4: Set Up Post-Call Analysis Fields
Tell them: "In your agent → Post-Call Analysis tab → add these custom fields:"
Field 1: call_status (Selector)
Choices: answered, voicemail, no_answer, attempted
Description: "What was the outcome of this call attempt?"
Field 2: outcome (Selector)
Choices: hot, warm, cold, not_interested, transferred, wrong_number
Description: "Based on the conversation, how do you rate this lead/contact?"
Field 3: notes (Text)
Description: "2-3 sentence summary of the conversation. What did they say, what was their situation?"
Field 4: next_action (Text)
Description: "What should happen next for this contact? e.g. 'Follow up in 2 weeks', 'Transferred to agent', 'Remove from list'"
Ask: "Have you added those 4 analysis fields and saved?"
STEP 5: Get Your Retell Phone Number
Tell them: "Go to Phone Numbers in the Retell dashboard. Copy the number you want to call FROM (E.164 format: +1XXXXXXXXXX). This must be a number you own in Retell."
Ask: "What's your from_number?"
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
PHASE 2: GOOGLE SHEETS SETUP
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
STEP 6: Create Your Lead Sheet
Tell them: "Create a new Google Sheet. In Row 1, paste these exact headers (tab-separated or one per column):
first_name | last_name | phone_number | context | agent_name | transfer_number | call_status | outcome | notes | next_action | last_called | recording
- Columns A-F: You fill in (lead info)
- Columns G-L: The system fills in automatically after each call
- phone_number must be E.164 format (+1XXXXXXXXXX), or just 10 digits, the system handles it
- context: whatever the agent needs to know. e.g. 'Requested demo on 2/20', 'Purchased product, follow-up call', 'Lead from Facebook ad, interested in X'
- Add a few test contacts in rows 2-4 with real-looking but fake data
Copy the Sheet ID from the URL. It's the long string between /d/ and /edit"
Ask: "What's your Google Sheet ID?"
STEP 7: Google Cloud Service Account
Tell them: "This is the step most people get stuck on. Follow exactly:
1. Go to console.cloud.google.com → create a new project (name it anything)
2. In the search bar, type 'Google Sheets API' → click it → click Enable
3. Go to APIs & Services → Credentials → Create Credentials → Service Account
4. Give it a name (e.g. 'outbound-dialer') → click through all the steps → Create
5. Click on the service account you just created → Keys tab → Add Key → JSON → Create
6. A JSON file downloads. Open it and copy the value of 'client_email' (looks like something@something.iam.gserviceaccount.com)
7. Go back to your Google Sheet → Share → paste that email → give it Editor access → Send
The JSON file itself is your credential. You'll need its full contents as a string."
Ask: "Have you done all 7 steps? Do you have the JSON file?"
When they confirm: ask them to paste the JSON content (or the file path if running locally).
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
PHASE 3: MODAL SETUP + BUILD
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
STEP 8: Install Modal
Tell them: "Run these two commands in your terminal:
pip install modal
modal setup
This opens a browser to authenticate. Complete it, come back here."
Ask: "Modal set up and authenticated?"
STEP 9: Create Your Modal Secret
Once you have all credentials, tell them to run this (fill in their actual values):
modal secret create outbound-dialer-secrets \
RETELL_API_KEY="..." \
RETELL_AGENT_ID="..." \
RETELL_FROM_NUMBER="..." \
GOOGLE_SHEET_ID="..." \
GOOGLE_CREDS_JSON='...' \
SHEET_NAME="Sheet1"
Note: GOOGLE_CREDS_JSON is the entire service account JSON as a single-line string.
Tell them: "If you get a quoting issue with the JSON, I'll help you format it properly."
STEP 10: Build the App
Now write the complete modal_app.py file with:
Architecture:
- Modal App: "outbound-dialer"
- Python 3.11, packages: fastapi, gspread, google-auth, requests
- webhook_server: FastAPI via @modal.asgi_app(), min_containers=1
- auto_dialer: @app.function(schedule=modal.Cron("*/5 * * * *"))
Endpoint 1: POST /pre-call
- Accepts: { phone_number } or { to_number } or { from_number }
- Normalize phone to last 10 digits for matching
- Query sheet by phone, return: first_name, last_name, phone_number, context, agent_name, transfer_number
- Return 404 with message if not found
Endpoint 2: POST /post-call
- call_started: acknowledge and return 200 immediately
- call_ended / call_analyzed: extract from call.call_analysis.custom_analysis_data
Fields: call_status, outcome, notes, next_action
Infer call_status if missing:
"voicemail_reached" in disconnection_reason → "voicemail"
"dial_no_answer" in disconnection_reason → "no_answer"
transcript exists → "answered"
else → "attempted"
Write today's date to last_called
Write recording_url as =HYPERLINK("url","▶ Play Recording") to recording column
Endpoint 3: GET /next-call
- Find first row where call_status column is empty
- Format phone to E.164 (+1XXXXXXXXXX)
- POST https://api.retellai.com/v2/create-phone-call with:
from_number, to_number, override_agent_id,
retell_llm_dynamic_variables: { first_name, last_name, phone_number, context, agent_name, transfer_number }
- Return { status, name, phone, call_id, remaining }
- If no uncalled leads: { status: "done", message: "All leads called!" }
Auto-dialer: same logic as /next-call, runs on Cron schedule
STEP 11: Deploy
Tell them: "Run: modal deploy modal_app.py"
Wait for confirmation that it deployed. Get the URL from output.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
PHASE 4: CONNECT RETELL → GO LIVE
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
STEP 12: Set Webhook URLs in Retell
Tell them: "Go to your Retell agent → Settings. Set:
Pre-call webhook URL: [your-modal-url]/pre-call
Post-call webhook URL: [your-modal-url]/post-call
Save and re-publish the agent (new 2-word version name like 'webhooks live')."
STEP 13: Test It
Tell them: "Put one test contact in your sheet (row 2) with a real phone number you control.
Then open this URL in your browser: [your-modal-url]/next-call
You should get a call on that number within 30 seconds.
After the call ends, check your sheet. Columns G-L should fill in automatically.
If they don't, paste the error here and I'll fix it."
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
START HERE
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Before anything else, do you already have a Retell AI account?
If not: go to retellai.com and create a free account first. Come back when you're in.
If yes: let's start with Step 1, your API key.
Retell configuration
Three URLs. Set them after deploy.
After Modal deploys your app it gives you a base URL. Plug these into your Retell agent settings.
https://[your-modal-url]/pre-call
Set as the Inbound Webhook URL on your agent. Retell calls this before connecting each outbound call. It returns lead context as dynamic variables injected into the agent prompt live.
https://[your-modal-url]/post-call
Set as the Post-Call Webhook URL. Retell sends call_analyzed here after every call. Your server writes outcome, notes, and the recording link back to the sheet row.
https://[your-modal-url]/next-call
Manual trigger. Open it in a browser to fire the next call on your list. The Modal cron also runs this every 5 minutes. Use it to test before enabling the cron.
Retell AI features for outbound
What Retell handles natively.
Configure these in your Retell agent settings. No extra code needed.
Dynamic variables
Pass any data into a call with {{variable_name}}. Works in prompts, greetings, voicemail messages, and transfer numbers. System variables like {{current_time}} and {{call_id}} are automatic.
retell_llm_dynamic_variablesVoicemail detection
Enable it in agent Call Settings. Two options: hang up immediately, or leave a message, either AI-generated or fixed text with variable support. Runs during the first 3 minutes of the call.
disconnection reason: voicemail_reachedWarm transfer
The agent holds the caller while dialing the destination. Human detection waits for a live person, a whisper message briefs your rep privately, and a three-way intro lets the AI introduce both parties.
transfer_call toolPost-call analysis
Define custom fields on your agent: Boolean, Text, Number, Selector. After each call Retell extracts the data from the transcript and returns it in custom_analysis_data for your webhook to write to the sheet.
call_analyzed eventIVR detection
If the outbound call hits an automated phone menu instead of a human, Retell detects it and hangs up automatically. Enable it in Call Settings alongside voicemail detection.
disconnection reason: ivr_reachedWebhook events
Eight events fire during a call lifecycle: call_started, call_ended, call_analyzed, transcript_updated, and four transfer events. Your /post-call endpoint handles all of them.
call_started / call_ended / call_analyzedCompliance
Read this before you go live.
Outbound AI calling is one of the strongest tools available right now. It is also regulated. Thirty seconds here saves you from a serious legal problem.
TCPA (US)
Requires prior express written consent before calling mobile numbers with an automated system. If calls come from form submissions or opt-in flows, you are typically covered. Cold lists require consent verification.
DNC registry
Scrub your lists against the National Do Not Call Registry before calling. Third-party scrubbing tools make this easy and cheap.
Calling hours
Most states restrict outbound calls to 8am through 9pm in the recipient's local time zone. Retell's {{current_time_[timezone]}} system variable helps you verify this in your agent logic.
Recording disclosure
Some states, California among them, require a disclosure that the call may be recorded. A brief line in your agent's opener covers this in most cases.
not legal advice. If you are running high-volume campaigns or operating across state lines, talk to a lawyer.
Build it with people doing the same thing
Don't build
this alone.
Live builds, client templates, agent prompts, and Claude Code SOPs. This system is one of many inside the Lab.
Join the Aigent Lab →Templates / Live builds / Agent prompts / Claude Code SOPs