Financial Services
Deploy AI voice agents for banks, NBFCs, and fintech companies to automate account inquiries, loan servicing, payment reminders, fraud alerts, and KYC verification while maintaining regulatory compliance.
Industry Overview
┌────────────────────────────────────────────────────────────────────────────┐
│ Financial Services Voice Agent │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Account │ │ Loan │ │ Payment │ │ Fraud │ │
│ │ Inquiries │ │ Status │ │ Reminders │ │ Alerts │ │
│ ├─────────────┤ ├─────────────┤ ├─────────────┤ ├─────────────┤ │
│ │ Balance │ │ EMI Details │ │ Due Dates │ │ Transaction │ │
│ │ Mini Stmt │ │ Foreclosure │ │ Overdue │ │ Verification│ │
│ │ Txn History │ │ Documents │ │ Payment │ │ Card Block │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ Compliance Layer │ │
│ │ PCI-DSS │ RBI Guidelines │ SEBI │ IRDAI │ Data Localization │ │
│ └─────────────────────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────────────────────┘
Use Cases
1. Account Balance and Inquiries
Handle account-related queries including balance checks, mini statements, and transaction history.
{
"useCase": "account-inquiry",
"inboundCapabilities": [
"Balance inquiry",
"Last 5 transactions",
"Mini statement request",
"Account freeze status",
"Cheque book request status"
],
"requiredIntegrations": [
"Core Banking System (CBS)",
"Customer Authentication",
"OTP Gateway"
]
}
2. Loan Status and Servicing
Provide loan details, EMI information, foreclosure quotes, and document assistance.
{
"useCase": "loan-servicing",
"capabilities": [
"Outstanding balance",
"EMI due dates and amounts",
"Foreclosure/prepayment quotes",
"Interest certificate requests",
"NOC status after closure",
"Loan restructuring inquiries"
],
"requiredIntegrations": [
"Loan Management System (LMS)",
"Document Management System"
]
}
3. Payment Reminders (Outbound)
Proactive outbound calls for EMI reminders, overdue notifications, and payment confirmations.
{
"useCase": "payment-reminders",
"callTypes": [
{
"type": "pre-due-reminder",
"timing": "3 days before EMI due date",
"goal": "Remind customer of upcoming payment"
},
{
"type": "overdue-reminder",
"timing": "Day 1, Day 7, Day 15 post due date",
"goal": "Collect payment commitment or payment"
},
{
"type": "payment-confirmation",
"timing": "After successful payment",
"goal": "Confirm receipt and next due date"
}
]
}
4. Fraud Alerts and Card Services
Real-time transaction verification and card management.
{
"useCase": "fraud-alerts",
"capabilities": [
"Suspicious transaction verification",
"Card block/unblock",
"PIN reset initiation",
"Temporary card limits",
"Travel notification",
"Dispute filing"
],
"slaRequirements": {
"responseTime": "< 30 seconds for fraud calls",
"availability": "24/7/365"
}
}
5. KYC Verification and Updates
Assist with KYC compliance, document collection, and verification.
{
"useCase": "kyc-verification",
"capabilities": [
"Video KYC scheduling",
"Document upload guidance",
"KYC status check",
"Address update verification",
"Re-KYC reminders",
"PAN/Aadhaar linking assistance"
]
}
Agent Configuration
Complete Financial Services Agent
{
"agent": {
"name": "ICICI Bank Voice Assistant",
"language": "hi-IN",
"fallbackLanguages": ["en-IN"],
"llmProvider": "gemini-2.5",
"llmModel": "gemini-2.5-flash-lite",
"llmTemperature": 0.3,
"sttProvider": "google",
"sttModel": "chirp",
"sttConfig": {
"model": "long",
"languageCode": "hi-IN",
"alternativeLanguageCodes": ["en-IN"],
"enableAutomaticPunctuation": true,
"profanityFilter": true,
"speechContexts": [
{
"phrases": ["EMI", "NEFT", "RTGS", "IMPS", "UPI", "OTP", "CVV", "ATM"],
"boost": 15
},
{
"phrases": ["loan", "balance", "account", "statement", "cheque"],
"boost": 10
}
]
},
"ttsProvider": "azure",
"ttsVoice": "hi-IN-SwaraNeural",
"ttsConfig": {
"speakingRate": 1.0,
"pitch": 0
},
"greetingMessage": "Namaste! ICICI Bank mein aapka swagat hai. Main aapki virtual assistant hoon. Aapka account number ya registered mobile number bataiye.",
"allowInterruptions": true,
"interruptionThreshold": 0.6,
"prompt": "...",
"tools": [],
"securityConfig": {
"requireAuthentication": true,
"authenticationMethods": ["otp", "debit_card_last_4", "dob"],
"maxAuthAttempts": 3,
"sessionTimeout": 300,
"pciMode": true,
"maskSensitiveData": true
},
"webhooks": {
"url": "https://api.bank.com/voice-agent/webhooks",
"events": ["call.started", "call.ended", "auth.success", "auth.failed", "transaction.initiated"],
"headers": {
"X-Bank-API-Key": "{{BANK_API_KEY}}"
}
}
}
}
System Prompt
You are Sia, a professional and helpful voice assistant for ICICI Bank. You assist customers with account inquiries, loan information, and banking services.
## Your Role
- Authenticate customers securely before providing account information
- Help with balance inquiries, transaction history, and statements
- Provide loan details including EMI, outstanding balance, and foreclosure quotes
- Assist with card-related services and fraud alerts
- Never provide financial advice or investment recommendations
## Security Protocol
### Authentication Flow
1. Greet the customer warmly
2. Ask for account number or registered mobile number
3. Send OTP to registered mobile
4. Verify OTP before proceeding
5. If OTP fails 3 times, inform customer to visit branch
### Sensitive Information Handling
- NEVER read out full account numbers (only last 4 digits)
- NEVER mention card CVV or PIN
- NEVER ask for or repeat full card numbers
- For any card number input, use DTMF (keypad) only
- Mask amounts over 1 lakh as "above one lakh rupees"
## Response Guidelines
### Language
- Speak in Hinglish (Hindi-English mix) naturally
- Use formal "aap" form, not "tum"
- Keep responses under 30 words
- Use rupees, not "INR" or symbols
### Tone
- Professional but warm
- Empathetic for payment issues
- Urgent but calm for fraud alerts
- Patient with elderly customers
## Available Functions
- verify_customer: Authenticate via OTP
- get_account_balance: Fetch current balance
- get_mini_statement: Last 5 transactions
- get_loan_details: EMI, outstanding, next due date
- get_foreclosure_quote: Prepayment amount
- block_card: Immediately block debit/credit card
- raise_dispute: File transaction dispute
- schedule_callback: Human agent callback
- transfer_to_agent: Connect to human agent
## Common Scenarios
### Balance Inquiry (after auth)
Customer: "Balance batao"
You: "Aapke savings account ka current balance ek lakh bahattar hazaar rupees hai. Kuch aur help chahiye?"
### Loan EMI Query
Customer: "Meri EMI kitni hai?"
You: "Aapki home loan EMI 45,230 rupees hai, jo har mahine ki 5 tareekh ko debit hoti hai. Next EMI 5 January ko hai."
### Suspicious Transaction
Customer: "Mujhe ek message aaya 50,000 debit ka jo maine nahi kiya"
You: "Main samajh sakti hoon yeh concerning hai. Pehle aapka card block karti hoon. Kya aap confirm karte hain?"
### Card Block Request
Customer: "Card kho gaya hai, block karo"
You: "Aapka card turant block kar deti hoon. Kya aap debit card ya credit card block karna chahte hain?"
## Escalation Rules
Transfer to human agent if:
- Customer requests human 2+ times
- Authentication fails 3 times
- Dispute amount > 50,000 rupees
- Customer is abusive or threatening
- Technical issues prevent service
- Complex loan restructuring queries
## Compliance Reminders
- Always confirm before any transaction
- Read out confirmation numbers slowly
- Remind about SMS confirmation for transactions
- Never pressure for immediate payments
- Respect DND for marketing calls
Function Calling Examples
Customer Authentication
{
"type": "function",
"function": {
"name": "verify_customer",
"description": "Authenticate customer using OTP sent to registered mobile number",
"parameters": {
"type": "object",
"properties": {
"identifier": {
"type": "string",
"description": "Account number or registered mobile number"
},
"identifier_type": {
"type": "string",
"enum": ["account_number", "mobile_number", "customer_id"],
"description": "Type of identifier provided"
}
},
"required": ["identifier", "identifier_type"]
}
}
}
Handler Implementation:
func handleVerifyCustomer(ctx context.Context, params map[string]any) (string, error) {
identifier := params["identifier"].(string)
identifierType := params["identifier_type"].(string)
// Validate identifier format
if identifierType == "mobile_number" && !isValidMobile(identifier) {
return "Mobile number valid nahi lag raha. Kya aap dobara bol sakte hain?", nil
}
// Look up customer
customer, err := cbsClient.FindCustomer(ctx, identifier, identifierType)
if err != nil {
return "Is number se koi account nahi mila. Kya aap account number try karna chahenge?", nil
}
// Send OTP
otpRef, err := otpService.SendOTP(ctx, customer.MobileNumber)
if err != nil {
return "OTP bhejne mein problem hui. Thodi der baad try karein.", nil
}
// Store OTP reference in session
session.Set("otp_ref", otpRef)
session.Set("customer_id", customer.ID)
session.Set("auth_attempts", 0)
maskedMobile := maskMobile(customer.MobileNumber)
return fmt.Sprintf("Aapke registered mobile %s par OTP bheja hai. Kya aap OTP bata sakte hain?", maskedMobile), nil
}
func maskMobile(mobile string) string {
if len(mobile) < 10 {
return "***"
}
return "******" + mobile[len(mobile)-4:]
}
Account Balance Inquiry
{
"type": "function",
"function": {
"name": "get_account_balance",
"description": "Get current balance for customer's account. Requires prior authentication.",
"parameters": {
"type": "object",
"properties": {
"account_type": {
"type": "string",
"enum": ["savings", "current", "loan", "credit_card", "all"],
"description": "Type of account to check balance for"
}
},
"required": []
}
}
}
Handler Implementation:
func handleGetAccountBalance(ctx context.Context, session *Session, params map[string]any) (string, error) {
// Verify authentication
if !session.IsAuthenticated() {
return "Pehle aapko verify karna hoga. Aapka registered mobile number batayein.", nil
}
customerID := session.Get("customer_id").(string)
accountType := params["account_type"]
if accountType == nil {
accountType = "savings"
}
accounts, err := cbsClient.GetAccounts(ctx, customerID, accountType.(string))
if err != nil {
return "Balance check karne mein problem hui. Thodi der baad try karein.", nil
}
if len(accounts) == 0 {
return "Aapke paas is type ka koi account nahi hai.", nil
}
// Format response
var responses []string
for _, acc := range accounts {
maskedAccNum := "******" + acc.Number[len(acc.Number)-4:]
balanceText := formatIndianCurrency(acc.Balance)
responses = append(responses,
fmt.Sprintf("%s account %s ka balance %s hai",
acc.Type, maskedAccNum, balanceText))
}
// Audit log
auditLogger.Log(ctx, AuditEvent{
Action: "balance_inquiry",
CustomerID: customerID,
Details: map[string]any{"account_type": accountType},
})
return strings.Join(responses, ". "), nil
}
func formatIndianCurrency(amount float64) string {
if amount >= 10000000 { // 1 crore+
return fmt.Sprintf("%.2f crore rupees", amount/10000000)
} else if amount >= 100000 { // 1 lakh+
return fmt.Sprintf("%.2f lakh rupees", amount/100000)
} else if amount >= 1000 {
return fmt.Sprintf("%.0f hazaar rupees", amount/1000)
}
return fmt.Sprintf("%.0f rupees", amount)
}
Loan Details Inquiry
{
"type": "function",
"function": {
"name": "get_loan_details",
"description": "Get loan account details including EMI, outstanding balance, and next due date",
"parameters": {
"type": "object",
"properties": {
"loan_account_number": {
"type": "string",
"description": "Loan account number (optional if customer has single loan)"
},
"detail_type": {
"type": "string",
"enum": ["summary", "emi_schedule", "payment_history", "foreclosure"],
"description": "Type of detail requested"
}
},
"required": []
}
}
}
Handler Implementation:
func handleGetLoanDetails(ctx context.Context, session *Session, params map[string]any) (string, error) {
if !session.IsAuthenticated() {
return "Pehle verification zaroori hai. OTP ke liye mobile number batayein.", nil
}
customerID := session.Get("customer_id").(string)
detailType := getStringParam(params, "detail_type", "summary")
loans, err := lmsClient.GetLoans(ctx, customerID)
if err != nil || len(loans) == 0 {
return "Aapke naam par koi active loan nahi mila.", nil
}
loan := loans[0] // Primary loan, or use loan_account_number if provided
switch detailType {
case "summary":
return formatLoanSummary(loan), nil
case "emi_schedule":
return formatEMISchedule(loan), nil
case "foreclosure":
quote, _ := lmsClient.GetForeclosureQuote(ctx, loan.ID)
return formatForeclosureQuote(loan, quote), nil
default:
return formatLoanSummary(loan), nil
}
}
func formatLoanSummary(loan *Loan) string {
return fmt.Sprintf(
"Aapka %s loan: EMI %s, outstanding %s, next EMI %s ko due hai. Total %d EMIs baaki hain.",
loan.Type,
formatIndianCurrency(loan.EMIAmount),
formatIndianCurrency(loan.OutstandingPrincipal),
loan.NextDueDate.Format("2 January"),
loan.RemainingTenure,
)
}
Block Card (Fraud Response)
{
"type": "function",
"function": {
"name": "block_card",
"description": "Immediately block a debit or credit card. Use for lost/stolen cards or suspected fraud.",
"parameters": {
"type": "object",
"properties": {
"card_type": {
"type": "string",
"enum": ["debit", "credit"],
"description": "Type of card to block"
},
"card_last_4": {
"type": "string",
"description": "Last 4 digits of card number for confirmation"
},
"reason": {
"type": "string",
"enum": ["lost", "stolen", "fraud", "damaged", "other"],
"description": "Reason for blocking"
}
},
"required": ["card_type", "reason"]
}
}
}
Handler Implementation:
func handleBlockCard(ctx context.Context, session *Session, params map[string]any) (string, error) {
if !session.IsAuthenticated() {
return "Card block karne ke liye pehle verification zaroori hai.", nil
}
customerID := session.Get("customer_id").(string)
cardType := params["card_type"].(string)
reason := params["reason"].(string)
// Get customer's cards
cards, err := cardService.GetCards(ctx, customerID, cardType)
if err != nil || len(cards) == 0 {
return fmt.Sprintf("Aapke naam par koi %s card nahi mila.", cardType), nil
}
card := cards[0]
// Immediate block - high priority
result, err := cardService.BlockCard(ctx, card.ID, reason)
if err != nil {
// Critical failure - escalate
return "Card block karne mein technical issue hai. Main aapko senior agent se connect karti hoon. Hold karein.", nil
}
// Send confirmation SMS
smsService.Send(ctx, session.Get("mobile").(string),
fmt.Sprintf("Your %s card ending %s has been blocked. Ref: %s",
cardType, card.Last4, result.ReferenceNumber))
// High-priority audit
auditLogger.Log(ctx, AuditEvent{
Action: "card_blocked",
CustomerID: customerID,
Priority: "HIGH",
Details: map[string]any{
"card_type": cardType,
"reason": reason,
"reference": result.ReferenceNumber,
},
})
return fmt.Sprintf(
"Aapka %s card ending %s turant block kar diya gaya hai. Reference number %s. Aapko SMS bhi aayega. Naya card ke liye branch visit karein ya net banking se apply karein.",
cardType, card.Last4, result.ReferenceNumber,
), nil
}
Payment Reminder (Outbound)
{
"type": "function",
"function": {
"name": "record_payment_commitment",
"description": "Record customer's commitment to pay EMI with date and amount",
"parameters": {
"type": "object",
"properties": {
"commitment_date": {
"type": "string",
"description": "Date customer commits to pay (ISO format or natural language)"
},
"amount": {
"type": "number",
"description": "Amount customer commits to pay"
},
"payment_mode": {
"type": "string",
"enum": ["upi", "neft", "cheque", "cash_deposit", "auto_debit"],
"description": "How customer plans to pay"
},
"reason_for_delay": {
"type": "string",
"description": "Customer's reason for payment delay (if overdue)"
}
},
"required": ["commitment_date", "amount"]
}
}
}
Compliance Considerations
PCI-DSS Compliance
For handling card data (card numbers, CVV, PIN):
type PCICompliantHandler struct {
dtmfCollector *DTMFCollector
tokenizer *CardTokenizer
recording *Recorder
auditLog *AuditLogger
}
// Collect card number via DTMF only - never voice
func (h *PCICompliantHandler) CollectCardNumber(ctx context.Context, session *Session) (string, error) {
// 1. Pause recording before collecting sensitive data
h.recording.Pause()
defer h.recording.Resume()
// 2. Mute STT to prevent transcription of spoken numbers
session.MuteSTT()
defer session.UnmuteSTT()
// 3. Prompt for DTMF input
session.TTS.Speak("Apne card ka 16 digit number phone ke keypad se enter karein, phir hash press karein.")
// 4. Collect DTMF with timeout
digits, err := h.dtmfCollector.Collect(ctx, DTMFConfig{
MaxDigits: 16,
Timeout: 60 * time.Second,
TerminatingDigit: "#",
})
if err != nil {
return "", fmt.Errorf("card collection failed: %w", err)
}
// 5. Validate card number (Luhn check)
if !isValidCardNumber(digits) {
return "", ErrInvalidCardNumber
}
// 6. Immediately tokenize - never store raw PAN
token, err := h.tokenizer.Tokenize(ctx, digits)
if err != nil {
return "", err
}
// 7. Audit log (token only, not PAN)
h.auditLog.Log(ctx, AuditEvent{
Action: "card_tokenized",
Details: map[string]any{"token_prefix": token[:8]},
})
// Clear digits from memory
for i := range digits {
digits = digits[:i] + "0" + digits[i+1:]
}
return token, nil
}
RBI Guidelines Compliance
type RBIComplianceConfig struct {
// Call timing restrictions
AllowedCallHours TimeRange // 9 AM to 6 PM
AllowedCallDays []string // Mon-Sat, no Sundays
// Collection call restrictions
MaxCallsPerDay int // Max 3 calls per day for collections
MinGapBetweenCalls time.Duration // Min 4 hours between calls
// Customer protection
DNDRespect bool // Honor DND registry
ConsentRequired bool // Require explicit consent
LanguageChoice bool // Allow customer to choose language
// Recording and disclosure
CallRecordingDisclosure bool // Inform about call recording
AgentIdentification bool // Must identify as AI/automated
// Data protection
DataLocalization bool // Store data in India only
RetentionPeriod time.Duration // 7 years for financial records
}
func (c *RBIComplianceConfig) CanMakeOutboundCall(customer *Customer, callType string) (bool, string) {
now := time.Now().In(istLocation)
// Check time restrictions
if !c.AllowedCallHours.Contains(now) {
return false, "Outside allowed calling hours (9 AM - 6 PM IST)"
}
// Check day restrictions
if now.Weekday() == time.Sunday {
return false, "Calls not allowed on Sundays"
}
// Check DND
if c.DNDRespect && customer.IsDND && callType == "marketing" {
return false, "Customer registered on DND"
}
// Check daily call limit for collections
if callType == "collection" {
todayCalls := getCallCount(customer.ID, today())
if todayCalls >= c.MaxCallsPerDay {
return false, "Daily call limit reached"
}
lastCall := getLastCallTime(customer.ID)
if time.Since(lastCall) < c.MinGapBetweenCalls {
return false, "Minimum gap between calls not met"
}
}
return true, ""
}
SEBI and IRDAI Considerations
For investment and insurance-related calls:
// Investment disclaimer (SEBI requirement)
const investmentDisclaimer = `Mutual fund investments are subject to market risks.
Please read all scheme related documents carefully before investing.
Past performance is not indicative of future returns.`
// Insurance disclaimer (IRDAI requirement)
const insuranceDisclaimer = `Insurance is the subject matter of solicitation.
For more details on risk factors, terms and conditions,
please read the sales brochure carefully before concluding the sale.`
func (a *FinancialAgent) handleInvestmentQuery(ctx context.Context, query string) string {
response := a.llm.Generate(ctx, query)
// Always append disclaimer for investment queries
if containsInvestmentTopic(query) {
response += "\n\n" + investmentDisclaimer
}
return response
}
Data Localization
type DataLocalizationConfig struct {
// Primary storage in India
PrimaryRegion string // "ap-south-1" (Mumbai)
// Allowed processing regions
AllowedRegions []string // Only Indian regions
// Data that must stay in India
LocalizedData []string // ["customer_pii", "financial_records", "call_recordings"]
// Cross-border data transfer rules
AllowCrossBorder bool // false for financial data
}
func (s *Storage) Save(ctx context.Context, data interface{}) error {
dataType := getDataType(data)
// Check if data must be localized
if s.config.requiresLocalization(dataType) {
if s.currentRegion != s.config.PrimaryRegion {
return fmt.Errorf("data type %s must be stored in %s",
dataType, s.config.PrimaryRegion)
}
}
return s.store.Save(ctx, data)
}
ROI Metrics and Cost Analysis
Cost Comparison
| Metric | Human Agent | AI Voice Agent | Savings |
|---|---|---|---|
| Cost per call | Rs 25-35 | Rs 3-5 | 85-90% |
| Calls per hour | 8-12 | Unlimited | - |
| Availability | 8-10 hours | 24/7 | 3x |
| Training time | 2-4 weeks | Instant | - |
| Consistency | Variable | 100% | - |
Volume-Based ROI Calculator
interface FinancialROIMetrics {
// Input metrics
monthlyCallVolume: number;
averageCallDuration: number; // minutes
humanAgentCostPerMinute: number; // INR
aiAgentCostPerMinute: number; // INR
// Output metrics
monthlySavings: number;
annualSavings: number;
roiPercentage: number;
paybackPeriodMonths: number;
}
function calculateFinancialServicesROI(
monthlyVolume: number,
avgDuration: number = 3,
humanCost: number = 8, // INR per minute
implementationCost: number = 500000 // INR
): FinancialROIMetrics {
// AI cost breakdown
const sttCostPerMin = 0.35; // Deepgram
const llmCostPerMin = 0.05; // Gemini 2.5 Flash
const ttsCostPerMin = 0.25; // Cartesia
const telephonyCostPerMin = 0.50; // Exotel
const aiAgentCostPerMinute = sttCostPerMin + llmCostPerMin + ttsCostPerMin + telephonyCostPerMin;
const totalMinutesPerMonth = monthlyVolume * avgDuration;
const humanMonthlyCost = totalMinutesPerMonth * humanCost;
const aiMonthlyCost = totalMinutesPerMonth * aiAgentCostPerMinute;
const monthlySavings = humanMonthlyCost - aiMonthlyCost;
const annualSavings = monthlySavings * 12;
const roiPercentage = ((annualSavings - implementationCost) / implementationCost) * 100;
const paybackPeriodMonths = implementationCost / monthlySavings;
return {
monthlyCallVolume: monthlyVolume,
averageCallDuration: avgDuration,
humanAgentCostPerMinute: humanCost,
aiAgentCostPerMinute: aiAgentCostPerMinute,
monthlySavings,
annualSavings,
roiPercentage,
paybackPeriodMonths,
};
}
// Example: Mid-size NBFC
const nbfcROI = calculateFinancialServicesROI(
50000, // 50K calls/month
3.5, // 3.5 min avg duration
8, // Rs 8/min human cost
500000 // Rs 5L implementation
);
// Results:
// Monthly savings: Rs 12.1L
// Annual savings: Rs 1.45Cr
// ROI: 2800%
// Payback: < 1 month
Key Performance Indicators
| KPI | Target | Measurement |
|---|---|---|
| Authentication Success Rate | > 95% | OTP verified / OTP sent |
| First Call Resolution | > 80% | Issues resolved without escalation |
| Average Handle Time | < 3 min | Total call duration |
| Customer Satisfaction (CSAT) | > 4.2/5 | Post-call survey |
| Escalation Rate | < 15% | Transfers to human agent |
| Collection Promise-to-Pay | > 40% | Commitments obtained |
| Collection Kept Rate | > 70% | Commitments honored |
Best Practices
1. Multi-Factor Authentication Flow
type AuthenticationFlow struct {
methods []AuthMethod
maxAttempts int
lockoutDuration time.Duration
}
type AuthMethod struct {
Name string
Priority int
Handler func(ctx context.Context, session *Session) (bool, error)
}
func (f *AuthenticationFlow) Authenticate(ctx context.Context, session *Session) error {
attempts := 0
for _, method := range f.methods {
for attempts < f.maxAttempts {
// Request authentication
session.TTS.Speak(method.Prompt)
success, err := method.Handler(ctx, session)
if err != nil {
return err
}
if success {
session.SetAuthenticated(true)
auditLogger.Log(ctx, AuditEvent{
Action: "auth_success",
Method: method.Name,
Details: map[string]any{"attempts": attempts + 1},
})
return nil
}
attempts++
session.TTS.Speak("Yeh match nahi hua. Dobara try karein.")
}
}
// Lock account after max attempts
session.TTS.Speak("Bahut zyada galat attempts. Security ke liye aap 30 minute baad try kar sakte hain, ya branch visit karein.")
return ErrMaxAuthAttemptsExceeded
}
2. Graceful Degradation
func (a *FinancialAgent) handleWithFallback(ctx context.Context, query string) string {
// Try primary CBS
response, err := a.cbsClient.Query(ctx, query)
if err == nil {
return response
}
// CBS down - try cache
if cached := a.cache.Get(query); cached != nil {
return cached.(string) + " (Yeh information thodi purani ho sakti hai.)"
}
// Complete failure - graceful message
return `Abhi humare systems mein technical issue hai.
Main aapka callback schedule kar sakti hoon, ya aap thodi der baad call kar sakte hain.
Kya callback schedule karein?`
}
3. Secure Session Management
type SecureSession struct {
ID string
CustomerID string
AuthenticatedAt time.Time
ExpiresAt time.Time
IPAddress string
AuthMethod string
AccessedData []string
mutex sync.RWMutex
}
func (s *SecureSession) IsValid() bool {
s.mutex.RLock()
defer s.mutex.RUnlock()
if time.Now().After(s.ExpiresAt) {
return false
}
return true
}
func (s *SecureSession) RecordDataAccess(dataType string) {
s.mutex.Lock()
defer s.mutex.Unlock()
s.AccessedData = append(s.AccessedData, fmt.Sprintf("%s:%s",
dataType, time.Now().Format(time.RFC3339)))
}
func (s *SecureSession) EndSession() {
auditLogger.Log(context.Background(), AuditEvent{
Action: "session_ended",
CustomerID: s.CustomerID,
Details: map[string]any{
"duration": time.Since(s.AuthenticatedAt).Seconds(),
"data_accessed": s.AccessedData,
"auth_method": s.AuthMethod,
},
})
}
4. Conversation Logging with PII Redaction
type ComplianceLogger struct {
redactor *PIIRedactor
storage Storage
}
func (l *ComplianceLogger) LogConversation(call *Call) error {
// Redact PII from transcript
redactedTranscript := make([]Turn, len(call.Transcript))
for i, turn := range call.Transcript {
redactedTranscript[i] = Turn{
Role: turn.Role,
Content: l.redactor.Redact(turn.Content),
Timestamp: turn.Timestamp,
}
}
// Store redacted version
return l.storage.Save(CallLog{
CallID: call.ID,
CustomerID: call.CustomerID,
Transcript: redactedTranscript,
Duration: call.Duration,
Outcome: call.Outcome,
AgentID: call.AgentID,
RecordingRef: call.EncryptedRecordingRef,
CreatedAt: time.Now(),
})
}
5. Language-Aware Financial Terms
var financialTermsHindi = map[string]string{
"balance": "balance / shesh raashi",
"EMI": "EMI / maasik kist",
"principal": "mool dhan",
"interest": "byaaj",
"outstanding": "baaki raashi",
"foreclosure": "prepayment / samay se pehle bhugtaan",
"statement": "statement / khata vivaran",
"transaction": "len-den",
}
func localizeFinancialTerm(term, language string) string {
if language == "hi-IN" {
if localized, ok := financialTermsHindi[term]; ok {
return localized
}
}
return term
}
Integration Architecture
┌────────────────────────────────────────────────────────────────────────────┐
│ Voice Agent Platform │
└─────────────────────────────────┬──────────────────────────────────────────┘
│
┌────────────────────────┼────────────────────────┐
│ │ │
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ CBS / Core │ │ Loan │ │ Card │
│ Banking System │ │ Management │ │ Management │
│ │ │ System │ │ System │
│ • Balance │ │ • EMI details │ │ • Block/Unblock │
│ • Transactions │ │ • Outstanding │ │ • Limits │
│ • Statements │ │ • Foreclosure │ │ • Disputes │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │ │
└────────────────────────┼────────────────────────┘
│
┌────────────────────────┼────────────────────────┐
│ │ │
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ OTP Gateway │ │ CRM / │ │ Compliance │
│ │ │ Ticketing │ │ Reporting │
│ • SMS OTP │ │ • Lead capture │ │ • RBI reports │
│ • WhatsApp OTP │ │ • Complaint log │ │ • Audit trails │
│ • Voice OTP │ │ • Follow-ups │ │ • Call logs │
└─────────────────┘ └─────────────────┘ └─────────────────┘
Next Steps
- Security Best Practices - Detailed security implementation
- Function Calling - Tool integration patterns
- Call Transfer - Human handoff for escalations
- Hindi Language Support - Hindi voice configuration
- Outbound Sales - Outbound calling patterns