|
| 1 | +This guide explains how to enhance your VAPI voice assistant by dynamically incorporating customer-specific information into conversations. |
| 2 | +By implementing this feature, your voice AI can reference personal details, or account information during calls, |
| 3 | +creating a personalized experience that leaves customers feeling understood and valued. |
| 4 | + |
| 5 | +## Understanding the Personalization Flow |
| 6 | + |
| 7 | +When a customer calls your VAPI phone number, here's what happens: |
| 8 | + |
| 9 | +1. VAPI receives the incoming call and identifies the destination phone number |
| 10 | +2. Instead of using a hardcoded assistant, VAPI sends a request to your server |
| 11 | +3. Your server identifies the caller, retrieves their information, and returns either: |
| 12 | + - An existing assistant ID with dynamic variable values, or |
| 13 | + - A complete transient assistant configuration with embedded customer data |
| 14 | +4. VAPI processes this response and handles the call using the personalized assistant |
| 15 | +5. The customer experiences a conversation tailored specifically to them |
| 16 | + |
| 17 | +This dynamic approach enables you to deliver personalized experiences without creating a separate assistant for each customer. Let's explore how to implement each piece of this system. |
| 18 | + |
| 19 | +## Prerequisites |
| 20 | + |
| 21 | +- A phone number (either purchased through VAPI or imported) |
| 22 | +- A created VAPI Assistant (for the existing assistant approach) |
| 23 | +- A server endpoint that can receive VAPI's requests |
| 24 | + |
| 25 | +## Understanding Dynamic Variables |
| 26 | + |
| 27 | +At the heart of this feature is VAPI's template variable system, which allows you to insert placeholders in your assistant's instructions that get replaced with real customer data at runtime. |
| 28 | + |
| 29 | +### Variable Syntax |
| 30 | + |
| 31 | +``` |
| 32 | +{{variable_name}} |
| 33 | +``` |
| 34 | + |
| 35 | +**Important:** Use exactly this format without additional characters. Any deviation will break the functionality. |
| 36 | + |
| 37 | +## Implementation |
| 38 | + |
| 39 | +### 1. Adding Dynamic Variables to Your Assistant |
| 40 | + |
| 41 | +First, you need to prepare your assistant to accept dynamic information by adding variable placeholders to its instructions. |
| 42 | + |
| 43 | +1. Navigate to the Assistants section in your VAPI dashboard |
| 44 | +2. Edit your existing assistant |
| 45 | +3. In the system instructions, include variables using the `{{variable_name}}` syntax |
| 46 | + - Example: "Hello {{customerName}}! I see you've been a {{accountType}} customer since {{joinDate}}." |
| 47 | +4. Save your assistant and note its ID - you'll need this ID in your server implementation |
| 48 | + |
| 49 | +Why this matters: These variables serve as placeholders that will be replaced with actual customer data when a call is received. Without these placeholders, your assistant would deliver the same generic experience to every caller. |
| 50 | + |
| 51 | +### 2. Configuring Your Phone Number |
| 52 | + |
| 53 | +Next, you need to configure your phone number to use your server instead of a hardcoded assistant. This is what enables the dynamic assistant selection process. |
| 54 | + |
| 55 | + |
| 56 | +#### API Method: |
| 57 | + |
| 58 | +```javascript |
| 59 | +PATCH /phone-number/{id} |
| 60 | +{ |
| 61 | + "assistantId": null, |
| 62 | + "squadId": null, |
| 63 | + "server": { |
| 64 | + "url": "https://your-server.com/api/assistant-selector" |
| 65 | + } |
| 66 | +} |
| 67 | +``` |
| 68 | + |
| 69 | +**Note:** The server timeout is fixed at 7.5 seconds by default and cannot be configured. |
| 70 | + |
| 71 | +Why this matters: By removing the hardcoded assistant and adding a server URL, you're telling VAPI to ask your server what assistant to use for each call. This is what transforms a static assistant into a dynamic, personalized experience. |
| 72 | + |
| 73 | +### 3. Implementing Your Server Endpoint |
| 74 | + |
| 75 | +Now for the crucial part - your server endpoint that will receive call information and return a personalized assistant configuration. When someone calls your VAPI number, VAPI will make an HTTP POST request to your server URL with information about the call, including the caller's phone number. |
| 76 | + |
| 77 | +Your endpoint needs to: |
| 78 | + |
| 79 | +1. Verify it's an assistant request from VAPI |
| 80 | +2. Extract the caller's phone number |
| 81 | +3. Look up the customer in your system (CRM, database, etc.) |
| 82 | +4. Return either a pre-created assistant with variables or a complete assistant configuration |
| 83 | + |
| 84 | +You have two approaches for personalizing the call: |
| 85 | + |
| 86 | +#### Method 1: Returning an Existing Assistant with Variable Overrides |
| 87 | + |
| 88 | +This approach is ideal when you want to maintain your assistant configuration in the VAPI dashboard while dynamically injecting customer-specific information: |
| 89 | + |
| 90 | +```javascript |
| 91 | +app.post("/api/assistant-selector", async (req, res) => { |
| 92 | + // Verify this is an assistant request from VAPI |
| 93 | + // This structure comes from the ServerMessage class in message.types.ts |
| 94 | + if (req.body.message && req.body.message.type === "assistant-request") { |
| 95 | + try { |
| 96 | + // Extract caller information from the request |
| 97 | + const callDetails = req.body.call; |
| 98 | + const phoneNumber = callDetails.from.phoneNumber; |
| 99 | + |
| 100 | + // Look up customer in your CRM or database |
| 101 | + const customer = await crmAPI.getCustomerByPhone(phoneNumber); |
| 102 | + |
| 103 | + // Return your pre-created assistant ID with personalized variables |
| 104 | + // This follows the AssistantRequestMessageResponse structure |
| 105 | + res.json({ |
| 106 | + assistantId: "asst_customersupport", // ID of your pre-created assistant |
| 107 | + assistantOverrides: { |
| 108 | + variableValues: { |
| 109 | + customerName: customer.name, |
| 110 | + accountType: customer.tier, |
| 111 | + joinDate: customer.createdAt, |
| 112 | + openTickets: customer.tickets.filter((t) => t.status === "open") |
| 113 | + .length, |
| 114 | + }, |
| 115 | + }, |
| 116 | + }); |
| 117 | + } catch (error) { |
| 118 | + // Return error response - this will be spoken to the customer |
| 119 | + res.json({ |
| 120 | + error: "Customer lookup failed. Please try again later.", |
| 121 | + }); |
| 122 | + } |
| 123 | + } else { |
| 124 | + res.status(400).json({ |
| 125 | + error: "Invalid request type", |
| 126 | + }); |
| 127 | + } |
| 128 | +}); |
| 129 | +``` |
| 130 | + |
| 131 | +Why this matters: This method lets you maintain a single assistant template in the VAPI dashboard while injecting customer-specific data at runtime. The variables in your assistant's instructions will be replaced with the values you provide in `variableValues`. |
| 132 | + |
| 133 | +#### Method 2: Returning a Complete Transient Assistant |
| 134 | + |
| 135 | +This approach gives you maximum flexibility by constructing the entire assistant configuration on the fly: |
| 136 | + |
| 137 | +```javascript |
| 138 | +app.post("/api/assistant-selector", async (req, res) => { |
| 139 | + // Verify this is an assistant request from VAPI |
| 140 | + // This structure comes from the ServerMessage class in message.types.ts |
| 141 | + if (req.body.message && req.body.message.type === "assistant-request") { |
| 142 | + try { |
| 143 | + // Extract caller information from the request |
| 144 | + const callDetails = req.body.call; |
| 145 | + const phoneNumber = callDetails.from.phoneNumber; |
| 146 | + |
| 147 | + // Look up customer in your CRM or database |
| 148 | + const customer = await crmAPI.getCustomerByPhone(phoneNumber); |
| 149 | + |
| 150 | + // Return a complete transient assistant configuration |
| 151 | + // This follows the CreateAssistantDTO structure from assistant.types.ts |
| 152 | + res.json({ |
| 153 | + assistant: { |
| 154 | + name: "Dynamic Customer Support Assistant", |
| 155 | + model: { |
| 156 | + provider: "openai", |
| 157 | + model: "gpt-4o", |
| 158 | + messages: [ |
| 159 | + { |
| 160 | + role: "system", |
| 161 | + content: `You are a helpful customer support agent for TechCo. |
| 162 | + The customer's name is ${customer.name} and they are a |
| 163 | + ${customer.tier} member since ${customer.createdAt}.`, |
| 164 | + }, |
| 165 | + ], |
| 166 | + }, |
| 167 | + voice: { |
| 168 | + provider: "11labs", |
| 169 | + voiceId: "shimmer", |
| 170 | + }, |
| 171 | + }, |
| 172 | + }); |
| 173 | + } catch (error) { |
| 174 | + // Return error response - this will be spoken to the customer |
| 175 | + res.json({ |
| 176 | + error: "Customer lookup failed. Please try again later.", |
| 177 | + }); |
| 178 | + } |
| 179 | + } else { |
| 180 | + res.status(400).json({ |
| 181 | + error: "Invalid request type", |
| 182 | + }); |
| 183 | + } |
| 184 | +}); |
| 185 | +``` |
| 186 | + |
| 187 | +Why this matters: This method gives you complete control over the assistant configuration for each call. Instead of relying on a pre-created assistant, you're building the entire assistant from scratch for each caller, which can be useful for highly customized experiences or when your assistant configuration itself needs to vary by customer. |
| 188 | + |
| 189 | +## What Happens During a Call |
| 190 | + |
| 191 | +Let's walk through what happens when a call comes in: |
| 192 | + |
| 193 | +1. Customer dials your VAPI phone number |
| 194 | +2. VAPI receives the call and identifies which phone number was called |
| 195 | +3. VAPI checks the phone number configuration and sees it has a server URL |
| 196 | +4. VAPI sends a POST request to your server URL with details about the call, including the caller's phone number |
| 197 | +5. Your server receives this request and looks up the customer in your system |
| 198 | +6. Your server returns either an existing assistant ID with variable values or a complete assistant configuration |
| 199 | +7. VAPI processes this response and initializes the assistant with the personalized information |
| 200 | +8. The call proceeds with the personalized assistant handling the conversation |
| 201 | + |
| 202 | +This entire process happens in seconds, creating a seamless experience for your caller while delivering personalized service. |
| 203 | + |
| 204 | +## Technical Constraints |
| 205 | + |
| 206 | +### Response Time |
| 207 | + |
| 208 | +Your server endpoint must return a response within 7.5 seconds. If your endpoint takes longer, VAPI will time out and the call will fall back to default behavior. |
| 209 | + |
| 210 | +### Error Handling |
| 211 | + |
| 212 | +If you need to return an error response for an assistant request, use the following format: |
| 213 | + |
| 214 | +```json |
| 215 | +{ |
| 216 | + "error": "Unable to find customer record. Please try again later." |
| 217 | +} |
| 218 | +``` |
| 219 | + |
| 220 | +This error message will be spoken to the customer, and the call will be ended. |
| 221 | + |
| 222 | +## Troubleshooting |
| 223 | + |
| 224 | +### Common Issues |
| 225 | + |
| 226 | +- **Variables not resolving:** Check for exact syntax: `{{variable_name}}` |
| 227 | +- **Timeout errors:** Optimize database queries; consider caching frequent lookups |
| 228 | +- **Missing customer data:** Implement fallbacks for each variable |
| 229 | +- **Call failures:** Ensure your endpoint has high availability and proper error handling |
0 commit comments