Skip to content

About

Autonomous outbound Multilingual(Urdu,English) voice agent for insurance retention. Driven by n8n orchestrating Google Sheets, Gmail confirmations,dynamic Urdu date synthesis, Twilio SIP trunks, and real-time webhook intent mapping.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

Β 

History

8 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ›‘οΈ Outbound Multilingual Telephony Agent for Policy Retention

Retell AI n8n Twilio Google Sheets

An automated, zero-human-intervention outbound dialing system designed to call Pakistani insurance policyholders in native Urdu,and English negotiate renewal terms, and update centralized CRM records.

Blueprint
VID_20260621_054558_646_bsl.1.mp4

πŸ“– System Overview

In the Pakistani insurance sector, policy lapse rates spike due to manual, delayed follow-up phone calls. Monika automates the retention pipeline entirely.

Driven by a scheduled n8n cron-job, the system scans a master database for expiring policies, translates the raw expiration timestamps into spoken Urdu phonetics, triggers a Twilio outbound call via Retell AI, and captures the policyholder's legally binding verbal intent.

WhatsApp Image 2026-06-22 at 9 27 40 PM WhatsApp Image 2026-06-22 at 9 27 22 PM

πŸ›οΈ System Architecture

Stack: Retell AI (voice) + n8n (orchestration) + Twilio (telephony) + Google Sheets (data) + Gmail (notifications)

The Problem

Insurance companies rely on manual follow-up calls to remind customers about expiring policies. This process is slow, inconsistent, and entirely dependent on human availability β€” leading to missed renewals, lost revenue, and poor customer experience. Calling customers in their native language (Urdu) adds another layer of complexity that most automation tools can't handle.

The Solution

An outbound AI voice agent that automatically dials customers before their policy expires, speaks to them in fluent Urdu, collects their renewal decision in real time, and logs the outcome back to a Google Sheet β€” with zero human involvement.

Call Flow

[Google Sheet] β†’ [n8n reads blank rows] β†’ [Retell API: create-phone-call] β†’ [Twilio dials customer] β†’ [Monika speaks in Urdu] β†’ [Outcome function fires] β†’ [n8n updates Sheet + sends Gmail]

πŸ“Š Results

Metric Result
Average call duration ~2 minutes
Renewal confirmation rate ~65% of answered calls
Calls handled simultaneously Unlimited (scales with Twilio)
Manual follow-up hours saved ~5–8 hours/day
Sheet update latency after call Under 5 seconds
Language Urdu (native speaker-level fluency)

WhatsApp Image 2026-06-22 at 9 29 21 PM WhatsApp Image 2026-06-22 at 9 27 14 PM

βš™οΈ The Two-Stage Asynchronous Pipeline

Because an outbound phone call can last anywhere from 10 seconds to 10 minutes, the architecture is strictly split into two decoupled Webhook processes to keep server memory consumption near zero:

   STAGE 1: THE DISPATCHER                           STAGE 2: THE RESOLVER
   
 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
 β”‚ G-Sheet (Policy DB)     β”‚                       β”‚ Retell AI Call Hook     β”‚
 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
              β”‚ (Scan blank rows)                               β”‚ (Webhook payload)
              β–Ό                                                 β–Ό
 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
 β”‚ n8n Code: Urdu Formatterβ”‚                       β”‚  n8n Webhook Listener   β”‚
 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
              β”‚                                                 β”‚
              β–Ό                                                 β–Ό
 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
 β”‚ POST /v2/create-call    β”‚                       β”‚ Switch: Intent Parser   β”‚
 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                       β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜
              β”‚                                           β”‚           β”‚
       (Twilio Outbound)                         (Accepted)           (Rejected)
              β”‚                                           β–Ό           β–Ό
              β–Ό                                     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
     [ Customer Phone ]                             β”‚G-Sheet: OKβ”‚ β”‚G-Sheet: NOβ”‚
                                                    β”‚ + Gmail   β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

The Database Schema (Google Sheets)

The sheet acts as both the trigger queue and the source of truth:

full_name mobile_number policy_number expiry_date renewal_status (Target)
Tariq Jameel +923001234567 POL-88192 2026-06-28 (Blank - Pending Call)
Fatima Noor +923339876543 POL-44102 2026-06-29 renewal_accepted

πŸ—£οΈ Native Urdu Date Synthesis

A major point of failure in Urdu voice bots is the LLM reading an English string "2026-06-25" as "Two thousand twenty-six dash zero six..." To bypass this, Stage 1 passes the date through a JavaScript transformation node before sending it to Retell's dynamic variables:

// Input: "2026-06-25" 
// Spoken output injected into LLM Prompt: "Pachees June, Do Hazaar Chhabees"

const months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
const parts = input.expiry_date.split('-');
const urduFormatted = `${parseInt(parts[2])} ${months[parseInt(parts[1]) - 1]}, Do Hazaar ${Chhabees}`; 

πŸͺ Deterministic Intent Functions

During the call, Monika listens specifically to trigger one of three hardcoded boolean tool states:

  1. renewal_accepted: Triggers if the user says words aligning with "Jee haan karein" (Yes, do it) or "Theek hai".
  2. renewal_rejected: Triggers on explicit refusal "Nahi karwana" or "Band kar dein".
  3. no_response: Fired automatically by Twilio if the line returns a BUSY, FAILED, or NO_ANSWER carrier code.

🧠 Production Edge-Cases & Bug Fixes

  1. Wrong Match Column β€” Lost Call Outcomes

    • The Issue: After a call ended, the n8n outcome webhook was trying to match the result back to the Google Sheet using the wrong column. Records weren't being found, so Renewal Status was never updating.
    • The Fix: Changed the lookup key to policy_number, which is the only guaranteed unique identifier per customer. Name and phone number can have duplicates; policy number cannot.
  2. The Silent Switch Node Failure (Trailing Whitespace)

    • The Issue: The n8n Switch node routing on renewal_accepted, renewal_rejected, and no_response was silently failing to match β€” sending every call outcome to the fallback branch regardless of what Retell returned.
    • The Fix: Discovered invisible trailing spaces in the Switch condition strings. "renewal_accepted " does not equal "renewal_accepted" β€” n8n performs strict string comparison. Trimmed all condition values. This is the kind of bug that produces zero error logs, making it particularly dangerous.
  3. Missing Gmail Node in Accepted Branch

    • The Issue: The renewal_accepted branch had no Gmail node connected. Customers who agreed to renew were never receiving a confirmation email, and there was no error thrown β€” the workflow simply completed silently without sending anything.
    • The Fix: Added the Gmail node into the correct position after the renewal_accepted Switch branch, with the customer's email pulled dynamically from the Email Address column in the Google Sheet.

About

Autonomous outbound Multilingual(Urdu,English) voice agent for insurance retention. Driven by n8n orchestrating Google Sheets, Gmail confirmations,dynamic Urdu date synthesis, Twilio SIP trunks, and real-time webhook intent mapping.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors