Eedesy
Book Demo
HomeProductsContact
AI Voice Agent
  • Introduction
  • Quick Start
  • Architecture
  • Core Concepts
  • Configuration
  • Creating an Agent
  • Using Templates
  • System Prompt Configuration
  • Language Selection
  • Settings Reference
  • Overview
  • Upload Files (PDF, DOCX)
  • Web Crawling (URLs & Sitemaps)
  • Document Processing
  • RAG Integration
  • Troubleshooting
  • Creating a Campaign
  • CSV Upload & Variables
  • Scheduling & Retry Logic
  • Campaign Analytics
  • Contact Management
  • Uploading Contacts
  • Managing Contacts
  • Call History Enrichment
  • Trial Numbers
  • Purchasing Numbers
  • BYOP Setup
  • Exotel Setup
  • Telephony Providers Guide
  • Credits System
  • Provider Costs Breakdown
  • Usage Analytics
  • Credit Packs
  • Overview
  • Finding Your Workspace ID
  • Common Issues
  • Audio Quality
  • Latency Optimization
  • Error Codes
  • Overview
  • Twilio
  • Exotel
  • Plivo
  • Telnyx
  • WhatsApp
  • WebRTC Browser
  • Overview
  • Deepgram
  • Google Chirp
  • Azure Speech
  • ElevenLabs Scribe
  • AssemblyAI
  • OpenAI Whisper
  • Overview
  • Cartesia
  • ElevenLabs
  • Google TTS
  • Azure Neural
  • OpenAI TTS
  • Deepgram Aura
  • Sarvam Bulbul
  • HeyPixa Luna
  • Overview
  • OpenAI GPT-4o
  • Gemini 2.0/2.5 Flash
  • Gemini Live (Native Audio)
  • OpenAI Realtime
  • Anthropic Claude
  • Azure OpenAI
  • Overview
  • VAD (Voice Activity Detection)
  • Interruption Handling
  • Turn Detection
  • Audio Processing
  • Function Calling
  • Call Transfer
  • DTMF Handling
  • Call Recording
  • Exporting Recordings
  • Transcripts
  • Webhooks
  • Variables & Templates
  • Multi-Language Support
  • Hindi
  • Tamil
  • Assamese
  • Other Indian Languages
  • Latency Optimization
  • Scaling & Performance
  • Error Handling
  • Monitoring & Logging
  • Security Best Practices
  • Trigger Call via API
  • REST API
  • WebSocket Protocol
  • Webhooks
  • Webhook Subscriptions
  • SDKs
  • Overview
  • Financial Services
  • E-commerce
  • Logistics
  • Hyperlocal
  • Healthcare
  • Education
  • Overview
  • Customer Support
  • Sales & Lead Conversion
  • Marketing Campaigns
  • Debt Collection
  • Overview
  • Customer Support Bot
  • Order Status IVR
  • Appointment Booking
  • Lead Qualification
  • Outbound Sales
  • Recruitment Screening
  • Overview
  • Migrate from Vapi
  • Migrate from Retell AI
  • Migrate from Traditional IVR

Related Products

  • AI Voice Agent
  • AI Voice Assistant
  • Try Free
AI Voice Agent
  • Introduction
  • Quick Start
  • Architecture
  • Core Concepts
  • Configuration
  • Creating an Agent
  • Using Templates
  • System Prompt Configuration
  • Language Selection
  • Settings Reference
  • Overview
  • Upload Files (PDF, DOCX)
  • Web Crawling (URLs & Sitemaps)
  • Document Processing
  • RAG Integration
  • Troubleshooting
  • Creating a Campaign
  • CSV Upload & Variables
  • Scheduling & Retry Logic
  • Campaign Analytics
  • Contact Management
  • Uploading Contacts
  • Managing Contacts
  • Call History Enrichment
  • Trial Numbers
  • Purchasing Numbers
  • BYOP Setup
  • Exotel Setup
  • Telephony Providers Guide
  • Credits System
  • Provider Costs Breakdown
  • Usage Analytics
  • Credit Packs
  • Overview
  • Finding Your Workspace ID
  • Common Issues
  • Audio Quality
  • Latency Optimization
  • Error Codes
  • Overview
  • Twilio
  • Exotel
  • Plivo
  • Telnyx
  • WhatsApp
  • WebRTC Browser
  • Overview
  • Deepgram
  • Google Chirp
  • Azure Speech
  • ElevenLabs Scribe
  • AssemblyAI
  • OpenAI Whisper
  • Overview
  • Cartesia
  • ElevenLabs
  • Google TTS
  • Azure Neural
  • OpenAI TTS
  • Deepgram Aura
  • Sarvam Bulbul
  • HeyPixa Luna
  • Overview
  • OpenAI GPT-4o
  • Gemini 2.0/2.5 Flash
  • Gemini Live (Native Audio)
  • OpenAI Realtime
  • Anthropic Claude
  • Azure OpenAI
  • Overview
  • VAD (Voice Activity Detection)
  • Interruption Handling
  • Turn Detection
  • Audio Processing
  • Function Calling
  • Call Transfer
  • DTMF Handling
  • Call Recording
  • Exporting Recordings
  • Transcripts
  • Webhooks
  • Variables & Templates
  • Multi-Language Support
  • Hindi
  • Tamil
  • Assamese
  • Other Indian Languages
  • Latency Optimization
  • Scaling & Performance
  • Error Handling
  • Monitoring & Logging
  • Security Best Practices
  • Trigger Call via API
  • REST API
  • WebSocket Protocol
  • Webhooks
  • Webhook Subscriptions
  • SDKs
  • Overview
  • Financial Services
  • E-commerce
  • Logistics
  • Hyperlocal
  • Healthcare
  • Education
  • Overview
  • Customer Support
  • Sales & Lead Conversion
  • Marketing Campaigns
  • Debt Collection
  • Overview
  • Customer Support Bot
  • Order Status IVR
  • Appointment Booking
  • Lead Qualification
  • Outbound Sales
  • Recruitment Screening
  • Overview
  • Migrate from Vapi
  • Migrate from Retell AI
  • Migrate from Traditional IVR
  1. Docs
  2. AI Voice Agent
  3. Use Cases
  4. Debt Collection

AI Voice Agents for Debt Collection

Build compliant, effective AI voice agents for debt collection with payment reminders, arrangement negotiation, and dispute handling while adhering to FDCPA and RBI guidelines.

AI Voice Agents for Debt Collection

Deploy AI voice agents that improve collection rates while maintaining compliance with regulatory requirements. This guide covers payment reminders, arrangement negotiation, payment confirmation, and dispute handling.

Use Cases

Use Case Description Automation Rate
Payment Reminders Proactive outreach for overdue payments 85-95%
Arrangement Negotiation Negotiate payment plans within authorized limits 60-75%
Payment Confirmation Confirm received payments and update accounts 90-98%
Dispute Handling Document disputes and route to specialists 70-85%
Promise-to-Pay Follow-up Follow up on missed payment commitments 80-90%

Agent Configuration

{
  "agent": {
    "name": "Collections Agent",
    "language": "en-IN",

    "llmProvider": "gemini-2.5",
    "llmModel": "gemini-2.5-flash-lite",
    "llmTemperature": 0.4,

    "sttProvider": "deepgram",
    "sttModel": "nova-3",
    "sttConfig": {
      "endpointing": 400,
      "interimResults": true,
      "keywords": ["payment:2", "dispute:2", "EMI:2", "amount:2"]
    },

    "ttsProvider": "azure",
    "ttsVoice": "en-IN-NeerjaNeural",
    "ttsConfig": {
      "rate": "0.95",
      "pitch": "0%"
    },

    "greetingMessage": "Hello, this is a call from {{companyName}} regarding your account. Am I speaking with {{customerName}}?",

    "allowInterruptions": true,
    "interruptionThreshold": 0.6,

    "prompt": "...",

    "tools": [],

    "compliance": {
      "recordingEnabled": true,
      "recordingDisclosure": true,
      "callHoursStart": "08:00",
      "callHoursEnd": "21:00",
      "timezone": "customer_local",
      "maxAttemptsPerDay": 3,
      "maxAttemptsPerWeek": 7
    },

    "webhooks": {
      "url": "https://your-server.com/webhooks/collections",
      "events": ["call.ended", "payment.arranged", "dispute.raised"]
    }
  }
}

System Prompt

You are a professional collections agent for {{companyName}}. Your role is to collect outstanding payments while treating customers with respect and empathy.

## Account Information
- Customer Name: {{customerName}}
- Account Number: {{accountNumber}}
- Outstanding Amount: {{outstandingAmount}}
- Days Past Due: {{daysPastDue}}
- Last Payment: {{lastPaymentDate}} ({{lastPaymentAmount}})
- Minimum Payment: {{minimumPayment}}
- Payment Due Date: {{dueDate}}
- Previous Arrangements: {{previousArrangements}}

## Your Objectives (in order)
1. Verify you're speaking with the right person
2. Inform them of the outstanding balance
3. Understand their situation
4. Collect payment or establish a payment arrangement
5. Document the outcome

## Conversation Flow

### Step 1: Identity Verification
First, confirm you're speaking with the account holder.

"Am I speaking with {{customerName}}?"

If yes, proceed. If no:
"Is {{customerName}} available? I need to speak with them regarding an important account matter."

Do NOT discuss account details with anyone other than the account holder.

### Step 2: Disclosure (Required)
"This call is from {{companyName}} regarding your account and may be recorded for quality assurance. This is an attempt to collect a debt."

### Step 3: State the Purpose
"I'm calling about your account ending in {{accountLast4}}, which currently shows an outstanding balance of {{outstandingAmount}}. This amount was due on {{dueDate}}."

### Step 4: Listen and Respond

#### If they can pay in full:
"That's great. I can help you make that payment right now. Would you like to pay by card or bank transfer?"
→ Use process_payment tool

#### If they need a payment plan:
"I understand. Let me see what options we have available."
→ Check their eligibility and offer arrangements within your authority

#### If they dispute the debt:
"I understand you're disputing this. Let me document the details of your dispute."
→ Use log_dispute tool
"Your dispute has been logged with reference number [X]. You'll receive written confirmation within 5 business days. No collection activity will occur on this account while we investigate."

#### If they claim financial hardship:
"I'm sorry to hear you're going through a difficult time. Let me understand your situation better so we can find a workable solution."
→ Ask about income, expenses, and what they can realistically afford
→ Offer hardship programs if available

### Authorized Payment Arrangements

You can offer the following without supervisor approval:
- Full payment within 7 days: No additional fees
- 2-3 installment plan: Split over 30-90 days
- Reduced settlement: Up to {{settlementAuthority}}% discount for immediate payment

For arrangements beyond these limits:
"Let me check with my supervisor on that option. Can I call you back within 24 hours?"
→ Schedule callback and escalate

## Tone Guidelines
- Professional and firm, but never aggressive
- Empathetic to genuine hardship
- Patient with explanations
- Clear about consequences without threats
- Respectful at all times

## What You MUST Do
- Disclose this is a debt collection call
- Verify identity before discussing details
- Accurately state the amount owed
- Honor disputes and cease collection on disputed accounts
- Provide your callback number
- Respect cease-and-desist requests

## What You MUST NOT Do
- Threaten legal action you cannot take
- Discuss the debt with third parties
- Call outside permitted hours
- Use abusive or harassing language
- Misrepresent the debt amount
- Ignore dispute requests
- Promise to remove accurate credit reporting
- Call after a cease-and-desist request

## If Customer Becomes Hostile
"I understand you're frustrated. My goal is to find a solution that works for you. Would you prefer I call back at a better time?"

If abuse continues:
"I want to help, but I'll need to end this call if we can't have a respectful conversation. Is there a better time to discuss this?"

## Closing
After payment or arrangement:
"Thank you for working with me today. You'll receive confirmation at {{customerEmail}}. Is there anything else I can help with?"

If no resolution:
"I understand. Please keep in mind that the balance of {{outstandingAmount}} remains due. You can reach us at {{callbackNumber}} to make a payment at any time. Have a good day."

Tools

Get Account Details

{
  "type": "function",
  "function": {
    "name": "get_account_details",
    "description": "Retrieve account details and payment history for a customer",
    "parameters": {
      "type": "object",
      "properties": {
        "account_id": {
          "type": "string",
          "description": "The customer account ID"
        },
        "phone": {
          "type": "string",
          "description": "Customer phone number for lookup"
        }
      },
      "required": ["account_id"]
    }
  }
}

Process Payment

{
  "type": "function",
  "function": {
    "name": "process_payment",
    "description": "Process a payment for the outstanding balance",
    "parameters": {
      "type": "object",
      "properties": {
        "account_id": {
          "type": "string",
          "description": "Customer account ID"
        },
        "amount": {
          "type": "number",
          "description": "Payment amount in currency units"
        },
        "payment_method": {
          "type": "string",
          "enum": ["card", "bank_transfer", "upi", "auto_debit"],
          "description": "Payment method"
        },
        "payment_date": {
          "type": "string",
          "description": "Date of payment (ISO 8601)"
        }
      },
      "required": ["account_id", "amount", "payment_method"]
    }
  }
}

Create Payment Arrangement

{
  "type": "function",
  "function": {
    "name": "create_arrangement",
    "description": "Create a payment arrangement or installment plan",
    "parameters": {
      "type": "object",
      "properties": {
        "account_id": {
          "type": "string",
          "description": "Customer account ID"
        },
        "arrangement_type": {
          "type": "string",
          "enum": ["full_payment", "installment", "settlement", "hardship"],
          "description": "Type of arrangement"
        },
        "total_amount": {
          "type": "number",
          "description": "Total amount to be paid"
        },
        "installments": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "amount": { "type": "number" },
              "due_date": { "type": "string" }
            }
          },
          "description": "Installment schedule"
        },
        "first_payment_date": {
          "type": "string",
          "description": "Date of first payment"
        }
      },
      "required": ["account_id", "arrangement_type", "total_amount"]
    }
  }
}

Log Dispute

{
  "type": "function",
  "function": {
    "name": "log_dispute",
    "description": "Log a customer dispute and pause collection activity",
    "parameters": {
      "type": "object",
      "properties": {
        "account_id": {
          "type": "string",
          "description": "Customer account ID"
        },
        "dispute_type": {
          "type": "string",
          "enum": ["not_my_debt", "wrong_amount", "already_paid", "identity_theft", "other"],
          "description": "Type of dispute"
        },
        "dispute_reason": {
          "type": "string",
          "description": "Detailed description of the dispute"
        },
        "supporting_info": {
          "type": "string",
          "description": "Any supporting information provided"
        }
      },
      "required": ["account_id", "dispute_type", "dispute_reason"]
    }
  }
}

Log Promise to Pay

{
  "type": "function",
  "function": {
    "name": "log_promise_to_pay",
    "description": "Record a promise to pay commitment",
    "parameters": {
      "type": "object",
      "properties": {
        "account_id": {
          "type": "string",
          "description": "Customer account ID"
        },
        "promised_amount": {
          "type": "number",
          "description": "Amount customer promised to pay"
        },
        "promised_date": {
          "type": "string",
          "description": "Date customer promised to pay"
        },
        "payment_method": {
          "type": "string",
          "description": "How they plan to pay"
        },
        "follow_up_date": {
          "type": "string",
          "description": "Date to follow up if payment not received"
        }
      },
      "required": ["account_id", "promised_amount", "promised_date"]
    }
  }
}

Transfer to Human

{
  "type": "function",
  "function": {
    "name": "transfer_to_agent",
    "description": "Transfer call to a human collections agent or supervisor",
    "parameters": {
      "type": "object",
      "properties": {
        "account_id": {
          "type": "string",
          "description": "Customer account ID"
        },
        "reason": {
          "type": "string",
          "enum": ["supervisor_request", "complex_negotiation", "legal_threat", "hardship", "escalation"],
          "description": "Reason for transfer"
        },
        "notes": {
          "type": "string",
          "description": "Context for the receiving agent"
        }
      },
      "required": ["account_id", "reason"]
    }
  }
}

Tool Handlers

func handleProcessPayment(params map[string]any) (string, error) {
    accountID := params["account_id"].(string)
    amount := params["amount"].(float64)
    method := params["payment_method"].(string)

    // Validate payment against account balance
    account, err := db.GetAccount(accountID)
    if err != nil {
        return "I'm having trouble accessing your account. Let me transfer you to a colleague.", err
    }

    if amount > account.OutstandingBalance {
        return fmt.Sprintf("The amount of %.2f exceeds your outstanding balance of %.2f. Would you like to pay the full balance?",
            amount, account.OutstandingBalance), nil
    }

    // For immediate card payments
    if method == "card" {
        return "I'll need your card details to process this payment. Please provide the 16-digit card number.", nil
    }

    // For bank transfers and UPI
    if method == "bank_transfer" || method == "upi" {
        paymentRef := generatePaymentReference(accountID)
        return fmt.Sprintf(
            "To complete the bank transfer of %.2f, please use reference number %s. "+
            "Payment details will be sent to your registered mobile. "+
            "The payment will reflect within 24 hours.",
            amount, paymentRef), nil
    }

    return "Payment method not supported", nil
}

func handleCreateArrangement(params map[string]any) (string, error) {
    accountID := params["account_id"].(string)
    arrangementType := params["arrangement_type"].(string)
    totalAmount := params["total_amount"].(float64)

    account, _ := db.GetAccount(accountID)

    // Validate arrangement is within authorized limits
    if !isWithinAuthority(arrangementType, totalAmount, account) {
        return "This arrangement requires supervisor approval. Let me schedule a callback within 24 hours to confirm.", nil
    }

    // Create the arrangement
    arrangement := &Arrangement{
        AccountID:   accountID,
        Type:        arrangementType,
        TotalAmount: totalAmount,
        CreatedAt:   time.Now(),
        Status:      "active",
    }

    if installments, ok := params["installments"].([]any); ok {
        arrangement.Installments = parseInstallments(installments)
    }

    err := db.CreateArrangement(arrangement)
    if err != nil {
        return "I wasn't able to set up the arrangement. Let me transfer you to a colleague who can help.", err
    }

    // Generate confirmation
    confirmationNumber := arrangement.ID[:8]

    // Send confirmation SMS/email
    sendArrangementConfirmation(account, arrangement)

    return fmt.Sprintf(
        "Your payment arrangement has been set up. Confirmation number: %s. "+
        "You'll receive the details via SMS and email. "+
        "Your first payment of %.2f is due on %s.",
        confirmationNumber,
        arrangement.Installments[0].Amount,
        arrangement.Installments[0].DueDate.Format("January 2"),
    ), nil
}

func handleLogDispute(params map[string]any) (string, error) {
    accountID := params["account_id"].(string)
    disputeType := params["dispute_type"].(string)
    reason := params["dispute_reason"].(string)

    dispute := &Dispute{
        AccountID:  accountID,
        Type:       disputeType,
        Reason:     reason,
        Status:     "open",
        CreatedAt:  time.Now(),
    }

    err := db.CreateDispute(dispute)
    if err != nil {
        return "I'm having trouble logging your dispute. Please contact us at our main number.", err
    }

    // Mark account as disputed - stop collections
    db.UpdateAccountStatus(accountID, "disputed")

    // Trigger dispute workflow
    triggerDisputeWorkflow(dispute)

    return fmt.Sprintf(
        "Your dispute has been logged with reference number %s. "+
        "All collection activity on this account is paused while we investigate. "+
        "You'll receive written confirmation within 5 business days, and "+
        "we'll complete our investigation within 30 days as required by law.",
        dispute.ID[:8],
    ), nil
}

Compliance Requirements

FDCPA Compliance (United States)

type FDCPACompliance struct {
    // Time restrictions
    CallHoursStart    int  // 8 AM local time
    CallHoursEnd      int  // 9 PM local time

    // Disclosure requirements
    MiniMirandaRequired bool // Must identify as debt collector

    // Contact restrictions
    HonorCeaseContact   bool // Must stop if requested
    NoWorkplaceCalls    bool // Unless permitted
    NoThirdPartyDisclosure bool // Cannot discuss with others

    // Dispute handling
    VerificationRequired bool // Must verify if disputed
    PauseOnDispute       bool // Must pause collection on dispute
}

func validateFDCPACompliance(call *Call) error {
    // Check calling hours
    localTime := call.Customer.GetLocalTime()
    if localTime.Hour() < 8 || localTime.Hour() >= 21 {
        return errors.New("call outside permitted hours (8 AM - 9 PM local)")
    }

    // Check cease and desist
    if call.Customer.CeaseContactRequested {
        return errors.New("customer has requested no contact")
    }

    // Check dispute status
    if call.Account.DisputeStatus == "open" {
        return errors.New("account has open dispute - collection paused")
    }

    return nil
}

RBI Guidelines (India)

type RBICompliance struct {
    // Time restrictions (RBI Circular 2022)
    CallHoursStart    int  // 8 AM
    CallHoursEnd      int  // 7 PM (stricter than FDCPA)

    // Frequency limits
    MaxCallsPerDay    int  // Maximum 3 calls per day
    MaxCallsPerWeek   int  // Maximum 7 calls per week

    // Disclosure
    AgentIDRequired   bool // Must identify with ID
    CompanyNameRequired bool

    // Language
    LocalLanguageOption bool // Must offer local language

    // Recording
    CallRecordingRequired bool
    RetentionPeriod       int // 2 years minimum
}

func validateRBICompliance(call *Call) error {
    // Check calling hours (8 AM - 7 PM IST)
    ist, _ := time.LoadLocation("Asia/Kolkata")
    localTime := time.Now().In(ist)
    if localTime.Hour() < 8 || localTime.Hour() >= 19 {
        return errors.New("call outside RBI permitted hours (8 AM - 7 PM)")
    }

    // Check daily call frequency
    callsToday := db.GetCallCountToday(call.Customer.Phone)
    if callsToday >= 3 {
        return errors.New("maximum 3 calls per day reached")
    }

    // Check weekly call frequency
    callsThisWeek := db.GetCallCountThisWeek(call.Customer.Phone)
    if callsThisWeek >= 7 {
        return errors.New("maximum 7 calls per week reached")
    }

    return nil
}

Call Recording and Retention

type RecordingConfig struct {
    Enabled           bool
    DisclosureMessage string
    StorageDuration   time.Duration
    EncryptionEnabled bool
    ConsentRequired   bool
}

func setupCompliantRecording(call *Call) error {
    config := RecordingConfig{
        Enabled:           true,
        DisclosureMessage: "This call may be recorded for quality and training purposes.",
        StorageDuration:   2 * 365 * 24 * time.Hour, // 2 years
        EncryptionEnabled: true,
        ConsentRequired:   false, // One-party consent jurisdiction
    }

    // Start recording with disclosure
    if config.Enabled {
        call.RecordingID = startRecording(call.ID)

        // Log recording start for audit
        auditLog.Record(AuditEvent{
            Type:      "recording_started",
            CallID:    call.ID,
            AccountID: call.Account.ID,
            Timestamp: time.Now(),
        })
    }

    return nil
}

Audit Trail

type CollectionAuditLog struct {
    ID          string
    CallID      string
    AccountID   string
    Timestamp   time.Time
    EventType   string
    Details     map[string]any
    AgentID     string
    RecordingID string
}

func logCollectionEvent(event CollectionAuditLog) {
    // Required for compliance
    event.Timestamp = time.Now()

    db.InsertAuditLog(event)

    // Real-time compliance monitoring
    if event.EventType == "dispute_raised" ||
       event.EventType == "cease_contact" ||
       event.EventType == "complaint" {
        alertComplianceTeam(event)
    }
}

Metrics and Analytics

Key Performance Indicators

type CollectionMetrics struct {
    // Contact Metrics
    TotalAttempts        int
    ContactRate          float64 // Percentage of successful contacts
    RightPartyContacts   int     // Reached actual account holder

    // Collection Metrics
    TotalCollected       float64
    CollectionRate       float64 // Amount collected / Amount attempted
    PaymentArrangements  int
    ArrangementValue     float64

    // Quality Metrics
    AverageCallDuration  time.Duration
    DisputeRate          float64
    EscalationRate       float64
    ComplianceScore      float64

    // Promise Metrics
    PromisesToPay        int
    PromiseKeptRate      float64 // Promises fulfilled / Promises made
}

func calculateCollectionMetrics(campaignID string, period time.Duration) *CollectionMetrics {
    calls := db.GetCampaignCalls(campaignID, period)

    metrics := &CollectionMetrics{}

    var totalAttemptedAmount float64
    var totalCollected float64
    var rightPartyContacts int
    var disputes int

    for _, call := range calls {
        metrics.TotalAttempts++
        totalAttemptedAmount += call.Account.OutstandingBalance

        if call.ContactMade {
            if call.RightPartyContact {
                rightPartyContacts++
            }

            if call.PaymentMade {
                totalCollected += call.PaymentAmount
            }

            if call.ArrangementMade {
                metrics.PaymentArrangements++
                metrics.ArrangementValue += call.ArrangementAmount
            }

            if call.DisputeRaised {
                disputes++
            }
        }

        metrics.AverageCallDuration += call.Duration
    }

    // Calculate rates
    if metrics.TotalAttempts > 0 {
        metrics.ContactRate = float64(rightPartyContacts) / float64(metrics.TotalAttempts)
        metrics.AverageCallDuration /= time.Duration(metrics.TotalAttempts)
    }

    if totalAttemptedAmount > 0 {
        metrics.CollectionRate = totalCollected / totalAttemptedAmount
    }

    if rightPartyContacts > 0 {
        metrics.DisputeRate = float64(disputes) / float64(rightPartyContacts)
    }

    metrics.TotalCollected = totalCollected
    metrics.RightPartyContacts = rightPartyContacts

    return metrics
}

Dashboard Metrics

func getCollectionsDashboard(teamID string) *Dashboard {
    today := time.Now().Truncate(24 * time.Hour)

    return &Dashboard{
        // Today's Performance
        TodayStats: TodayStats{
            CallsMade:         db.CountCalls(teamID, today),
            AmountCollected:   db.SumPayments(teamID, today),
            ArrangementsSetup: db.CountArrangements(teamID, today),
            ContactRate:       calculateContactRate(teamID, today),
        },

        // Agent Performance
        AgentMetrics: getAgentMetrics(teamID, today),

        // Account Buckets
        AccountBuckets: []AccountBucket{
            {Name: "0-30 DPD", Count: db.CountAccountsByDPD(0, 30)},
            {Name: "31-60 DPD", Count: db.CountAccountsByDPD(31, 60)},
            {Name: "61-90 DPD", Count: db.CountAccountsByDPD(61, 90)},
            {Name: "90+ DPD", Count: db.CountAccountsByDPD(91, 999)},
        },

        // Compliance
        ComplianceAlerts: getComplianceAlerts(teamID),
    }
}

Promise-to-Pay Tracking

type PromiseToPayMetrics struct {
    TotalPromises     int
    PromisesKept      int
    PromisesBroken    int
    PromisesPending   int
    KeptRate          float64
    AveragePromiseAge time.Duration
}

func trackPromiseToPayMetrics(period time.Duration) *PromiseToPayMetrics {
    promises := db.GetPromises(period)

    metrics := &PromiseToPayMetrics{
        TotalPromises: len(promises),
    }

    for _, p := range promises {
        switch p.Status {
        case "kept":
            metrics.PromisesKept++
        case "broken":
            metrics.PromisesBroken++
        case "pending":
            metrics.PromisesPending++
        }
    }

    if metrics.TotalPromises > 0 {
        metrics.KeptRate = float64(metrics.PromisesKept) /
            float64(metrics.PromisesKept + metrics.PromisesBroken)
    }

    return metrics
}

Campaign Management

Outbound Campaign Setup

func runCollectionsCampaign(campaignID string) {
    campaign, _ := db.GetCampaign(campaignID)
    accounts := db.GetCampaignAccounts(campaignID)

    // Sort by priority (higher DPD, higher balance first)
    sort.Slice(accounts, func(i, j int) bool {
        scoreI := accounts[i].DaysPastDue * int(accounts[i].Balance)
        scoreJ := accounts[j].DaysPastDue * int(accounts[j].Balance)
        return scoreI > scoreJ
    })

    for _, account := range accounts {
        // Pre-call compliance check
        if err := validateCompliance(account); err != nil {
            log.Printf("Skipping %s: %v", account.ID, err)
            continue
        }

        // Check optimal calling time
        if !isOptimalCallTime(account) {
            scheduleForLater(account)
            continue
        }

        // Prepare context
        variables := map[string]string{
            "customerName":        account.CustomerName,
            "accountNumber":       account.ID,
            "accountLast4":        account.ID[len(account.ID)-4:],
            "outstandingAmount":   formatCurrency(account.Balance),
            "daysPastDue":         strconv.Itoa(account.DaysPastDue),
            "minimumPayment":      formatCurrency(account.MinimumPayment),
            "dueDate":             account.DueDate.Format("January 2, 2006"),
            "lastPaymentDate":     account.LastPaymentDate.Format("January 2"),
            "lastPaymentAmount":   formatCurrency(account.LastPaymentAmount),
            "previousArrangements": summarizeArrangements(account.Arrangements),
            "settlementAuthority": strconv.Itoa(campaign.SettlementAuthority),
            "companyName":         campaign.CompanyName,
            "callbackNumber":      campaign.CallbackNumber,
            "customerEmail":       account.Email,
        }

        // Initiate call
        initiateCall(campaign.AgentID, account.Phone, variables)

        // Respect pacing
        time.Sleep(campaign.PacingDelay)
    }
}

API Integration

# Initiate collection call
curl -X POST https://voice-agent.edesy.in/api/v1/calls \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "collections_agent",
    "to": "+919876543210",
    "variables": {
      "customerName": "Rahul Kumar",
      "accountNumber": "ACC-2024-12345",
      "outstandingAmount": "Rs. 15,450",
      "daysPastDue": "45",
      "minimumPayment": "Rs. 5,000",
      "dueDate": "December 15, 2024",
      "companyName": "FinCorp Services"
    },
    "compliance": {
      "record_call": true,
      "disclosure_required": true
    },
    "webhook_url": "https://your-server.com/webhooks/collection-complete"
  }'

Best Practices

1. Right Party Contact Verification

// Always verify identity before discussing account
func verifyIdentity(session *Session) bool {
    // Ask for identifying information
    session.TTS.Speak("For security, could you please confirm the last 4 digits of your PAN card?")

    response := session.WaitForResponse()

    if verifyPAN(session.Account.PAN, response) {
        return true
    }

    // Alternative verification
    session.TTS.Speak("Let me try another verification. What is your date of birth?")
    response = session.WaitForResponse()

    return verifyDOB(session.Account.DOB, response)
}

2. Empathetic Communication

// Phrases that acknowledge customer situation
var empathyPhrases = map[string][]string{
    "financial_hardship": {
        "I understand times can be tough financially.",
        "I appreciate you sharing that with me.",
        "Let's see what options we have to work with your situation.",
    },
    "confusion": {
        "I completely understand this can be confusing.",
        "Let me explain that more clearly.",
        "That's a very fair question.",
    },
    "frustration": {
        "I hear your frustration, and I want to help.",
        "I understand this isn't the call you wanted to receive.",
        "Let's work together to find a solution.",
    },
}

3. Tiered Escalation

type EscalationTier struct {
    Level           int
    AuthorizedDiscount float64
    ArrangementTerms   int // months
    RequiresApproval   bool
}

var escalationTiers = []EscalationTier{
    {Level: 1, AuthorizedDiscount: 0,    ArrangementTerms: 3,  RequiresApproval: false},
    {Level: 2, AuthorizedDiscount: 0.10, ArrangementTerms: 6,  RequiresApproval: false},
    {Level: 3, AuthorizedDiscount: 0.25, ArrangementTerms: 12, RequiresApproval: true},
    {Level: 4, AuthorizedDiscount: 0.50, ArrangementTerms: 24, RequiresApproval: true},
}

func getAuthorizedArrangement(account *Account, requestedDiscount float64) *EscalationTier {
    // Determine tier based on account age, amount, and customer history
    customerScore := calculateCustomerScore(account)

    for _, tier := range escalationTiers {
        if requestedDiscount <= tier.AuthorizedDiscount {
            return &tier
        }
    }

    return nil // Requires supervisor
}

4. Optimal Contact Timing

func determineOptimalContactTime(account *Account) time.Time {
    // Analyze past successful contacts
    successfulContacts := db.GetSuccessfulContacts(account.ID)

    if len(successfulContacts) > 0 {
        // Return time when we've reached them before
        return analyzeSuccessfulTimes(successfulContacts)
    }

    // Default optimal windows by segment
    if account.Segment == "salaried" {
        // Evening after work hours
        return nextTimeInWindow(18, 20, account.Timezone)
    } else if account.Segment == "business" {
        // Late morning
        return nextTimeInWindow(10, 12, account.Timezone)
    }

    // Default: mid-day
    return nextTimeInWindow(11, 14, account.Timezone)
}

5. Follow-up Automation

type FollowUpRule struct {
    Trigger       string
    DelayHours    int
    Action        string
    MaxAttempts   int
}

var followUpRules = []FollowUpRule{
    {Trigger: "promise_to_pay", DelayHours: 24, Action: "reminder_sms", MaxAttempts: 1},
    {Trigger: "arrangement_due", DelayHours: -24, Action: "reminder_call", MaxAttempts: 2},
    {Trigger: "payment_failed", DelayHours: 4, Action: "call", MaxAttempts: 3},
    {Trigger: "no_contact", DelayHours: 48, Action: "retry_call", MaxAttempts: 5},
    {Trigger: "voicemail", DelayHours: 24, Action: "retry_different_time", MaxAttempts: 3},
}

func scheduleFollowUp(account *Account, trigger string) {
    rule := findRule(trigger)
    if rule == nil {
        return
    }

    // Check attempt limits
    attempts := db.GetFollowUpAttempts(account.ID, trigger)
    if attempts >= rule.MaxAttempts {
        log.Printf("Max follow-up attempts reached for %s", account.ID)
        return
    }

    followUpTime := time.Now().Add(time.Duration(rule.DelayHours) * time.Hour)

    db.ScheduleFollowUp(FollowUp{
        AccountID:  account.ID,
        ScheduledAt: followUpTime,
        Action:     rule.Action,
        Trigger:    trigger,
    })
}

Testing

Compliance Test Scenarios

func TestFDCPACompliance(t *testing.T) {
    agent := setupTestAgent()

    // Test calling hours
    t.Run("RejectsCallOutsideHours", func(t *testing.T) {
        call := simulateCall(agent, CallConfig{
            Time: time.Date(2024, 1, 1, 7, 0, 0, 0, time.Local), // 7 AM
        })
        assert.Equal(t, "blocked", call.Status)
        assert.Contains(t, call.BlockReason, "outside permitted hours")
    })

    // Test Mini-Miranda disclosure
    t.Run("IncludesDebtDisclosure", func(t *testing.T) {
        call := simulateCall(agent, CallConfig{
            Time: time.Date(2024, 1, 1, 10, 0, 0, 0, time.Local),
        })
        assert.Contains(t, call.Transcript, "attempt to collect a debt")
    })

    // Test dispute handling
    t.Run("PausesOnDispute", func(t *testing.T) {
        agent.Process("I dispute this debt")
        account := db.GetAccount(testAccountID)
        assert.Equal(t, "disputed", account.Status)
        assert.True(t, agent.ToolCalled("log_dispute"))
    })

    // Test cease contact
    t.Run("HonorsCeaseContact", func(t *testing.T) {
        agent.Process("Stop calling me")
        assert.Contains(t, agent.LastResponse, "won't receive any more calls")
    })
}

Payment Flow Testing

func TestPaymentArrangement(t *testing.T) {
    agent := setupTestAgent()

    t.Run("CreatesValidArrangement", func(t *testing.T) {
        agent.Process("I can pay 5000 rupees now and the rest next month")

        assert.True(t, agent.ToolCalled("create_arrangement"))

        arrangement := db.GetLatestArrangement(testAccountID)
        assert.Equal(t, "installment", arrangement.Type)
        assert.Len(t, arrangement.Installments, 2)
    })

    t.Run("EscalatesOverLimit", func(t *testing.T) {
        agent.Process("I can only pay 30% of the total")

        assert.Contains(t, agent.LastResponse, "supervisor approval")
        assert.False(t, agent.ToolCalled("create_arrangement"))
    })
}

Next Steps

  • Customer Support - General support use cases
  • Call Recording - Recording configuration
  • Function Calling - Tool integration
  • Webhooks - Call completion events
  • Indian Languages - Hindi, Tamil collection agents
Previous
Marketing Campaigns
Next
Overview

On this page

  • Use Cases
  • Agent Configuration
  • System Prompt
  • Account Information
  • Your Objectives (in order)
  • Conversation Flow
  • Step 1: Identity Verification
  • Step 2: Disclosure (Required)
  • Step 3: State the Purpose
  • Step 4: Listen and Respond
  • If they can pay in full:
  • If they need a payment plan:
  • If they dispute the debt:
  • If they claim financial hardship:
  • Authorized Payment Arrangements
  • Tone Guidelines
  • What You MUST Do
  • What You MUST NOT Do
  • If Customer Becomes Hostile
  • Closing
  • Tools
  • Get Account Details
  • Process Payment
  • Create Payment Arrangement
  • Log Dispute
  • Log Promise to Pay
  • Transfer to Human
  • Tool Handlers
  • Compliance Requirements
  • FDCPA Compliance (United States)
  • RBI Guidelines (India)
  • Call Recording and Retention
  • Audit Trail
  • Metrics and Analytics
  • Key Performance Indicators
  • Dashboard Metrics
  • Promise-to-Pay Tracking
  • Campaign Management
  • Outbound Campaign Setup
  • API Integration
  • Best Practices
  • 1. Right Party Contact Verification
  • 2. Empathetic Communication
  • 3. Tiered Escalation
  • 4. Optimal Contact Timing
  • 5. Follow-up Automation
  • Testing
  • Compliance Test Scenarios
  • Payment Flow Testing
  • Next Steps

Stay Updated

Get the latest updates on AI voice technology, product releases, and exclusive resources.

Get Started

Try our products for free
AI Voice Agent
Build voice AI for calls
WhatsApp AI Bot
Automate WhatsApp chats
Website Chatbot
AI chat for websites
Edesy CRM
Manage leads & customers
Book a DemoCall UsEmail Us
Eedesy

Your all-in-one platform for digital innovation. We build AI-powered solutions that transform how businesses operate.

[email protected]+91 95475 31359

Products

  • AI Voice Assistant
  • WhatsApp Voice AI
  • WhatsApp Bot Builder
  • AI Website Chatbot
  • AI-SDR
  • Number Masking
  • Shopify Apps
  • View All Products

Solutions

  • For E-commerce
  • For Healthcare
  • For Real Estate
  • For Restaurants
  • For Appointments
  • View All Use Cases

Services

  • AI Chatbot Development
  • Voice AI Development
  • Shopify Development
  • SaaS Development
  • WhatsApp API Integration
  • View All Services

Resources

  • Documentation
  • Voice Agent Docs
  • API Reference
  • Number Masking API Docs
  • Blog
  • Changelog
  • Book a Demo

Company

  • About Us
  • Contact
  • Careers
  • Privacy Policy
  • Terms of Service

Products

  • AI Voice Assistant
  • WhatsApp Voice AI
  • WhatsApp Bot Builder
  • AI Website Chatbot
  • AI-SDR
  • Number Masking
  • Shopify Apps
  • View All Products

Solutions

  • For E-commerce
  • For Healthcare
  • For Real Estate
  • For Restaurants
  • For Appointments
  • View All Use Cases

Services

  • AI Chatbot Development
  • Voice AI Development
  • Shopify Development
  • SaaS Development
  • WhatsApp API Integration
  • View All Services

Resources

  • Documentation
  • Voice Agent Docs
  • API Reference
  • Number Masking API Docs
  • Blog
  • Changelog
  • Book a Demo

Company

  • About Us
  • Contact
  • Careers
  • Privacy Policy
  • Terms of Service
  • AI Voice Assistant
  • WhatsApp Voice AI
  • WhatsApp Bot Builder
  • AI Website Chatbot
  • AI-SDR
  • Number Masking
  • Shopify Apps
  • View All Products
  • For E-commerce
  • For Healthcare
  • For Real Estate
  • For Restaurants
  • For Appointments
  • View All Use Cases
  • AI Chatbot Development
  • Voice AI Development
  • Shopify Development
  • SaaS Development
  • WhatsApp API Integration
  • View All Services
  • Documentation
  • Voice Agent Docs
  • API Reference
  • Number Masking API Docs
  • Blog
  • Changelog
  • Book a Demo
  • About Us
  • Contact
  • Careers
  • Privacy Policy
  • Terms of Service

Popular Free Tools

Compress PDFMerge PDFPDF to WordGST CalculatorEMI CalculatorSIP CalculatorJSON FormatterBase64 EncoderImage CompressorQR Code GeneratorVoice AI ROI CalculatorAmazon FBA CalculatorAI Email WriterVideo to GIFPrivacy Policy GeneratorCRM ROI CalculatorMeeting Cost Calculator
Categories:PDF ToolsDeveloper ToolsFinance CalculatorsImage ToolsVideo ToolsAI Writing ToolsAudio ToolsWhatsApp ToolsDocument GeneratorsVoice AI ToolsE-commerce ToolsView All Tools

© 2026 Edesy Technology Labs Pvt Ltd

SSL Secured
99.9% Uptime