Customer support escalation system

Build intelligent support routing using assistants that escalate calls based on customer tier, issue complexity, and agent expertise.

Overview

Build an intelligent customer support escalation system that determines transfer destinations dynamically using customer tier analysis, issue complexity assessment, and real-time agent availability. This approach uses transfer tools with empty destinations and webhook servers for maximum escalation flexibility.

Agent Capabilities:

  • Customer tier-based prioritization and routing
  • Issue complexity analysis for specialist routing
  • Real-time agent availability and expertise matching
  • Intelligent escalation with context preservation

What You’ll Build:

  • Transfer tool with dynamic escalation logic
  • Assistant with intelligent support conversation flow
  • Webhook server for escalation destination logic
  • CRM integration for customer tier-based routing

Prerequisites

  • A Vapi account
  • Node.js or Python server environment
  • (Optional) CRM or customer database for tier lookup

Scenario

We will build a customer support escalation system for TechCorp that intelligently routes support calls based on customer tier, issue complexity, and agent expertise in real-time.


1. Create a Dynamic Escalation Tool

2

Create the escalation tool

  • Click Create Tool
  • Select Transfer Call as the tool type
  • Set tool name: Smart Support Escalation
  • Important: Leave the destinations array empty - this creates a dynamic transfer tool
  • Set function name: escalateToSupport
  • Add description: Escalate calls to appropriate support specialists based on customer tier and issue complexity
3

Configure tool parameters

Add these parameters to help the assistant provide context:

  • issue_category (string): Category of customer issue (technical, billing, account, product)
  • complexity_level (string): Issue complexity (basic, intermediate, advanced, critical)
  • customer_context (string): Relevant customer information for routing
  • escalation_reason (string): Why this needs escalation vs self-service

2. Create an Assistant with Smart Escalation

1

Create assistant

  • Navigate to Assistants in your dashboard
  • Click Create Assistant
  • Name: TechCorp Support Assistant
  • Add your dynamic escalation tool to the assistant’s tools
2

Configure system prompt

System Prompt
You are TechCorp's intelligent customer support assistant. Your job is to:
1. Help customers resolve issues when possible
2. Assess issue complexity and customer needs
3. Escalate to human specialists when appropriate using the escalateToSupport function
Try to resolve simple issues first. For complex issues or when customers request human help, escalate intelligently based on:
- Issue category (technical, billing, account, product)
- Complexity level (basic, intermediate, advanced, critical)
- Customer context and history
Always be professional and efficient in your support.
3

Enable server events

In assistant settings, enable the transfer-destination-request server event. This sends webhooks to your server when escalations are triggered.

4

Set server URL

Configure your server URL to handle escalation requests (e.g., https://your-app.com/webhook/escalation)


3. Build Escalation Logic Server

1import express from 'express';
2import crypto from 'crypto';
3
4const app = express();
5app.use(express.json());
6
7// Webhook secret verification
8function verifyWebhookSignature(payload: string, signature: string) {
9 const expectedSignature = crypto
10 .createHmac('sha256', process.env.WEBHOOK_SECRET!)
11 .update(payload)
12 .digest('hex');
13 return crypto.timingSafeEqual(
14 Buffer.from(signature),
15 Buffer.from(expectedSignature)
16 );
17}
18
19// Support escalation logic
20function determineSupportDestination(request: any) {
21 const { functionCall, call, customer } = request;
22 const { issue_category, complexity_level, customer_context, escalation_reason } = functionCall.parameters;
23
24 // Simulate customer tier lookup
25 const customerData = lookupCustomerTier(customer.number);
26
27 // Enterprise customer escalation
28 if (customerData?.tier === 'enterprise' || complexity_level === 'critical') {
29 return {
30 type: "number",
31 number: "+1-555-ENTERPRISE-SUPPORT",
32 message: "Connecting you to our enterprise support specialist.",
33 transferPlan: {
34 mode: "warm-transfer-say-summary",
35 summaryPlan: {
36 enabled: true,
37 messages: [
38 {
39 role: "system",
40 content: "Provide a summary for the enterprise support specialist."
41 },
42 {
43 role: "user",
44 content: `Enterprise customer with ${issue_category} issue. Complexity: ${complexity_level}. Reason: ${escalation_reason}. Context: ${customer_context}`
45 }
46 ]
47 }
48 }
49 };
50 }
51
52 // Advanced technical issues
53 if (issue_category === 'technical' && (complexity_level === 'advanced' || complexity_level === 'intermediate')) {
54 return {
55 type: "number",
56 number: "+1-555-TECH-SPECIALISTS",
57 message: "Transferring you to our technical support specialists.",
58 transferPlan: {
59 mode: "warm-transfer-say-message",
60 message: `Technical ${complexity_level} issue. Customer context: ${customer_context}. Escalation reason: ${escalation_reason}`
61 }
62 };
63 }
64
65 // Billing and account specialists
66 if (issue_category === 'billing' || issue_category === 'account') {
67 return {
68 type: "number",
69 number: "+1-555-BILLING-TEAM",
70 message: "Connecting you with our billing and account specialists.",
71 transferPlan: {
72 mode: "warm-transfer-say-message",
73 message: `${issue_category} issue, complexity ${complexity_level}. Context: ${customer_context}`
74 }
75 };
76 }
77
78 // Product and feature questions
79 if (issue_category === 'product') {
80 return {
81 type: "number",
82 number: "+1-555-PRODUCT-SUPPORT",
83 message: "Transferring you to our product specialists.",
84 transferPlan: {
85 mode: "warm-transfer-say-message",
86 message: `Product ${complexity_level} inquiry. Context: ${customer_context}`
87 }
88 };
89 }
90
91 // Default to general support
92 return {
93 type: "number",
94 number: "+1-555-GENERAL-SUPPORT",
95 message: "Connecting you with our support team.",
96 transferPlan: {
97 mode: "warm-transfer-say-message",
98 message: `General ${issue_category} support needed. Level: ${complexity_level}`
99 }
100 };
101}
102
103// Simulate customer tier lookup
104function lookupCustomerTier(phoneNumber: string) {
105 // In production, integrate with your actual CRM
106 const mockCustomerData = {
107 "+1234567890": { tier: "enterprise", account: "TechCorp Enterprise" },
108 "+0987654321": { tier: "standard", account: "Basic Plan" },
109 "+1111111111": { tier: "premium", account: "Premium Support" }
110 };
111 return mockCustomerData[phoneNumber];
112}
113
114// Support escalation webhook
115app.post('/webhook/escalation', (req, res) => {
116 try {
117 const signature = req.headers['x-vapi-signature'] as string;
118 const payload = JSON.stringify(req.body);
119
120 // Verify webhook signature
121 if (!verifyWebhookSignature(payload, signature)) {
122 return res.status(401).json({ error: 'Invalid signature' });
123 }
124
125 const request = req.body;
126
127 // Only handle transfer destination requests
128 if (request.type !== 'transfer-destination-request') {
129 return res.status(200).json({ received: true });
130 }
131
132 // Determine destination based on escalation context
133 const destination = determineSupportDestination(request);
134
135 res.json({ destination });
136 } catch (error) {
137 console.error('Escalation webhook error:', error);
138 res.status(500).json({
139 error: 'Unable to determine escalation destination. Please try again.'
140 });
141 }
142});
143
144app.listen(3000, () => {
145 console.log('Support escalation server running on port 3000');
146});

4. Test Your Support Escalation System

1

Create a phone number

  • Navigate to Phone Numbers in your dashboard
  • Click Create Phone Number
  • Assign your support assistant to the number
  • Configure any additional settings
2

Test different escalation scenarios

Call your number and test various scenarios:

  • Basic technical questions (should try to resolve first)
  • Complex billing issues from enterprise customers
  • Advanced technical problems requiring specialists
  • Critical issues requiring immediate escalation
3

Monitor escalation patterns

Check your server logs to see:

  • Escalation requests received
  • Customer tier classifications
  • Destination routing decisions
  • Any errors or routing issues

Advanced Integration Examples

CRM Integration (Salesforce)

1// Example: Salesforce CRM integration for customer tier lookup
2async function lookupCustomerInSalesforce(phoneNumber: string) {
3 const salesforce = new SalesforceAPI({
4 clientId: process.env.SALESFORCE_CLIENT_ID,
5 clientSecret: process.env.SALESFORCE_CLIENT_SECRET,
6 redirectUri: process.env.SALESFORCE_REDIRECT_URI
7 });
8
9 try {
10 const customer = await salesforce.query(`
11 SELECT Id, Account.Type, Support_Tier__c, Case_Count__c, Contract_Level__c
12 FROM Contact
13 WHERE Phone = '${phoneNumber}'
14 `);
15
16 return customer.records[0];
17 } catch (error) {
18 console.error('Salesforce lookup failed:', error);
19 return null;
20 }
21}

Issue Complexity Assessment

1function assessIssueComplexity(issueDescription: string, customerHistory: any) {
2 const complexKeywords = ['api', 'integration', 'custom', 'enterprise', 'migration'];
3 const criticalKeywords = ['down', 'outage', 'critical', 'urgent', 'emergency'];
4
5 const hasComplexKeywords = complexKeywords.some(keyword =>
6 issueDescription.toLowerCase().includes(keyword)
7 );
8
9 const hasCriticalKeywords = criticalKeywords.some(keyword =>
10 issueDescription.toLowerCase().includes(keyword)
11 );
12
13 if (hasCriticalKeywords || customerHistory.previousEscalations > 2) {
14 return 'critical';
15 }
16
17 if (hasComplexKeywords || customerHistory.tier === 'enterprise') {
18 return 'advanced';
19 }
20
21 return 'basic';
22}

Agent Availability Checking

1function getAvailableSpecialist(category: string, complexity: string) {
2 const specialists = getSpecialistsByCategory(category);
3 const qualifiedAgents = specialists.filter(agent =>
4 agent.complexityLevel >= complexity && agent.isAvailable
5 );
6
7 if (qualifiedAgents.length === 0) {
8 return {
9 type: "number",
10 number: "+1-555-QUEUE-CALLBACK",
11 message: "All specialists are busy. You'll be added to our priority queue.",
12 transferPlan: {
13 mode: "warm-transfer-say-message",
14 message: `${category} ${complexity} issue - customer needs callback when specialist available`
15 }
16 };
17 }
18
19 // Return least busy qualified agent
20 const bestAgent = qualifiedAgents.sort(
21 (a, b) => a.activeCallCount - b.activeCallCount
22 )[0];
23
24 return {
25 type: "number",
26 number: bestAgent.phoneNumber,
27 message: `Connecting you to ${bestAgent.name}, our ${category} specialist.`,
28 transferPlan: {
29 mode: "warm-transfer-say-summary",
30 summaryPlan: {
31 enabled: true,
32 messages: [
33 {
34 role: "system",
35 content: `Provide a summary for ${bestAgent.name}`
36 }
37 ]
38 }
39 }
40 };
41}

Error Handling Best Practices

Comprehensive Error Handling

1function handleEscalationError(error: any, context: any) {
2 console.error('Support escalation error:', error);
3
4 // Log escalation details for debugging
5 console.error('Escalation context:', {
6 phoneNumber: context.customer?.number,
7 issueCategory: context.functionCall?.parameters?.issue_category,
8 complexityLevel: context.functionCall?.parameters?.complexity_level,
9 timestamp: new Date().toISOString()
10 });
11
12 // Return fallback destination
13 return {
14 type: "number",
15 number: process.env.FALLBACK_SUPPORT_NUMBER,
16 message: "I'll connect you with our general support team who can help you.",
17 transferPlan: {
18 mode: "warm-transfer-say-message",
19 message: "Escalation routing error - connecting to general support team"
20 }
21 };
22}

Queue Management

1async function getEscalationWithQueueManagement(context: any) {
2 try {
3 const queueStatus = await checkSupportQueueStatus();
4 const destination = await determineEscalationDestination(context);
5
6 // Add queue time estimate if available
7 if (queueStatus.estimatedWaitTime > 5) {
8 destination.message += ` Current wait time is approximately ${queueStatus.estimatedWaitTime} minutes.`;
9 }
10
11 return destination;
12 } catch (error) {
13 return handleEscalationError(error, context);
14 }
15}

Next Steps

You’ve built a sophisticated customer support escalation system using assistants! Consider these enhancements: