From 9ad3557372683df08f621d8bf36e0d66e5c982a0 Mon Sep 17 00:00:00 2001 From: Stephen Smith Date: Thu, 24 Sep 2026 14:35:00 -0700 Subject: [PATCH] updated examples to use different tools --- fern/assistants/examples/inbound-support.mdx | 786 ++++++++---------- .../examples/multilingual-agent.mdx | 777 ++++++++--------- fern/openai-realtime.mdx | 130 +-- fern/server-url/server-authentication.mdx | 6 +- .../multilingual-support/customers.csv | 24 +- 5 files changed, 840 insertions(+), 883 deletions(-) diff --git a/fern/assistants/examples/inbound-support.mdx b/fern/assistants/examples/inbound-support.mdx index fd97222a1..11479a9df 100644 --- a/fern/assistants/examples/inbound-support.mdx +++ b/fern/assistants/examples/inbound-support.mdx @@ -1,33 +1,43 @@ --- title: Inbound customer support -subtitle: Build a banking customer support agent that can process inbound phone calls and assist with common banking issues +subtitle: Build an inbound support demo that answers questions from sample account and transaction files slug: assistants/examples/inbound-support -description: Build a voice AI banking support agent with tools for account lookup, balance and transaction retrieval. +description: Build a Vapi inbound support demo with a Query tool and sample CSV files, then configure prompts and test account, balance, and transaction retrieval. --- + +Use only the supplied sample data or other fictional records. Matching a name and phone digits is not identity verification, and this example does not enforce account-level authorization. + + ## Overview -Build a banking support agent with function tools and CSV knowledge bases. The agent handles account verification, balance inquiries, and transaction history via phone calls. +A [Query tool](/knowledge-base/using-query-tool) retrieves information from uploaded files. In this demo, one Query tool uses both CSV files to answer questions about sample accounts, balances, and transactions. You don't need a custom server or a `tool-calls` webhook handler. + +**Demo capabilities:** -**Agent Capabilities:** -* Account lookup and verification via phone number -* Balance and transaction history retrieval +* Find a sample account by name and the last four phone digits. +* Read a balance and summarize transactions from the uploaded files. -**What You'll Build:** -* Retrieval tools and CSV knowledge bases for account/transaction data -* Inbound phone number configuration for 24/7 availability +**What you'll build:** + +* One Query tool with a knowledge base containing both CSV files. +* An assistant and inbound phone number for testing the support conversation. ## Prerequisites * A [Vapi account](https://dashboard.vapi.ai/). +* A Vapi private API key for the API examples. Set the `VAPI_API_KEY` environment variable to this key. Run the examples on your server or local machine, not in browser code. +* Install `@vapi-ai/server-sdk` version 2.0.1 for TypeScript or the `requests` package for Python. The cURL model-update examples also use `jq`. + +Replace `YOUR_ASSISTANT_ID` and the file and tool ID placeholders with IDs from your Vapi account. ## Scenario -We will be creating a customer support agent for VapiBank, a bank that wants to provide 24/7 support to consumers. +VapiBank is a fictional bank. The CSV files are a fixed snapshot for this demo, not a connection to live banking data. --- -## 1. Create a Knowledge Base +## 1. Upload the sample files @@ -43,18 +53,20 @@ We will be creating a customer support agent for VapiBank, a bank that wants to - 1. Navigate to **Files** in your [Vapi Dashboard](https://dashboard.vapi.ai/) - 2. Click **Choose file** and upload both `accounts.csv` and `transactions.csv` - 3. Note the file IDs for use in creating tools + 1. Navigate to **Files** in your [Vapi Dashboard](https://dashboard.vapi.ai/). + 2. Click **Choose file** and upload both `accounts.csv` and `transactions.csv`. + 3. Note the file IDs for use in creating the Query tool. - + ```typescript import { VapiClient } from "@vapi-ai/server-sdk"; import fs from 'fs'; - const vapi = new VapiClient({ token: "YOUR_VAPI_API_KEY" }); + const apiKey = process.env.VAPI_API_KEY; + if (!apiKey) throw new Error("Set VAPI_API_KEY to your Vapi private API key"); + const vapi = new VapiClient({ token: apiKey }); async function uploadFile(filePath: string) { try { @@ -78,17 +90,19 @@ We will be creating a customer support agent for VapiBank, a bank that wants to console.log(`Transactions file ID: ${transactionsFile.id}`); ``` - + ```python + import os import requests def upload_file(file_path): url = "https://api.vapi.ai/file" - headers = {"Authorization": f"Bearer {YOUR_VAPI_API_KEY}"} + headers = {"Authorization": f"Bearer {os.environ['VAPI_API_KEY']}"} with open(file_path, 'rb') as file: files = {'file': file} - response = requests.post(url, headers=headers, files=files) + response = requests.post(url, headers=headers, files=files, timeout=30) + response.raise_for_status() return response.json() # Upload both files @@ -99,16 +113,16 @@ We will be creating a customer support agent for VapiBank, a bank that wants to print(f"Transactions file ID: {transactions_file['id']}") ``` - + ```bash # Upload accounts.csv - curl -X POST https://api.vapi.ai/file \ - -H "Authorization: Bearer YOUR_VAPI_API_KEY" \ + curl --fail -X POST https://api.vapi.ai/file \ + -H "Authorization: Bearer $VAPI_API_KEY" \ -F "file=@accounts.csv" # Upload transactions.csv - curl -X POST https://api.vapi.ai/file \ - -H "Authorization: Bearer YOUR_VAPI_API_KEY" \ + curl --fail -X POST https://api.vapi.ai/file \ + -H "Authorization: Bearer $VAPI_API_KEY" \ -F "file=@transactions.csv" ``` @@ -135,13 +149,15 @@ We will be creating a customer support agent for VapiBank, a bank that wants to - + ```typescript import { VapiClient } from "@vapi-ai/server-sdk"; - const vapi = new VapiClient({ token: "YOUR_VAPI_API_KEY" }); + const apiKey = process.env.VAPI_API_KEY; + if (!apiKey) throw new Error("Set VAPI_API_KEY to your Vapi private API key"); + const vapi = new VapiClient({ token: apiKey }); - const systemPrompt = `You are Tom, a friendly VapiBank customer support assistant. Help customers check balances and view recent transactions. Always verify identity with phone number first.`; + const systemPrompt = `You are Tom, a friendly VapiBank customer support assistant. Help callers explore sample balances and transactions. Use fictional records only; do not treat a name or phone digits as identity verification.`; const assistant = await vapi.assistants.create({ name: "Tom", @@ -165,17 +181,18 @@ We will be creating a customer support agent for VapiBank, a bank that wants to console.log(`Assistant created with ID: ${assistant.id}`); ``` - + ```python + import os import requests url = "https://api.vapi.ai/assistant" headers = { - "Authorization": f"Bearer {YOUR_VAPI_API_KEY}", + "Authorization": f"Bearer {os.environ['VAPI_API_KEY']}", "Content-Type": "application/json" } - system_prompt = "You are Tom, a friendly VapiBank customer support assistant. Help customers check balances and view recent transactions. Always verify identity with phone number first." + system_prompt = "You are Tom, a friendly VapiBank customer support assistant. Help callers explore sample balances and transactions. Use fictional records only; do not treat a name or phone digits as identity verification." data = { "name": "Tom", @@ -196,15 +213,16 @@ We will be creating a customer support agent for VapiBank, a bank that wants to } } - response = requests.post(url, headers=headers, json=data) + response = requests.post(url, headers=headers, json=data, timeout=30) + response.raise_for_status() assistant = response.json() print(f"Assistant created with ID: {assistant['id']}") ``` - + ```bash - curl -X POST https://api.vapi.ai/assistant \ - -H "Authorization: Bearer YOUR_VAPI_API_KEY" \ + curl --fail -X POST https://api.vapi.ai/assistant \ + -H "Authorization: Bearer $VAPI_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Tom", @@ -215,7 +233,7 @@ We will be creating a customer support agent for VapiBank, a bank that wants to "messages": [ { "role": "system", - "content": "You are Tom, a friendly VapiBank customer support assistant. Help customers check balances and view recent transactions. Always verify identity with phone number first." + "content": "You are Tom, a friendly VapiBank customer support assistant. Help callers explore sample balances and transactions. Use fictional records only; do not treat a name or phone digits as identity verification." } ] }, @@ -242,26 +260,30 @@ We will be creating a customer support agent for VapiBank, a bank that wants to Hello, you've reached VapiBank customer support! My name is Tom, how may I assist you today? ``` - + ```typescript import { VapiClient } from "@vapi-ai/server-sdk"; - const vapi = new VapiClient({ token: "YOUR_VAPI_API_KEY" }); + const apiKey = process.env.VAPI_API_KEY; + if (!apiKey) throw new Error("Set VAPI_API_KEY to your Vapi private API key"); + const vapi = new VapiClient({ token: apiKey }); - const updatedAssistant = await vapi.assistants.update("YOUR_ASSISTANT_ID", { + const updatedAssistant = await vapi.assistants.update({ + id: "YOUR_ASSISTANT_ID", firstMessage: "Hello, you've reached VapiBank customer support! My name is Tom, how may I assist you today?" }); console.log("First message updated successfully"); ``` - + ```python + import os import requests - url = f"https://api.vapi.ai/assistant/{YOUR_ASSISTANT_ID}" + url = "https://api.vapi.ai/assistant/YOUR_ASSISTANT_ID" headers = { - "Authorization": f"Bearer {YOUR_VAPI_API_KEY}", + "Authorization": f"Bearer {os.environ['VAPI_API_KEY']}", "Content-Type": "application/json" } @@ -269,15 +291,16 @@ We will be creating a customer support agent for VapiBank, a bank that wants to "firstMessage": "Hello, you've reached VapiBank customer support! My name is Tom, how may I assist you today?" } - response = requests.patch(url, headers=headers, json=data) + response = requests.patch(url, headers=headers, json=data, timeout=30) + response.raise_for_status() assistant = response.json() print("First message updated successfully") ``` - + ```bash - curl -X PATCH https://api.vapi.ai/assistant/YOUR_ASSISTANT_ID \ - -H "Authorization: Bearer YOUR_VAPI_API_KEY" \ + curl --fail -X PATCH https://api.vapi.ai/assistant/YOUR_ASSISTANT_ID \ + -H "Authorization: Bearer $VAPI_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "firstMessage": "Hello, you'\''ve reached VapiBank customer support! My name is Tom, how may I assist you today?" @@ -290,75 +313,68 @@ We will be creating a customer support agent for VapiBank, a bank that wants to First, create this system prompt: ```txt title="System Prompt" maxLines=10 -# VapiBank - Phone Support Agent Prompt - -## Identity & Purpose -You are **Tom**, VapiBank's friendly, 24x7 phone-support voice assistant. Do not introduce yourself after the first message. -You help customers with account inquiries: - -1. **Check balance** -2. **View recent transactions** - -## Data Sources -You have access to CSV files with account and transaction data: -- **accounts.csv**: `account_id, name, phone_last4, balance, card_status, email` -- **transactions.csv**: transaction history for all accounts - -## Available Tools -1. **lookup_account** → verify customer identity using phone number -2. **get_balance** → returns current balance for verified account -3. **get_recent_transactions** → returns recent transaction history - -## Conversation Flow -1. **Greeting** - > "Hello, you've reached VapiBank customer support! My name is Tom, how may I assist you today?" - -2. **Account Verification** - * After caller provides phone digits → call **lookup_account** - * Read back the returned `name` for confirmation - * If no match after 2 tries → apologize and offer to transfer - -3. **Handle Request** - Ask: "How can I help you today—check your balance or review recent transactions?" - - **Balance** → call **get_balance** → read current balance - **Transactions** → call **get_recent_transactions** → summarize recent activity - -4. **Close** - > "Is there anything else I can help you with today?" - If no → thank the caller and end the call - -## Style & Tone -* Warm, concise, ≤ 30 words per reply -* One question at a time -* Repeat important numbers slowly and clearly -* Professional but friendly tone - -## Edge Cases -* **No account match** → offer to transfer to human agent -* **Multiple requests** → handle each request, then ask if anything else needed -* **Technical issues** → apologize and offer callback or transfer - -(Remember: only share account information with verified account holders.) +# VapiBank - Phone Support Demo + +## Identity and purpose +You are Tom, a friendly VapiBank support assistant in a demo with fictional data. +Do not introduce yourself again after the first message. +Help callers find a sample account, read its stored balance, and review its transactions. + +## Data and tool +Use defaultQueryTool with knowledgeBaseNames set to ["bank_records"] before answering a question about account data. +The bank_records knowledge base contains both accounts.csv and transactions.csv. +accounts.csv contains account_id, name, phone_last4, balance, card_status, and email. +transactions.csv contains account_id, date, description, and amount. +These files are a snapshot, not live banking data. Never describe a returned balance as a live balance. + +## Conversation flow +1. Ask for the name on the sample account and the last four phone digits. Ask one question at a time. +2. Call defaultQueryTool to find a sample account matching both values. +3. Use only a returned account whose name and phone_last4 match the supplied details. + If the result is missing, ambiguous, or mismatched, ask for clarification. Do not guess or disclose another record. +4. For a balance question, call defaultQueryTool and report the matching account's balance from the file. +5. For a transaction question, call defaultQueryTool and use only transactions with the matching account_id. + Summarize up to three returned transactions, newest date first. Do not invent missing transactions. +6. If the caller changes the account details, repeat the lookup and ignore results for the previous account. +7. When finished, ask whether the caller needs anything else, then thank them and say goodbye. + +## Limits and failures +This lookup does not authenticate the caller or authorize access to real accounts. +If a lookup fails or the result is unclear, say that you could not retrieve the requested information. +Do not interpret a failed lookup as a zero balance or no transactions. +Do not claim to transfer the call, arrange a callback, change an account, or move money. Those actions are not configured. + +## Style +Be warm and concise. Aim for no more than 30 words per reply. +Read important numbers slowly and clearly. ``` - Then update your assistant: + Then update your assistant. In the TypeScript and Python examples, replace the abbreviated prompt with the complete prompt above. + + When updating `model` through the API, retrieve its current configuration first and preserve the fields you are not changing: Copy the system prompt above and paste it into the `System Prompt` field in your assistant configuration. - + ```typescript import { VapiClient } from "@vapi-ai/server-sdk"; - const vapi = new VapiClient({ token: "YOUR_VAPI_API_KEY" }); + const apiKey = process.env.VAPI_API_KEY; + if (!apiKey) throw new Error("Set VAPI_API_KEY to your Vapi private API key"); + const vapi = new VapiClient({ token: apiKey }); // Use the system prompt from above - const systemPrompt = `# VapiBank - Phone Support Agent Prompt...`; + const systemPrompt = `# VapiBank - Phone Support Demo...`; + + const assistant = await vapi.assistants.get({ id: "YOUR_ASSISTANT_ID" }); + if (!assistant.model) throw new Error("Assistant has no model configuration"); - const updatedAssistant = await vapi.assistants.update("YOUR_ASSISTANT_ID", { + const updatedAssistant = await vapi.assistants.update({ + id: assistant.id, model: { + ...assistant.model, messages: [ { role: "system", @@ -371,21 +387,27 @@ You have access to CSV files with account and transaction data: console.log("System prompt updated successfully"); ``` - + ```python + import os import requests - url = f"https://api.vapi.ai/assistant/{YOUR_ASSISTANT_ID}" + url = "https://api.vapi.ai/assistant/YOUR_ASSISTANT_ID" headers = { - "Authorization": f"Bearer {YOUR_VAPI_API_KEY}", + "Authorization": f"Bearer {os.environ['VAPI_API_KEY']}", "Content-Type": "application/json" } # Use the system prompt from above - system_prompt = """# VapiBank - Phone Support Agent Prompt...""" + system_prompt = """# VapiBank - Phone Support Demo...""" + + current_response = requests.get(url, headers=headers, timeout=30) + current_response.raise_for_status() + current_model = current_response.json()["model"] data = { "model": { + **current_model, "messages": [ { "role": "system", @@ -395,26 +417,23 @@ You have access to CSV files with account and transaction data: } } - response = requests.patch(url, headers=headers, json=data) + response = requests.patch(url, headers=headers, json=data, timeout=30) + response.raise_for_status() assistant = response.json() print("System prompt updated successfully") ``` - + ```bash - curl -X PATCH https://api.vapi.ai/assistant/YOUR_ASSISTANT_ID \ - -H "Authorization: Bearer YOUR_VAPI_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "model": { - "messages": [ - { - "role": "system", - "content": "# VapiBank - Phone Support Agent Prompt\n\n## Identity & Purpose\nYou are **Tom**, VapiBank'\''s friendly, 24x7 phone-support voice assistant. Do not introduce yourself after the first message.\nYou help customers with account inquiries:\n\n1. **Check balance**\n2. **View recent transactions**\n\n## Data Sources\nYou have access to CSV files with account and transaction data:\n- **accounts.csv**: account_id, name, phone_last4, balance, card_status, email\n- **transactions.csv**: transaction history for all accounts\n\n## Available Tools\n1. **lookup_account** → verify customer identity using phone number\n2. **get_balance** → returns current balance for verified account\n3. **get_recent_transactions** → returns recent transaction history\n\n## Conversation Flow\n1. **Greeting**\n > \"Hello, you'\''ve reached VapiBank customer support! My name is Tom, how may I assist you today?\"\n\n2. **Account Verification**\n * After caller provides phone digits → call **lookup_account**\n * Read back the returned name for confirmation\n * If no match after 2 tries → apologize and offer to transfer\n\n3. **Handle Request**\n Ask: \"How can I help you today—check your balance or review recent transactions?\"\n\n **Balance** → call **get_balance** → read current balance\n **Transactions** → call **get_recent_transactions** → summarize recent activity\n\n4. **Close**\n > \"Is there anything else I can help you with today?\"\n If no → thank the caller and end the call\n\n## Style & Tone\n* Warm, concise, ≤ 30 words per reply\n* One question at a time\n* Repeat important numbers slowly and clearly\n* Professional but friendly tone\n\n## Edge Cases\n* **No account match** → offer to transfer to human agent\n* **Multiple requests** → handle each request, then ask if anything else needed\n* **Technical issues** → apologize and offer callback or transfer\n\n(Remember: only share account information with verified account holders.)" - } - ] - } - }' + current_assistant=$(curl --fail https://api.vapi.ai/assistant/YOUR_ASSISTANT_ID \ + -H "Authorization: Bearer $VAPI_API_KEY") && + assistant_update=$(jq -e --argjson changes '{"messages":[{"role":"system","content":"# VapiBank - Phone Support Demo\n\n## Identity and purpose\nYou are Tom, a friendly VapiBank support assistant in a demo with fictional data.\nDo not introduce yourself again after the first message.\nHelp callers find a sample account, read its stored balance, and review its transactions.\n\n## Data and tool\nUse defaultQueryTool with knowledgeBaseNames set to [\"bank_records\"] before answering a question about account data.\nThe bank_records knowledge base contains both accounts.csv and transactions.csv.\naccounts.csv contains account_id, name, phone_last4, balance, card_status, and email.\ntransactions.csv contains account_id, date, description, and amount.\nThese files are a snapshot, not live banking data. Never describe a returned balance as a live balance.\n\n## Conversation flow\n1. Ask for the name on the sample account and the last four phone digits. Ask one question at a time.\n2. Call defaultQueryTool to find a sample account matching both values.\n3. Use only a returned account whose name and phone_last4 match the supplied details.\n If the result is missing, ambiguous, or mismatched, ask for clarification. Do not guess or disclose another record.\n4. For a balance question, call defaultQueryTool and report the matching account'\''s balance from the file.\n5. For a transaction question, call defaultQueryTool and use only transactions with the matching account_id.\n Summarize up to three returned transactions, newest date first. Do not invent missing transactions.\n6. If the caller changes the account details, repeat the lookup and ignore results for the previous account.\n7. When finished, ask whether the caller needs anything else, then thank them and say goodbye.\n\n## Limits and failures\nThis lookup does not authenticate the caller or authorize access to real accounts.\nIf a lookup fails or the result is unclear, say that you could not retrieve the requested information.\nDo not interpret a failed lookup as a zero balance or no transactions.\nDo not claim to transfer the call, arrange a callback, change an account, or move money. Those actions are not configured.\n\n## Style\nBe warm and concise. Aim for no more than 30 words per reply.\nRead important numbers slowly and clearly."}]}' \ + 'if (.model | type) != "object" then error("Assistant has no model configuration") else {model: (.model + $changes)} end' \ + <<< "$current_assistant") && + curl --fail -X PATCH https://api.vapi.ai/assistant/YOUR_ASSISTANT_ID \ + -H "Authorization: Bearer $VAPI_API_KEY" \ + -H "Content-Type: application/json" \ + --data "$assistant_update" ``` @@ -424,28 +443,28 @@ You have access to CSV files with account and transaction data: Configure the LLM settings to your liking. - Select any provider and model you like (you will see cost and latency estimates). - - You can configure the files available to the LLM as knowledge base. - You can specify the temperature and max tokens of the LLM. - + ```typescript import { VapiClient } from "@vapi-ai/server-sdk"; - const vapi = new VapiClient({ token: "YOUR_VAPI_API_KEY" }); + const apiKey = process.env.VAPI_API_KEY; + if (!apiKey) throw new Error("Set VAPI_API_KEY to your Vapi private API key"); + const vapi = new VapiClient({ token: apiKey }); async function updateAssistantLLMSettings(assistantId: string) { - const updatedAssistant = await vapi.assistants.update(assistantId, { + const currentAssistant = await vapi.assistants.get({ id: assistantId }); + if (!currentAssistant.model) throw new Error("Assistant has no model configuration"); + + const updatedAssistant = await vapi.assistants.update({ + id: assistantId, model: { + ...currentAssistant.model, provider: "openai", model: "gpt-4o", temperature: 0.7, - maxTokens: 150, - messages: [ - { - role: "system", - content: "You are Tom, VapiBank's customer support assistant..." - } - ] + maxTokens: 150 } }); @@ -457,33 +476,34 @@ You have access to CSV files with account and transaction data: console.log('Assistant LLM settings updated'); ``` - + ```python + import os import requests def update_assistant_llm_settings(assistant_id): url = f"https://api.vapi.ai/assistant/{assistant_id}" headers = { - "Authorization": f"Bearer {YOUR_VAPI_API_KEY}", + "Authorization": f"Bearer {os.environ['VAPI_API_KEY']}", "Content-Type": "application/json" } + current_response = requests.get(url, headers=headers, timeout=30) + current_response.raise_for_status() + current_model = current_response.json()["model"] + data = { "model": { + **current_model, "provider": "openai", "model": "gpt-4o", "temperature": 0.7, - "maxTokens": 150, - "messages": [ - { - "role": "system", - "content": "You are Tom, VapiBank's customer support assistant..." - } - ] + "maxTokens": 150 } } - response = requests.patch(url, headers=headers, json=data) + response = requests.patch(url, headers=headers, json=data, timeout=30) + response.raise_for_status() return response.json() # Update LLM settings @@ -491,25 +511,16 @@ You have access to CSV files with account and transaction data: print("Assistant LLM settings updated") ``` - + ```bash - curl -X PATCH https://api.vapi.ai/assistant/YOUR_ASSISTANT_ID \ - -H "Authorization: Bearer YOUR_VAPI_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "model": { - "provider": "openai", - "model": "gpt-4o", - "temperature": 0.7, - "maxTokens": 150, - "messages": [ - { - "role": "system", - "content": "You are Tom, VapiBank'\''s customer support assistant..." - } - ] - } - }' + current_assistant=$(curl --fail https://api.vapi.ai/assistant/YOUR_ASSISTANT_ID \ + -H "Authorization: Bearer $VAPI_API_KEY") && + assistant_update=$(jq -e 'if (.model | type) != "object" then error("Assistant has no model configuration") else {model: (.model + {provider: "openai", model: "gpt-4o", temperature: 0.7, maxTokens: 150})} end' \ + <<< "$current_assistant") && + curl --fail -X PATCH https://api.vapi.ai/assistant/YOUR_ASSISTANT_ID \ + -H "Authorization: Bearer $VAPI_API_KEY" \ + -H "Content-Type: application/json" \ + --data "$assistant_update" ``` @@ -518,30 +529,41 @@ You have access to CSV files with account and transaction data: **Dashboard only:** Click `Publish` to save your changes. - When using the Server SDKs, changes are applied immediately when you make API calls. There's no separate "publish" step required. + When you use the Server SDK or HTTP API, changes apply immediately. You don't need a separate "publish" step. + At this stage, test the greeting only. Test account answers after you [create and attach the Query tool](#4-create-and-attach-a-query-tool). + + The API examples in this step place an outbound call, so outbound calling must be enabled for your phone number and account. First, [assign a phone number to the assistant](#5-assign-a-phone-number-to-an-assistant). Then replace `YOUR_PHONE_NUMBER_ID` with that phone number's ID and `+14155550100` with a phone number you control. + + If your Vapi phone number is inbound-only, call it from your own phone instead. + Click `Talk to Assistant` to test it out. - + ```typescript import { VapiClient } from "@vapi-ai/server-sdk"; - const vapi = new VapiClient({ token: "YOUR_VAPI_API_KEY" }); + const apiKey = process.env.VAPI_API_KEY; + if (!apiKey) throw new Error("Set VAPI_API_KEY to your Vapi private API key"); + const vapi = new VapiClient({ token: apiKey }); async function testAssistantWithCall(assistantId: string) { const call = await vapi.calls.create({ assistantId: assistantId, + phoneNumberId: "YOUR_PHONE_NUMBER_ID", customer: { - number: "+1234567890" // Your test number + number: "+14155550100" // Your test phone number } }); + if (!("id" in call)) throw new Error("Expected a single call"); + console.log(`Test call created: ${call.id}`); return call; } @@ -550,25 +572,28 @@ You have access to CSV files with account and transaction data: const testCall = await testAssistantWithCall('YOUR_ASSISTANT_ID'); ``` - + ```python + import os import requests def test_assistant_with_call(assistant_id): url = "https://api.vapi.ai/call" headers = { - "Authorization": f"Bearer {YOUR_VAPI_API_KEY}", + "Authorization": f"Bearer {os.environ['VAPI_API_KEY']}", "Content-Type": "application/json" } data = { "assistantId": assistant_id, + "phoneNumberId": "YOUR_PHONE_NUMBER_ID", "customer": { - "number": "+1234567890" # Your test number + "number": "+14155550100" # Your test phone number } } - response = requests.post(url, headers=headers, json=data) + response = requests.post(url, headers=headers, json=data, timeout=30) + response.raise_for_status() call = response.json() print(f"Test call created: {call['id']}") return call @@ -577,16 +602,17 @@ You have access to CSV files with account and transaction data: test_call = test_assistant_with_call('YOUR_ASSISTANT_ID') ``` - + ```bash # Create a test call - curl -X POST https://api.vapi.ai/call \ - -H "Authorization: Bearer YOUR_VAPI_API_KEY" \ + curl --fail -X POST https://api.vapi.ai/call \ + -H "Authorization: Bearer $VAPI_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "assistantId": "YOUR_ASSISTANT_ID", + "phoneNumberId": "YOUR_PHONE_NUMBER_ID", "customer": { - "number": "+1234567890" + "number": "+14155550100" } }' ``` @@ -597,307 +623,183 @@ You have access to CSV files with account and transaction data: --- -## 4. Add Tools to an Assistant +## 4. Create and attach a Query tool + +Create one Query tool with both CSV files in the same knowledge base. Each lookup can then use the account details and transaction records together. + +The API examples use the default function name, `defaultQueryTool`. Use the same name in the dashboard and in the system prompt above. Replace the file ID placeholders with the IDs from [step 1](#1-upload-the-sample-files). + +For complete request schemas, see the [Create Tool](/api-reference/tools/create) and [Update Assistant](/api-reference/assistants/update) API references. - - Open your [dashboard.vapi.ai](https://dashboard.vapi.ai) and click `Tools` in the left sidebar. - - - - Click `Create Tool`. - - Select `Function` as your tool type. - - Change tool name to `get_balance`. - - Add the following function description: - - ```txt title="Function Description" wordWrap - Retrieve the balance for an account based on provided account holder name and last 4 digits of the phone number. - ``` - - Scroll down to the `Knowledge Bases` section and add the following knowledge base: - - - Name: `accounts`
- Description: `Use this to retrieve account information`
- File IDs: `` -
- - - Click `Create Tool`. - - Select `Function` as your tool type. - - Change tool name to `get_recent_transactions`. - - Add the following function description: - - ```txt title="Function Description" wordWrap - Return the three most recent transactions for a specific account. - ``` - - Scroll down to the `Knowledge Bases` section and add the following knowledge bases: - - - Name: `accounts`
- Description: `Use this to retrieve account information`
- File IDs: `` - - - Name: `transactions`
- Description: `Use this to retrieve transactions`
- File IDs: `` + + Open **Tools** in the [Vapi Dashboard](https://dashboard.vapi.ai). Click **Create Tool** and select **Query**. Set **Tool Name** to `defaultQueryTool`. - - - Click `Create Tool`. - - Select `Function` as your tool type. - - Change tool name to `lookup_account`. - - Add the following function description: - - ```txt title="Function Description" wordWrap - Look up account based on provided name and last 4 digits of the phone number. - ``` - - Scroll down to the `Knowledge Bases` section and add the following knowledge bases: - - - Name: `accounts`
- Description: `Use this to retrieve account information`
- File IDs: `` + + Under **Knowledge Bases**, click **Add Knowledge Base** and configure these fields: + + | Field | Value | + | --- | --- | + | **Name** | `bank_records` | + | **Description** | Sample bank account and transaction records. Use both CSV files to match sample accounts and retrieve their recorded balances and transactions. | + | **Model** | `gemini-2.5-flash` | + | **Files** | Select both `accounts.csv` and `transactions.csv`. | + + Save or publish the tool. - - - Click `Assistants` in the left sidebar. - - Make sure `Tom` is selected in the list of assistants. - - Scroll down until you see `Tools` accordion. Expand it. - - In the expanded accordion, add `get_balance` and `get_recent_transactions` tools. - - Click `Publish` to save your changes. - -
- + + Set `VAPI_API_KEY` to your Vapi private API key. + ```typescript import { VapiClient } from "@vapi-ai/server-sdk"; - const vapi = new VapiClient({ token: "YOUR_VAPI_API_KEY" }); + const apiKey = process.env.VAPI_API_KEY; + if (!apiKey) throw new Error("Set VAPI_API_KEY to your Vapi private API key"); + const vapi = new VapiClient({ token: apiKey }); - // Step 1: Create the account lookup tool - const lookupAccountTool = await vapi.tools.create({ - type: "function", - function: { - name: "lookup_account", - description: "Look up account based on provided name and last 4 digits of the phone number." - }, + const queryTool = await vapi.tools.create({ + type: "query", knowledgeBases: [ { - name: "accounts", - description: "Use this to retrieve account information", - fileIds: ["YOUR_ACCOUNTS_FILE_ID"] + name: "bank_records", + provider: "google", + model: "gemini-2.5-flash", + description: "Sample bank account and transaction records. Use both CSV files to match sample accounts and retrieve their recorded balances and transactions.", + fileIds: [ + "YOUR_ACCOUNTS_FILE_ID", + "YOUR_TRANSACTIONS_FILE_ID" + ] } ] }); - console.log(`Created lookup_account tool: ${lookupAccountTool.id}`); + console.log(`Created Query tool: ${queryTool.id}`); - // Step 2: Create the balance retrieval tool - const getBalanceTool = await vapi.tools.create({ - type: "function", - function: { - name: "get_balance", - description: "Retrieve the balance for an account based on provided account holder name and last 4 digits of the phone number." - }, - knowledgeBases: [ - { - name: "accounts", - description: "Use this to retrieve account information", - fileIds: ["YOUR_ACCOUNTS_FILE_ID"] - } - ] - }); - - console.log(`Created get_balance tool: ${getBalanceTool.id}`); + const assistant = await vapi.assistants.get({ id: "YOUR_ASSISTANT_ID" }); + if (!assistant.model) throw new Error("Assistant has no model configuration"); - // Step 3: Create the transactions retrieval tool - const getTransactionsTool = await vapi.tools.create({ - type: "function", - function: { - name: "get_recent_transactions", - description: "Return the three most recent transactions for a specific account." - }, - knowledgeBases: [ - { - name: "accounts", - description: "Use this to retrieve account information", - fileIds: ["YOUR_ACCOUNTS_FILE_ID"] - }, - { - name: "transactions", - description: "Use this to retrieve transactions", - fileIds: ["YOUR_TRANSACTIONS_FILE_ID"] - } - ] - }); - - console.log(`Created get_recent_transactions tool: ${getTransactionsTool.id}`); - - // Step 4: Add all tools to the assistant - const updatedAssistant = await vapi.assistants.update("YOUR_ASSISTANT_ID", { + await vapi.assistants.update({ + id: assistant.id, model: { - toolIds: [ - lookupAccountTool.id, - getBalanceTool.id, - getTransactionsTool.id - ] + ...assistant.model, + toolIds: [queryTool.id] } }); - - console.log("All tools added to assistant successfully!"); ``` - + + Set `VAPI_API_KEY` to your Vapi private API key. + ```python + import os import requests - # Helper function to create tools - def create_tool(name, description, knowledge_bases): - url = "https://api.vapi.ai/tool" - headers = { - "Authorization": f"Bearer {YOUR_VAPI_API_KEY}", - "Content-Type": "application/json" - } - - data = { - "type": "function", - "function": { - "name": name, - "description": description - }, - "knowledgeBases": knowledge_bases - } - - response = requests.post(url, headers=headers, json=data) - return response.json() - - # Step 1: Create the account lookup tool - lookup_account_tool = create_tool( - "lookup_account", - "Look up account based on provided name and last 4 digits of the phone number.", - [{"name": "accounts", "description": "Use this to retrieve account information", "fileIds": ["YOUR_ACCOUNTS_FILE_ID"]}] - ) - print(f"Created lookup_account tool: {lookup_account_tool['id']}") + headers = { + "Authorization": f"Bearer {os.environ['VAPI_API_KEY']}", + "Content-Type": "application/json" + } - # Step 2: Create the balance retrieval tool - get_balance_tool = create_tool( - "get_balance", - "Retrieve the balance for an account based on provided account holder name and last 4 digits of the phone number.", - [{"name": "accounts", "description": "Use this to retrieve account information", "fileIds": ["YOUR_ACCOUNTS_FILE_ID"]}] + tool_response = requests.post( + "https://api.vapi.ai/tool", + headers=headers, + json={ + "type": "query", + "knowledgeBases": [ + { + "name": "bank_records", + "provider": "google", + "model": "gemini-2.5-flash", + "description": "Sample bank account and transaction records. Use both CSV files to match sample accounts and retrieve their recorded balances and transactions.", + "fileIds": [ + "YOUR_ACCOUNTS_FILE_ID", + "YOUR_TRANSACTIONS_FILE_ID" + ] + } + ] + }, + timeout=30 ) - print(f"Created get_balance tool: {get_balance_tool['id']}") - - # Step 3: Create the transactions retrieval tool - get_transactions_tool = create_tool( - "get_recent_transactions", - "Return the three most recent transactions for a specific account.", - [ - {"name": "accounts", "description": "Use this to retrieve account information", "fileIds": ["YOUR_ACCOUNTS_FILE_ID"]}, - {"name": "transactions", "description": "Use this to retrieve transactions", "fileIds": ["YOUR_TRANSACTIONS_FILE_ID"]} - ] + tool_response.raise_for_status() + query_tool = tool_response.json() + print(f"Created Query tool: {query_tool['id']}") + + assistant_url = "https://api.vapi.ai/assistant/YOUR_ASSISTANT_ID" + current_response = requests.get(assistant_url, headers=headers, timeout=30) + current_response.raise_for_status() + current_model = current_response.json()["model"] + + assistant_response = requests.patch( + assistant_url, + headers=headers, + json={"model": {**current_model, "toolIds": [query_tool["id"]]}}, + timeout=30 ) - print(f"Created get_recent_transactions tool: {get_transactions_tool['id']}") - - # Step 4: Add all tools to the assistant - def update_assistant_with_tools(assistant_id, tool_ids): - url = f"https://api.vapi.ai/assistant/{assistant_id}" - headers = { - "Authorization": f"Bearer {YOUR_VAPI_API_KEY}", - "Content-Type": "application/json" - } - - data = { - "model": { - "toolIds": tool_ids - } - } - - response = requests.patch(url, headers=headers, json=data) - return response.json() - - tool_ids = [lookup_account_tool['id'], get_balance_tool['id'], get_transactions_tool['id']] - updated_assistant = update_assistant_with_tools("YOUR_ASSISTANT_ID", tool_ids) - print("All tools added to assistant successfully!") + assistant_response.raise_for_status() ``` - - ```bash - # Step 1: Create the account lookup tool - curl -X POST https://api.vapi.ai/tool \ - -H "Authorization: Bearer YOUR_VAPI_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "type": "function", - "function": { - "name": "lookup_account", - "description": "Look up account based on provided name and last 4 digits of the phone number." - }, - "knowledgeBases": [ - { - "name": "accounts", - "description": "Use this to retrieve account information", - "fileIds": ["YOUR_ACCOUNTS_FILE_ID"] - } - ] - }' + + Create the tool and copy its returned `id`: - # Step 2: Create the balance retrieval tool - curl -X POST https://api.vapi.ai/tool \ - -H "Authorization: Bearer YOUR_VAPI_API_KEY" \ + ```bash + curl --fail -X POST https://api.vapi.ai/tool \ + -H "Authorization: Bearer $VAPI_API_KEY" \ -H "Content-Type: application/json" \ -d '{ - "type": "function", - "function": { - "name": "get_balance", - "description": "Retrieve the balance for an account based on provided account holder name and last 4 digits of the phone number." - }, + "type": "query", "knowledgeBases": [ { - "name": "accounts", - "description": "Use this to retrieve account information", - "fileIds": ["YOUR_ACCOUNTS_FILE_ID"] + "name": "bank_records", + "provider": "google", + "model": "gemini-2.5-flash", + "description": "Sample bank account and transaction records. Use both CSV files to match sample accounts and retrieve their recorded balances and transactions.", + "fileIds": [ + "YOUR_ACCOUNTS_FILE_ID", + "YOUR_TRANSACTIONS_FILE_ID" + ] } ] }' + ``` - # Step 3: Create the transactions retrieval tool - curl -X POST https://api.vapi.ai/tool \ - -H "Authorization: Bearer YOUR_VAPI_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "type": "function", - "function": { - "name": "get_recent_transactions", - "description": "Return the three most recent transactions for a specific account." - }, - "knowledgeBases": [ - { - "name": "accounts", - "description": "Use this to retrieve account information", - "fileIds": ["YOUR_ACCOUNTS_FILE_ID"] - }, - { - "name": "transactions", - "description": "Use this to retrieve transactions", - "fileIds": ["YOUR_TRANSACTIONS_FILE_ID"] - } - ] - }' + Replace `YOUR_QUERY_TOOL_ID` with that ID, then attach the tool: - # Step 4: Add all tools to the assistant - curl -X PATCH https://api.vapi.ai/assistant/YOUR_ASSISTANT_ID \ - -H "Authorization: Bearer YOUR_VAPI_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "model": { - "toolIds": ["LOOKUP_ACCOUNT_TOOL_ID", "GET_BALANCE_TOOL_ID", "GET_TRANSACTIONS_TOOL_ID"] - } - }' + ```bash + current_assistant=$(curl --fail https://api.vapi.ai/assistant/YOUR_ASSISTANT_ID \ + -H "Authorization: Bearer $VAPI_API_KEY") && + assistant_update=$(jq -e --arg toolId "YOUR_QUERY_TOOL_ID" \ + 'if (.model | type) != "object" then error("Assistant has no model configuration") else {model: (.model + {toolIds: [$toolId]})} end' \ + <<< "$current_assistant") && + curl --fail -X PATCH https://api.vapi.ai/assistant/YOUR_ASSISTANT_ID \ + -H "Authorization: Bearer $VAPI_API_KEY" \ + -H "Content-Type: application/json" \ + --data "$assistant_update" ```
+The API examples target the new assistant created in this guide and replace its `model.toolIds` array. If you adapt an existing assistant, include any unrelated tool IDs you want to keep. Use only one Query tool for this example. + +After attaching the tool, test with the sample name `John Doe` and phone digits `1234`. Check that `defaultQueryTool` runs with `knowledgeBaseNames: ["bank_records"]`. Compare the answer with `acc_001` in the CSV files: the stored balance is `2534.67`, and the three transactions are dated May 22–24, 2025. + +Also test unknown or mismatched account details, a correction during the conversation, and a failed lookup. The assistant should ask for clarification or explain the failure, not invent account data. Prompt instructions guide retrieval; they do not enforce exact matching, identity verification, or account access controls. + --- ## 5. Assign a Phone Number to an Assistant + +These examples create a Vapi phone number in a US-region organization. Choose an available area code; the examples use `415`. + + @@ -905,64 +807,78 @@ You have access to CSV files with account and transaction data: Open your [dashboard.vapi.ai](https://dashboard.vapi.ai) and click `Phone Numbers` in the left sidebar.
- - Click `Create Phone Number`. - - Stick with `Free Vapi Number`. - - Enter your preferred area code (e.g. `530`). + - Click **Create Phone Number**. + - Select **Free Vapi Number**. + - Enter an available area code in **Area code**, for example `415`. + - Click **Create**. - - Set the `Phone Number Name` to `Vapi Support Hotline`. - - Under `Inbound Settings` find `Assistant` dropdown and select `Tom` from the list. - - Changes are saved automatically. + - Set **Phone Number Label** to `Vapi Support Hotline`. + - Under **Inbound Settings**, select `Tom` from the **Assistant** dropdown. + - Click **Save**.
- + ```typescript import { VapiClient } from "@vapi-ai/server-sdk"; - const vapi = new VapiClient({ token: "YOUR_VAPI_API_KEY" }); + const apiKey = process.env.VAPI_API_KEY; + if (!apiKey) throw new Error("Set VAPI_API_KEY to your Vapi private API key"); + const vapi = new VapiClient({ token: apiKey }); const phoneNumber = await vapi.phoneNumbers.create({ + provider: "vapi", + numberDesiredAreaCode: "415", name: "Vapi Support Hotline", assistantId: "YOUR_ASSISTANT_ID" }); console.log(`Phone number created: ${phoneNumber.number}`); + console.log(`Phone number ID: ${phoneNumber.id}`); ``` - + ```python + import os import requests def create_phone_number(name, assistant_id): url = "https://api.vapi.ai/phone-number" headers = { - "Authorization": f"Bearer {YOUR_VAPI_API_KEY}", + "Authorization": f"Bearer {os.environ['VAPI_API_KEY']}", "Content-Type": "application/json" } data = { + "provider": "vapi", + "numberDesiredAreaCode": "415", "name": name, "assistantId": assistant_id } - response = requests.post(url, headers=headers, json=data) + response = requests.post(url, headers=headers, json=data, timeout=30) + response.raise_for_status() return response.json() # Create phone number for Tom + assistant_id = "YOUR_ASSISTANT_ID" phone_number = create_phone_number("Vapi Support Hotline", assistant_id) print(f"Phone number created: {phone_number['number']}") + print(f"Phone number ID: {phone_number['id']}") ``` - + ```bash # Create a phone number - curl -X POST https://api.vapi.ai/phone-number \ - -H "Authorization: Bearer YOUR_VAPI_API_KEY" \ + curl --fail -X POST https://api.vapi.ai/phone-number \ + -H "Authorization: Bearer $VAPI_API_KEY" \ -H "Content-Type: application/json" \ -d '{ + "provider": "vapi", + "numberDesiredAreaCode": "415", "name": "Vapi Support Hotline", "assistantId": "YOUR_ASSISTANT_ID" }' @@ -974,9 +890,9 @@ You have access to CSV files with account and transaction data: ## Next Steps -Just like that, you've built a 24/7 customer support hotline that can handle inbound calls and answer balance and transaction questions. +You've configured an inbound support demo that uses a Query tool to answer questions from sample CSV files. For real customer accounts, use an authenticated backend that enforces account access and retrieves current data. -Consider the reading the following guides to further enhance your assistant: +Consider reading the following guides to further enhance your assistant: * [**Knowledge bases**](/knowledge-base) - Learn more about knowledge bases to build knowledge-based agents. * [**External Integrations**](../tools/) - Configure integrations with [Google Calendar](../tools/google-calendar), [Google Sheets](../tools/google-sheets), [Slack](../tools/slack), etc. diff --git a/fern/assistants/examples/multilingual-agent.mdx b/fern/assistants/examples/multilingual-agent.mdx index eab6130bc..bfd06363c 100644 --- a/fern/assistants/examples/multilingual-agent.mdx +++ b/fern/assistants/examples/multilingual-agent.mdx @@ -1,21 +1,30 @@ --- title: Multilingual support agent -subtitle: Build a global support agent that handles English, Spanish, and French customer inquiries with automatic language detection and native voice quality +subtitle: Configure transcription, a multilingual voice, and file-based support answers in English, Spanish, and French slug: assistants/examples/multilingual-agent -description: Build a multilingual voice AI customer support agent with automatic language detection, native voices, and comprehensive tools for international customer service +description: Build a multilingual Vapi support demo with transcription, voice settings, prompts, and a Query tool for sample customer, product, and support article data. --- + +Use sample customer records only. A knowledge-base lookup does not authenticate callers or enforce access to real customer accounts. + + ## Overview -Build a dynamic customer support agent for GlobalTech International that automatically detects and responds in the customer's language (English, Spanish, or French) during conversation, with seamless language switching and real-time adaptation. +Build a support assistant for GlobalTech International that handles English, Spanish, and French. Configure multilingual transcription and one multilingual voice, then use a prompt to guide the assistant's response language. + +A [Query tool](/knowledge-base/using-query-tool) retrieves information from uploaded files. In this demo, one Query tool searches three CSV files. You don't need a custom server or a `tool-calls` webhook handler. +The files are a snapshot, not a live customer database or product catalog. -**What You'll Build:** -* Assistant with automatic multilingual transcription -* Dynamic voice adaptation for detected languages -* Real-time language switching during conversations -* Phone number setup for seamless international support -* Advanced prompting for cultural context awareness +**What you'll build:** + +* Multilingual transcription for English, Spanish, and French +* One multilingual voice that automatically selects the synthesis language +* Prompt-guided responses when callers change languages +* A Vapi phone number for incoming support calls +* A system prompt with language and tone instructions +* One Query tool for customer records, product information, and support article summaries **Alternative Approach**: For a more structured multilingual experience with explicit language selection, see our [Squad-based multilingual support](../../squads/examples/multilingual-support) that guides customers through language selection and dedicated conversation paths. @@ -24,14 +33,20 @@ Build a dynamic customer support agent for GlobalTech International that automat ## Prerequisites * A [Vapi account](https://dashboard.vapi.ai/). +* A Vapi private API key stored in the `VAPI_API_KEY` environment variable. Run API examples on your server or local machine, not in browser code. +* Install `@vapi-ai/server-sdk` version 2.0.1 for TypeScript or the `requests` package for Python. The cURL model-update examples also use `jq`. + +Each TypeScript and Python snippet includes its own imports and setup. Replace `YOUR_ASSISTANT_ID` and the file or tool ID placeholders with the IDs returned by earlier steps. ## Scenario -We will be creating a dynamic multilingual customer support agent for GlobalTech International, a technology company serving customers across North America, Europe, and Latin America. Unlike structured language selection, this agent automatically detects the customer's language from their speech and can switch languages mid-conversation, providing a truly seamless multilingual experience. +GlobalTech International serves customers across North America, Europe, and Latin America. This example uses one assistant for all three languages, without a language-selection menu. Test transcription, spoken responses, and knowledge-base answers in each language before connecting callers. --- -## 1. Create a Multilingual Knowledge Base +## 1. Upload the sample files + +The CSV files contain fictional example data for this tutorial. Do not call or email the sample customers. @@ -50,18 +65,20 @@ We will be creating a dynamic multilingual customer support agent for GlobalTech - 1. Navigate to **Files** in your [Vapi Dashboard](https://dashboard.vapi.ai/) - 2. Click **Choose file** and upload all three CSV files - 3. Note the file IDs for use in creating multilingual tools + 1. Navigate to **Files** in your [Vapi Dashboard](https://dashboard.vapi.ai/). + 2. Click **Choose file** and upload all three CSV files. + 3. Note the file IDs for use in creating the Query tool. - + ```typescript import { VapiClient } from "@vapi-ai/server-sdk"; import fs from 'fs'; - const vapi = new VapiClient({ token: "YOUR_VAPI_API_KEY" }); + const apiKey = process.env.VAPI_API_KEY; + if (!apiKey) throw new Error("Set VAPI_API_KEY to your Vapi private API key"); + const vapi = new VapiClient({ token: apiKey }); async function uploadMultilingualFiles() { try { @@ -99,19 +116,20 @@ We will be creating a dynamic multilingual customer support agent for GlobalTech const fileIds = await uploadMultilingualFiles(); ``` - + ```python + import os import requests def upload_multilingual_file(file_path): """Upload a CSV file for multilingual support data""" url = "https://api.vapi.ai/file" - headers = {"Authorization": f"Bearer {YOUR_VAPI_API_KEY}"} + headers = {"Authorization": f"Bearer {os.environ['VAPI_API_KEY']}"} try: with open(file_path, 'rb') as file: files = {'file': file} - response = requests.post(url, headers=headers, files=files) + response = requests.post(url, headers=headers, files=files, timeout=30) response.raise_for_status() return response.json() except requests.exceptions.RequestException as error: @@ -128,21 +146,21 @@ We will be creating a dynamic multilingual customer support agent for GlobalTech print(f"Support articles file ID: {support_file['id']}") ``` - + ```bash # Upload customers.csv - curl -X POST https://api.vapi.ai/file \ - -H "Authorization: Bearer YOUR_VAPI_API_KEY" \ + curl --fail -X POST https://api.vapi.ai/file \ + -H "Authorization: Bearer $VAPI_API_KEY" \ -F "file=@customers.csv" # Upload products.csv - curl -X POST https://api.vapi.ai/file \ - -H "Authorization: Bearer YOUR_VAPI_API_KEY" \ + curl --fail -X POST https://api.vapi.ai/file \ + -H "Authorization: Bearer $VAPI_API_KEY" \ -F "file=@products.csv" # Upload support_articles.csv - curl -X POST https://api.vapi.ai/file \ - -H "Authorization: Bearer YOUR_VAPI_API_KEY" \ + curl --fail -X POST https://api.vapi.ai/file \ + -H "Authorization: Bearer $VAPI_API_KEY" \ -F "file=@support_articles.csv" ``` @@ -167,11 +185,13 @@ We will be creating a dynamic multilingual customer support agent for GlobalTech - + ```typescript import { VapiClient } from "@vapi-ai/server-sdk"; - const vapi = new VapiClient({ token: "YOUR_VAPI_API_KEY" }); + const apiKey = process.env.VAPI_API_KEY; + if (!apiKey) throw new Error("Set VAPI_API_KEY to your Vapi private API key"); + const vapi = new VapiClient({ token: apiKey }); const systemPrompt = `You are Maria, a multilingual customer support representative for GlobalTech International. You help customers in English, Spanish, and French with product information, account support, and technical troubleshooting. @@ -205,13 +225,14 @@ We will be creating a dynamic multilingual customer support agent for GlobalTech console.log(`Assistant created with ID: ${assistant.id}`); ``` - + ```python + import os import requests url = "https://api.vapi.ai/assistant" headers = { - "Authorization": f"Bearer {YOUR_VAPI_API_KEY}", + "Authorization": f"Bearer {os.environ['VAPI_API_KEY']}", "Content-Type": "application/json" } @@ -244,15 +265,16 @@ We will be creating a dynamic multilingual customer support agent for GlobalTech } } - response = requests.post(url, headers=headers, json=data) + response = requests.post(url, headers=headers, json=data, timeout=30) + response.raise_for_status() assistant = response.json() print(f"Assistant created with ID: {assistant['id']}") ``` - + ```bash - curl -X POST https://api.vapi.ai/assistant \ - -H "Authorization: Bearer YOUR_VAPI_API_KEY" \ + curl --fail -X POST https://api.vapi.ai/assistant \ + -H "Authorization: Bearer $VAPI_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "GlobalTech Support Agent", @@ -278,42 +300,54 @@ We will be creating a dynamic multilingual customer support agent for GlobalTech + Use Deepgram `nova-3` with `language: "multi"` for English, Spanish, and French. Nova-2 multilingual mode supports English and Spanish only. Choose one transcriber configuration below. + 1. In your assistant configuration, find the **Transcriber** section 2. **Provider**: Select `Deepgram` (recommended for speed and accuracy) - 3. **Model**: Choose `Nova 2` or `Nova 3` + 3. **Model**: Choose `Nova 3` 4. **Language**: Select `Multi` (enables automatic language detection) 5. **Alternative**: Use `Google` provider with `Multilingual` language setting - + ```typescript + import { VapiClient } from "@vapi-ai/server-sdk"; + + const apiKey = process.env.VAPI_API_KEY; + if (!apiKey) throw new Error("Set VAPI_API_KEY to your Vapi private API key"); + const vapi = new VapiClient({ token: apiKey }); + // Option 1: Deepgram Multi (recommended) const deepgramTranscriber = { provider: "deepgram", - model: "nova-2", // or "nova-3" + model: "nova-3", language: "multi" - }; + } as const; // Option 2: Google Multilingual const googleTranscriber = { provider: "google", model: "gemini-2.0-flash", language: "Multilingual" - }; + } as const; - // Update assistant with transcriber - await vapi.assistants.update("YOUR_ASSISTANT_ID", { + // For Google, pass googleTranscriber instead. + await vapi.assistants.update({ + id: "YOUR_ASSISTANT_ID", transcriber: deepgramTranscriber }); ``` - + ```python + import os + import requests + # Option 1: Deepgram Multi (recommended) deepgram_transcriber = { "provider": "deepgram", - "model": "nova-2", # or "nova-3" + "model": "nova-3", "language": "multi" } @@ -324,34 +358,41 @@ We will be creating a dynamic multilingual customer support agent for GlobalTech "language": "Multilingual" } - # Update assistant with transcriber - url = f"https://api.vapi.ai/assistant/{YOUR_ASSISTANT_ID}" + # For Google, pass google_transcriber instead. + url = "https://api.vapi.ai/assistant/YOUR_ASSISTANT_ID" headers = { - "Authorization": f"Bearer {YOUR_VAPI_API_KEY}", + "Authorization": f"Bearer {os.environ['VAPI_API_KEY']}", "Content-Type": "application/json" } data = {"transcriber": deepgram_transcriber} - response = requests.patch(url, headers=headers, json=data) + response = requests.patch(url, headers=headers, json=data, timeout=30) + response.raise_for_status() ``` - + + Run one of these requests. For Deepgram: + ```bash # Option 1: Deepgram Multi - curl -X PATCH https://api.vapi.ai/assistant/YOUR_ASSISTANT_ID \ - -H "Authorization: Bearer YOUR_VAPI_API_KEY" \ + curl --fail -X PATCH https://api.vapi.ai/assistant/YOUR_ASSISTANT_ID \ + -H "Authorization: Bearer $VAPI_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "transcriber": { "provider": "deepgram", - "model": "nova-2", + "model": "nova-3", "language": "multi" } }' + ``` + + For Google instead: + ```bash # Option 2: Google Multilingual - curl -X PATCH https://api.vapi.ai/assistant/YOUR_ASSISTANT_ID \ - -H "Authorization: Bearer YOUR_VAPI_API_KEY" \ + curl --fail -X PATCH https://api.vapi.ai/assistant/YOUR_ASSISTANT_ID \ + -H "Authorization: Bearer $VAPI_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "transcriber": { @@ -381,23 +422,33 @@ We will be creating a dynamic multilingual customer support agent for GlobalTech Voice fallbacks activate when synthesis fails. They do not select a different voice based on the detected language. - + ```typescript + import { VapiClient } from "@vapi-ai/server-sdk"; + + const apiKey = process.env.VAPI_API_KEY; + if (!apiKey) throw new Error("Set VAPI_API_KEY to your Vapi private API key"); + const vapi = new VapiClient({ token: apiKey }); + // Vapi Voices V2 automatically selects the synthesis language. const multilingualVoice = { provider: "vapi", voiceId: "Elliot", - version: 2, + version: "2", language: "auto" - }; + } as const; - await vapi.assistants.update("YOUR_ASSISTANT_ID", { + await vapi.assistants.update({ + id: "YOUR_ASSISTANT_ID", voice: multilingualVoice }); ``` - + ```python + import os + import requests + # Vapi Voices V2 automatically selects the synthesis language. multilingual_voice = { "provider": "vapi", @@ -407,20 +458,21 @@ We will be creating a dynamic multilingual customer support agent for GlobalTech } # Update assistant with voice configuration - url = f"https://api.vapi.ai/assistant/{YOUR_ASSISTANT_ID}" + url = "https://api.vapi.ai/assistant/YOUR_ASSISTANT_ID" headers = { - "Authorization": f"Bearer {YOUR_VAPI_API_KEY}", + "Authorization": f"Bearer {os.environ['VAPI_API_KEY']}", "Content-Type": "application/json" } data = {"voice": multilingual_voice} - response = requests.patch(url, headers=headers, json=data) + response = requests.patch(url, headers=headers, json=data, timeout=30) + response.raise_for_status() ``` - + ```bash - curl -X PATCH https://api.vapi.ai/assistant/YOUR_ASSISTANT_ID \ - -H "Authorization: Bearer YOUR_VAPI_API_KEY" \ + curl --fail -X PATCH https://api.vapi.ai/assistant/YOUR_ASSISTANT_ID \ + -H "Authorization: Bearer $VAPI_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "voice": { @@ -442,7 +494,7 @@ We will be creating a dynamic multilingual customer support agent for GlobalTech - First, create this comprehensive system prompt: + Use this system prompt to choose the relevant knowledge base and answer from the returned data: ```txt title="System Prompt" maxLines=15 # GlobalTech International - Multilingual Support Agent @@ -469,9 +521,9 @@ You are **Maria**, a multilingual customer support representative for GlobalTech ## Core Responsibilities 1. **Product Information**: Help customers understand our technology solutions -2. **Account Support**: Assist with account access, billing, and subscription questions -3. **Technical Troubleshooting**: Guide customers through technical issues step-by-step -4. **Escalation**: Transfer to specialized teams when needed +2. **Customer Records**: Look up sample customer profiles without changing accounts +3. **Support Articles**: Find relevant article titles and summaries +4. **Limits**: Explain when the sample data cannot answer a question. Transfers and callbacks are not configured. ## Language Behavior - **Auto-detect**: Automatically respond in the customer's language @@ -479,25 +531,40 @@ You are **Maria**, a multilingual customer support representative for GlobalTech - **Mixed Languages**: If customer uses multiple languages, respond in their primary language - **Unsupported Languages**: If customer speaks another language, politely explain you support English, Spanish, and French -## Available Tools -- **Customer Lookup**: Search customer database by email, phone, or account ID -- **Product Information**: Access product catalog and specifications -- **Support Articles**: Find relevant troubleshooting guides in customer's language +## Knowledge-base tool +Use defaultQueryTool before answering questions about customer records, products, or support articles. +Select the relevant knowledge base with knowledgeBaseNames: +- ["customers"]: Sample customer profiles. Ask for a customer_id, email, or phone number, then use only a matching returned record. +- ["products"]: Product names, descriptions, prices in USD, and availability from the sample catalog. +- ["support_articles"]: Article titles and content summaries. These are not full articles or step-by-step instructions. +Select more than one knowledge base if the caller's question needs multiple categories. + +## Grounded answers and limits +Respond in the caller's current language. For products and articles, use the returned _en, _es, or _fr fields for English, Spanish, or French. +If the caller changes languages, keep the same factual answer and use the appropriate language fields. +If the caller changes the customer or product details, repeat the lookup and ignore results for the old request. +Use only returned facts. If a record is missing, ambiguous, or mismatched, ask for clarification instead of guessing. +If retrieval fails, explain the failure. Do not treat it as proof that a customer does not exist or a product is unavailable. +Do not invent article steps, URLs, customer history, or pricing terms that the files do not contain. +Matching a customer record does not verify identity or authorize access to real accounts. +The files are a snapshot. Do not claim to check live stock, change an account, reset a password, or complete a transfer. Keep responses concise (under 50 words) while being thorough and helpful. ``` - Then update your assistant: + Then update your assistant. The API examples retrieve the existing `model` first so the prompt update preserves its other settings: Copy the system prompt above and paste it into the `System Prompt` field in your assistant configuration. - + ```typescript import { VapiClient } from "@vapi-ai/server-sdk"; - const vapi = new VapiClient({ token: "YOUR_VAPI_API_KEY" }); + const apiKey = process.env.VAPI_API_KEY; + if (!apiKey) throw new Error("Set VAPI_API_KEY to your Vapi private API key"); + const vapi = new VapiClient({ token: apiKey }); const systemPrompt = `# GlobalTech International - Multilingual Support Agent @@ -523,9 +590,9 @@ You are **Maria**, a multilingual customer support representative for GlobalTech ## Core Responsibilities 1. **Product Information**: Help customers understand our technology solutions -2. **Account Support**: Assist with account access, billing, and subscription questions -3. **Technical Troubleshooting**: Guide customers through technical issues step-by-step -4. **Escalation**: Transfer to specialized teams when needed +2. **Customer Records**: Look up sample customer profiles without changing accounts +3. **Support Articles**: Find relevant article titles and summaries +4. **Limits**: Explain when the sample data cannot answer a question. Transfers and callbacks are not configured. ## Language Behavior - **Auto-detect**: Automatically respond in the customer's language @@ -533,17 +600,33 @@ You are **Maria**, a multilingual customer support representative for GlobalTech - **Mixed Languages**: If customer uses multiple languages, respond in their primary language - **Unsupported Languages**: If customer speaks another language, politely explain you support English, Spanish, and French -## Available Tools -- **Customer Lookup**: Search customer database by email, phone, or account ID -- **Product Information**: Access product catalog and specifications -- **Support Articles**: Find relevant troubleshooting guides in customer's language +## Knowledge-base tool +Use defaultQueryTool before answering questions about customer records, products, or support articles. +Select the relevant knowledge base with knowledgeBaseNames: +- ["customers"]: Sample customer profiles. Ask for a customer_id, email, or phone number, then use only a matching returned record. +- ["products"]: Product names, descriptions, prices in USD, and availability from the sample catalog. +- ["support_articles"]: Article titles and content summaries. These are not full articles or step-by-step instructions. +Select more than one knowledge base if the caller's question needs multiple categories. + +## Grounded answers and limits +Respond in the caller's current language. For products and articles, use the returned _en, _es, or _fr fields for English, Spanish, or French. +If the caller changes languages, keep the same factual answer and use the appropriate language fields. +If the caller changes the customer or product details, repeat the lookup and ignore results for the old request. +Use only returned facts. If a record is missing, ambiguous, or mismatched, ask for clarification instead of guessing. +If retrieval fails, explain the failure. Do not treat it as proof that a customer does not exist or a product is unavailable. +Do not invent article steps, URLs, customer history, or pricing terms that the files do not contain. +Matching a customer record does not verify identity or authorize access to real accounts. +The files are a snapshot. Do not claim to check live stock, change an account, reset a password, or complete a transfer. Keep responses concise (under 50 words) while being thorough and helpful.`; - const updatedAssistant = await vapi.assistants.update("YOUR_ASSISTANT_ID", { + const assistant = await vapi.assistants.get({ id: "YOUR_ASSISTANT_ID" }); + if (!assistant.model) throw new Error("Assistant has no model configuration"); + + const updatedAssistant = await vapi.assistants.update({ + id: assistant.id, model: { - provider: "openai", - model: "gpt-4o", + ...assistant.model, messages: [ { role: "system", @@ -556,13 +639,14 @@ Keep responses concise (under 50 words) while being thorough and helpful.`; console.log("System prompt updated successfully"); ``` - + ```python + import os import requests - url = f"https://api.vapi.ai/assistant/{YOUR_ASSISTANT_ID}" + url = "https://api.vapi.ai/assistant/YOUR_ASSISTANT_ID" headers = { - "Authorization": f"Bearer {YOUR_VAPI_API_KEY}", + "Authorization": f"Bearer {os.environ['VAPI_API_KEY']}", "Content-Type": "application/json" } @@ -590,9 +674,9 @@ You are **Maria**, a multilingual customer support representative for GlobalTech ## Core Responsibilities 1. **Product Information**: Help customers understand our technology solutions -2. **Account Support**: Assist with account access, billing, and subscription questions -3. **Technical Troubleshooting**: Guide customers through technical issues step-by-step -4. **Escalation**: Transfer to specialized teams when needed +2. **Customer Records**: Look up sample customer profiles without changing accounts +3. **Support Articles**: Find relevant article titles and summaries +4. **Limits**: Explain when the sample data cannot answer a question. Transfers and callbacks are not configured. ## Language Behavior - **Auto-detect**: Automatically respond in the customer's language @@ -600,17 +684,33 @@ You are **Maria**, a multilingual customer support representative for GlobalTech - **Mixed Languages**: If customer uses multiple languages, respond in their primary language - **Unsupported Languages**: If customer speaks another language, politely explain you support English, Spanish, and French -## Available Tools -- **Customer Lookup**: Search customer database by email, phone, or account ID -- **Product Information**: Access product catalog and specifications -- **Support Articles**: Find relevant troubleshooting guides in customer's language +## Knowledge-base tool +Use defaultQueryTool before answering questions about customer records, products, or support articles. +Select the relevant knowledge base with knowledgeBaseNames: +- ["customers"]: Sample customer profiles. Ask for a customer_id, email, or phone number, then use only a matching returned record. +- ["products"]: Product names, descriptions, prices in USD, and availability from the sample catalog. +- ["support_articles"]: Article titles and content summaries. These are not full articles or step-by-step instructions. +Select more than one knowledge base if the caller's question needs multiple categories. + +## Grounded answers and limits +Respond in the caller's current language. For products and articles, use the returned _en, _es, or _fr fields for English, Spanish, or French. +If the caller changes languages, keep the same factual answer and use the appropriate language fields. +If the caller changes the customer or product details, repeat the lookup and ignore results for the old request. +Use only returned facts. If a record is missing, ambiguous, or mismatched, ask for clarification instead of guessing. +If retrieval fails, explain the failure. Do not treat it as proof that a customer does not exist or a product is unavailable. +Do not invent article steps, URLs, customer history, or pricing terms that the files do not contain. +Matching a customer record does not verify identity or authorize access to real accounts. +The files are a snapshot. Do not claim to check live stock, change an account, reset a password, or complete a transfer. Keep responses concise (under 50 words) while being thorough and helpful.""" + current_response = requests.get(url, headers=headers, timeout=30) + current_response.raise_for_status() + current_model = current_response.json()["model"] + data = { "model": { - "provider": "openai", - "model": "gpt-4o", + **current_model, "messages": [ { "role": "system", @@ -620,28 +720,23 @@ Keep responses concise (under 50 words) while being thorough and helpful.""" } } - response = requests.patch(url, headers=headers, json=data) + response = requests.patch(url, headers=headers, json=data, timeout=30) + response.raise_for_status() assistant = response.json() print("System prompt updated successfully") ``` - + ```bash - curl -X PATCH https://api.vapi.ai/assistant/YOUR_ASSISTANT_ID \ - -H "Authorization: Bearer YOUR_VAPI_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "model": { - "provider": "openai", - "model": "gpt-4o", - "messages": [ - { - "role": "system", - "content": "# GlobalTech International - Multilingual Support Agent..." - } - ] - } - }' + current_assistant=$(curl --fail https://api.vapi.ai/assistant/YOUR_ASSISTANT_ID \ + -H "Authorization: Bearer $VAPI_API_KEY") && + assistant_update=$(jq -e --argjson changes '{"messages":[{"role":"system","content":"# GlobalTech International - Multilingual Support Agent\n\n## Identity & Role\nYou are **Maria**, a multilingual customer support representative for GlobalTech International. You are fluent in English, Spanish, and French, and you help customers with product information, account support, and technical troubleshooting.\n\n## Language Capabilities & Cultural Guidelines\n\n### English (Primary)\n- **Tone**: Direct, friendly, professional\n- **Style**: Conversational but efficient\n- **Approach**: Solution-focused, provide clear steps\n\n### Spanish \n- **Tone**: Warm, respectful, patient\n- **Formality**: Use formal \"usted\" initially, then adapt to customer preference\n- **Approach**: Take time to build rapport, be thorough in explanations\n\n### French\n- **Tone**: Polite, courteous, professional\n- **Formality**: Use proper greeting conventions (\"Bonjour/Bonsoir\")\n- **Approach**: Structured responses, respectful of formality\n\n## Core Responsibilities\n1. **Product Information**: Help customers understand our technology solutions\n2. **Customer Records**: Look up sample customer profiles without changing accounts\n3. **Support Articles**: Find relevant article titles and summaries\n4. **Limits**: Explain when the sample data cannot answer a question. Transfers and callbacks are not configured.\n\n## Language Behavior\n- **Auto-detect**: Automatically respond in the customer'\''s language\n- **Language Switching**: If customer switches languages, switch with them seamlessly\n- **Mixed Languages**: If customer uses multiple languages, respond in their primary language\n- **Unsupported Languages**: If customer speaks another language, politely explain you support English, Spanish, and French\n\n## Knowledge-base tool\nUse defaultQueryTool before answering questions about customer records, products, or support articles.\nSelect the relevant knowledge base with knowledgeBaseNames:\n- [\"customers\"]: Sample customer profiles. Ask for a customer_id, email, or phone number, then use only a matching returned record.\n- [\"products\"]: Product names, descriptions, prices in USD, and availability from the sample catalog.\n- [\"support_articles\"]: Article titles and content summaries. These are not full articles or step-by-step instructions.\nSelect more than one knowledge base if the caller'\''s question needs multiple categories.\n\n## Grounded answers and limits\nRespond in the caller'\''s current language. For products and articles, use the returned _en, _es, or _fr fields for English, Spanish, or French.\nIf the caller changes languages, keep the same factual answer and use the appropriate language fields.\nIf the caller changes the customer or product details, repeat the lookup and ignore results for the old request.\nUse only returned facts. If a record is missing, ambiguous, or mismatched, ask for clarification instead of guessing.\nIf retrieval fails, explain the failure. Do not treat it as proof that a customer does not exist or a product is unavailable.\nDo not invent article steps, URLs, customer history, or pricing terms that the files do not contain.\nMatching a customer record does not verify identity or authorize access to real accounts.\nThe files are a snapshot. Do not claim to check live stock, change an account, reset a password, or complete a transfer.\n\nKeep responses concise (under 50 words) while being thorough and helpful."}]}' \ + 'if (.model | type) != "object" then error("Assistant has no model configuration") else {model: (.model + $changes)} end' \ + <<< "$current_assistant") && + curl --fail -X PATCH https://api.vapi.ai/assistant/YOUR_ASSISTANT_ID \ + -H "Authorization: Bearer $VAPI_API_KEY" \ + -H "Content-Type: application/json" \ + --data "$assistant_update" ``` @@ -650,293 +745,231 @@ Keep responses concise (under 50 words) while being thorough and helpful.""" --- -## 6. Add Multilingual Tools +## 6. Create and attach a Query tool + +Create one [Query tool](/knowledge-base/using-query-tool) with three knowledge bases. The assistant selects the relevant knowledge bases for each question. Vapi retrieves from the uploaded files, so you don't need a custom `tool-calls` webhook handler. + +The API examples use the default function name, `defaultQueryTool`. Use that name in the dashboard and in the [system prompt from step 5](#5-configure-system-prompt). Replace the file ID placeholders with the IDs from [step 1](#1-upload-the-sample-files). + +For complete request schemas, see the [Create Tool](/api-reference/tools/create) and [Update Assistant](/api-reference/assistants/update) API references. - - Open your [dashboard.vapi.ai](https://dashboard.vapi.ai) and click `Tools` in the left sidebar. - - - - Click `Create Tool`. - - Select `Function` as your tool type. - - Change tool name to `lookup_customer`. - - Add function description: - - ```txt title="Function Description" wordWrap - Look up customer information by email, phone number, or account ID. Returns customer details including preferred language, account status, and support history. - ``` - - Add knowledge base: - - Name: `customers` - - Description: `Customer database with multilingual support preferences` - - File IDs: `` + + Open **Tools** in the [Vapi Dashboard](https://dashboard.vapi.ai). Click **Create Tool** and select **Query**. Set **Tool Name** to `defaultQueryTool`. - - - Click `Create Tool`. - - Select `Function` as your tool type. - - Change tool name to `get_product_info`. - - Add function description: - - ```txt title="Function Description" wordWrap - Get detailed product information including specifications, pricing, and availability. Supports queries in English, Spanish, and French. - ``` - - Add knowledge base: - - Name: `products` - - Description: `Product catalog with multilingual descriptions` - - File IDs: `` - - - - Click `Create Tool`. - - Select `Function` as your tool type. - - Change tool name to `search_support_articles`. - - Add function description: - - ```txt title="Function Description" wordWrap - Search technical support articles and troubleshooting guides. Returns relevant articles in the customer's preferred language. - ``` - - Add knowledge base: - - Name: `support_articles` - - Description: `Multilingual support documentation and troubleshooting guides` - - File IDs: `` + + Under **Knowledge Bases**, click **Add Knowledge Base** for each row below. Set **Model** to `gemini-2.5-flash` for all three. + + | Name | Files | Description | + | --- | --- | --- | + | `customers` | `customers.csv` | Sample customer profiles with customer IDs, contact details, preferred languages, account status, and support tiers. | + | `products` | `products.csv` | Sample product names and descriptions in English, Spanish, and French, with prices in USD and recorded availability. | + | `support_articles` | `support_articles.csv` | Support article titles and content summaries in English, Spanish, and French. Does not contain full articles or step-by-step instructions. | + + Save or publish the tool. - - - Click `Assistants` in the left sidebar. - - Select your `GlobalTech Support Agent`. - - Scroll down to the `Tools` section and expand it. - - Add all three tools: `lookup_customer`, `get_product_info`, and `search_support_articles`. - - Click `Publish` to save your changes. + + Open **Assistants** and select `GlobalTech Support Agent`. In **Tools**, attach `defaultQueryTool`. If you followed an earlier version of this guide, detach `lookup_customer`, `get_product_info`, and `search_support_articles`. + + Keep the system prompt from step 5, then publish the assistant. - + + Set `VAPI_API_KEY` to your Vapi private API key. + ```typescript import { VapiClient } from "@vapi-ai/server-sdk"; - const vapi = new VapiClient({ token: "YOUR_VAPI_API_KEY" }); + const apiKey = process.env.VAPI_API_KEY; + if (!apiKey) throw new Error("Set VAPI_API_KEY to your Vapi private API key"); + const vapi = new VapiClient({ token: apiKey }); - // Create customer lookup tool - const customerLookupTool = await vapi.tools.create({ - type: "function", - function: { - name: "lookup_customer", - description: "Look up customer information by email, phone number, or account ID. Returns customer details including preferred language, account status, and support history." - }, + const queryTool = await vapi.tools.create({ + type: "query", knowledgeBases: [ { name: "customers", - description: "Customer database with multilingual support preferences", + provider: "google", + model: "gemini-2.5-flash", + description: "Sample customer profiles with customer IDs, contact details, preferred languages, account status, and support tiers.", fileIds: ["YOUR_CUSTOMERS_FILE_ID"] - } - ] - }); - - // Create product information tool - const productInfoTool = await vapi.tools.create({ - type: "function", - function: { - name: "get_product_info", - description: "Get detailed product information including specifications, pricing, and availability. Supports queries in English, Spanish, and French." - }, - knowledgeBases: [ + }, { name: "products", - description: "Product catalog with multilingual descriptions", + provider: "google", + model: "gemini-2.5-flash", + description: "Sample product names and descriptions in English, Spanish, and French, with prices in USD and recorded availability.", fileIds: ["YOUR_PRODUCTS_FILE_ID"] - } - ] - }); - - // Create support articles tool - const supportArticlesTool = await vapi.tools.create({ - type: "function", - function: { - name: "search_support_articles", - description: "Search technical support articles and troubleshooting guides. Returns relevant articles in the customer's preferred language." - }, - knowledgeBases: [ + }, { name: "support_articles", - description: "Multilingual support documentation and troubleshooting guides", + provider: "google", + model: "gemini-2.5-flash", + description: "Support article titles and content summaries in English, Spanish, and French. Does not contain full articles or step-by-step instructions.", fileIds: ["YOUR_SUPPORT_ARTICLES_FILE_ID"] } ] }); - // Add all tools to the assistant - const updatedAssistant = await vapi.assistants.update("YOUR_ASSISTANT_ID", { + const assistant = await vapi.assistants.get({ id: "YOUR_ASSISTANT_ID" }); + if (!assistant.model) throw new Error("Assistant has no model configuration"); + + await vapi.assistants.update({ + id: assistant.id, model: { - toolIds: [ - customerLookupTool.id, - productInfoTool.id, - supportArticlesTool.id - ] + ...assistant.model, + toolIds: [queryTool.id] } }); - console.log("All multilingual tools added to assistant successfully!"); + console.log(`Attached Query tool: ${queryTool.id}`); ``` - + + Set `VAPI_API_KEY` to your Vapi private API key. + ```python + import os import requests - def create_multilingual_tool(name, description, knowledge_base_name, knowledge_base_description, file_id): - """Create a multilingual tool with knowledge base""" - url = "https://api.vapi.ai/tool" - headers = { - "Authorization": f"Bearer {YOUR_VAPI_API_KEY}", - "Content-Type": "application/json" - } - - data = { - "type": "function", - "function": { - "name": name, - "description": description + headers = { + "Authorization": f"Bearer {os.environ['VAPI_API_KEY']}", + "Content-Type": "application/json" + } + tool_data = { + "type": "query", + "knowledgeBases": [ + { + "name": "customers", + "provider": "google", + "model": "gemini-2.5-flash", + "description": "Sample customer profiles with customer IDs, contact details, preferred languages, account status, and support tiers.", + "fileIds": [ + "YOUR_CUSTOMERS_FILE_ID" + ] }, - "knowledgeBases": [ - { - "name": knowledge_base_name, - "description": knowledge_base_description, - "fileIds": [file_id] - } - ] - } - - response = requests.post(url, headers=headers, json=data) - return response.json() - - # Create customer lookup tool - customer_lookup_tool = create_multilingual_tool( - "lookup_customer", - "Look up customer information by email, phone number, or account ID. Returns customer details including preferred language, account status, and support history.", - "customers", - "Customer database with multilingual support preferences", - "YOUR_CUSTOMERS_FILE_ID" - ) + { + "name": "products", + "provider": "google", + "model": "gemini-2.5-flash", + "description": "Sample product names and descriptions in English, Spanish, and French, with prices in USD and recorded availability.", + "fileIds": [ + "YOUR_PRODUCTS_FILE_ID" + ] + }, + { + "name": "support_articles", + "provider": "google", + "model": "gemini-2.5-flash", + "description": "Support article titles and content summaries in English, Spanish, and French. Does not contain full articles or step-by-step instructions.", + "fileIds": [ + "YOUR_SUPPORT_ARTICLES_FILE_ID" + ] + } + ] + } - # Create product information tool - product_info_tool = create_multilingual_tool( - "get_product_info", - "Get detailed product information including specifications, pricing, and availability. Supports queries in English, Spanish, and French.", - "products", - "Product catalog with multilingual descriptions", - "YOUR_PRODUCTS_FILE_ID" + tool_response = requests.post( + "https://api.vapi.ai/tool", + headers=headers, + json=tool_data, + timeout=30 ) - - # Create support articles tool - support_articles_tool = create_multilingual_tool( - "search_support_articles", - "Search technical support articles and troubleshooting guides. Returns relevant articles in the customer'\''s preferred language.", - "support_articles", - "Multilingual support documentation and troubleshooting guides", - "YOUR_SUPPORT_ARTICLES_FILE_ID" + tool_response.raise_for_status() + query_tool = tool_response.json() + + assistant_url = "https://api.vapi.ai/assistant/YOUR_ASSISTANT_ID" + current_response = requests.get(assistant_url, headers=headers, timeout=30) + current_response.raise_for_status() + current_model = current_response.json()["model"] + + response = requests.patch( + assistant_url, + headers=headers, + json={"model": {**current_model, "toolIds": [query_tool["id"]]}}, + timeout=30 ) - - # Add all tools to the assistant - def update_assistant_with_tools(assistant_id, tool_ids): - url = f"https://api.vapi.ai/assistant/{assistant_id}" - headers = { - "Authorization": f"Bearer {YOUR_VAPI_API_KEY}", - "Content-Type": "application/json" - } - - data = { - "model": { - "toolIds": tool_ids - } - } - - response = requests.patch(url, headers=headers, json=data) - return response.json() - - tool_ids = [ - customer_lookup_tool['id'], - product_info_tool['id'], - support_articles_tool['id'] - ] - - updated_assistant = update_assistant_with_tools("YOUR_ASSISTANT_ID", tool_ids) - print("All multilingual tools added to assistant successfully!") + response.raise_for_status() + print(f"Attached Query tool: {query_tool['id']}") ``` - + + Create the tool and copy its returned `id`: + ```bash - # Create customer lookup tool - curl -X POST https://api.vapi.ai/tool \ - -H "Authorization: Bearer YOUR_VAPI_API_KEY" \ + curl --fail -X POST https://api.vapi.ai/tool \ + -H "Authorization: Bearer $VAPI_API_KEY" \ -H "Content-Type: application/json" \ -d '{ - "type": "function", - "function": { - "name": "lookup_customer", - "description": "Look up customer information by email, phone number, or account ID. Returns customer details including preferred language, account status, and support history." - }, + "type": "query", "knowledgeBases": [ { "name": "customers", - "description": "Customer database with multilingual support preferences", - "fileIds": ["YOUR_CUSTOMERS_FILE_ID"] - } - ] - }' - - # Create product information tool - curl -X POST https://api.vapi.ai/tool \ - -H "Authorization: Bearer YOUR_VAPI_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "type": "function", - "function": { - "name": "get_product_info", - "description": "Get detailed product information including specifications, pricing, and availability. Supports queries in English, Spanish, and French." - }, - "knowledgeBases": [ + "provider": "google", + "model": "gemini-2.5-flash", + "description": "Sample customer profiles with customer IDs, contact details, preferred languages, account status, and support tiers.", + "fileIds": [ + "YOUR_CUSTOMERS_FILE_ID" + ] + }, { "name": "products", - "description": "Product catalog with multilingual descriptions", - "fileIds": ["YOUR_PRODUCTS_FILE_ID"] - } - ] - }' - - # Create support articles tool - curl -X POST https://api.vapi.ai/tool \ - -H "Authorization: Bearer YOUR_VAPI_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "type": "function", - "function": { - "name": "search_support_articles", - "description": "Search technical support articles and troubleshooting guides. Returns relevant articles in the customer'\''s preferred language." - }, - "knowledgeBases": [ + "provider": "google", + "model": "gemini-2.5-flash", + "description": "Sample product names and descriptions in English, Spanish, and French, with prices in USD and recorded availability.", + "fileIds": [ + "YOUR_PRODUCTS_FILE_ID" + ] + }, { "name": "support_articles", - "description": "Multilingual support documentation and troubleshooting guides", - "fileIds": ["YOUR_SUPPORT_ARTICLES_FILE_ID"] + "provider": "google", + "model": "gemini-2.5-flash", + "description": "Support article titles and content summaries in English, Spanish, and French. Does not contain full articles or step-by-step instructions.", + "fileIds": [ + "YOUR_SUPPORT_ARTICLES_FILE_ID" + ] } ] }' + ``` - # Add all tools to the assistant - curl -X PATCH https://api.vapi.ai/assistant/YOUR_ASSISTANT_ID \ - -H "Authorization: Bearer YOUR_VAPI_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "model": { - "toolIds": ["CUSTOMER_LOOKUP_TOOL_ID", "PRODUCT_INFO_TOOL_ID", "SUPPORT_ARTICLES_TOOL_ID"] - } - }' + Replace `YOUR_QUERY_TOOL_ID` with that ID. Retrieve the assistant's existing model, then attach the tool without discarding its other settings: + + ```bash + current_assistant=$(curl --fail https://api.vapi.ai/assistant/YOUR_ASSISTANT_ID \ + -H "Authorization: Bearer $VAPI_API_KEY") && + assistant_update=$(jq -e --arg toolId "YOUR_QUERY_TOOL_ID" \ + 'if (.model | type) != "object" then error("Assistant has no model configuration") else {model: (.model + {toolIds: [$toolId]})} end' \ + <<< "$current_assistant") && + curl --fail -X PATCH https://api.vapi.ai/assistant/YOUR_ASSISTANT_ID \ + -H "Authorization: Bearer $VAPI_API_KEY" \ + -H "Content-Type: application/json" \ + --data "$assistant_update" ``` +The API examples target the new assistant created in this guide and replace its `model.toolIds` array. Include unrelated tool IDs you want to keep if you adapt an existing assistant. Use one Query tool for these three knowledge bases. + +Test the saved assistant before connecting callers: + +- Ask about `P001` in English, then switch to Spanish. Check that `defaultQueryTool` uses `knowledgeBaseNames: ["products"]` and that both answers match the product's corresponding language fields. +- Ask in French for a summary of `A001`. The answer should use `support_articles` and summarize the French content, without inventing password-reset steps. +- Ask for the sample profile `C001`. The answer should use `customers` and match that record. Confirm that the assistant does not describe the lookup as authentication. +- Test an unknown ID, a correction, and a failed lookup. The assistant should clarify or explain the failure instead of inventing a record. + +Knowledge-base selection, language choice, and matching are guided by the prompt, not enforced as database rules. The sample files contain no live inventory, account-changing actions, or complete troubleshooting procedures. + --- ## 7. Set Up Phone Number +These examples create a Vapi phone number in a US-region organization. Choose an available area code; the API examples request `415`. + @@ -944,84 +977,78 @@ Keep responses concise (under 50 words) while being thorough and helpful.""" Open your [dashboard.vapi.ai](https://dashboard.vapi.ai) and click `Phone Numbers` in the left sidebar. - - Click `Create Phone Number`. - - Choose `Free Vapi Number` to get started. - - Select your preferred area code (e.g., `212` for New York). + - Click **Create Phone Number**. + - Choose **Free Vapi Number**. + - Enter an available area code in **Area code**, for example `415`. + - Click **Create**. - - Set the `Phone Number Name` to `GlobalTech International Support`. - - Under `Inbound Settings`, find `Assistant` dropdown and select `GlobalTech Support Agent`. - - **Optional**: Configure advanced settings: - - Enable call recording for quality assurance - - Set up voicemail detection - - Configure business hours if needed - - Changes are saved automatically. + - Set **Phone Number Label** to `GlobalTech International Support`. + - Under **Inbound Settings**, select `GlobalTech Support Agent` from **Assistant**. + - Click **Save**. - + ```typescript import { VapiClient } from "@vapi-ai/server-sdk"; - const vapi = new VapiClient({ token: "YOUR_VAPI_API_KEY" }); + const apiKey = process.env.VAPI_API_KEY; + if (!apiKey) throw new Error("Set VAPI_API_KEY to your Vapi private API key"); + const vapi = new VapiClient({ token: apiKey }); const phoneNumber = await vapi.phoneNumbers.create({ + provider: "vapi", + numberDesiredAreaCode: "415", name: "GlobalTech International Support", - assistantId: "YOUR_ASSISTANT_ID", - inboundSettings: { - recordingEnabled: true, - voicemailDetectionEnabled: true, - maxCallDurationMinutes: 30 - } + assistantId: "YOUR_ASSISTANT_ID" }); console.log(`Multilingual support phone number created: ${phoneNumber.number}`); + console.log(`Phone number ID: ${phoneNumber.id}`); ``` - + ```python + import os import requests def create_multilingual_phone_number(assistant_id): """Create phone number for multilingual support""" url = "https://api.vapi.ai/phone-number" headers = { - "Authorization": f"Bearer {YOUR_VAPI_API_KEY}", + "Authorization": f"Bearer {os.environ['VAPI_API_KEY']}", "Content-Type": "application/json" } data = { + "provider": "vapi", + "numberDesiredAreaCode": "415", "name": "GlobalTech International Support", - "assistantId": assistant_id, - "inboundSettings": { - "recordingEnabled": True, - "voicemailDetectionEnabled": True, - "maxCallDurationMinutes": 30 - } + "assistantId": assistant_id } - response = requests.post(url, headers=headers, json=data) + response = requests.post(url, headers=headers, json=data, timeout=30) + response.raise_for_status() return response.json() # Create multilingual support phone number phone_number = create_multilingual_phone_number("YOUR_ASSISTANT_ID") print(f"Multilingual support phone number created: {phone_number['number']}") + print(f"Phone number ID: {phone_number['id']}") ``` - + ```bash # Create multilingual support phone number - curl -X POST https://api.vapi.ai/phone-number \ - -H "Authorization: Bearer YOUR_VAPI_API_KEY" \ + curl --fail -X POST https://api.vapi.ai/phone-number \ + -H "Authorization: Bearer $VAPI_API_KEY" \ -H "Content-Type: application/json" \ -d '{ + "provider": "vapi", + "numberDesiredAreaCode": "415", "name": "GlobalTech International Support", - "assistantId": "YOUR_ASSISTANT_ID", - "inboundSettings": { - "recordingEnabled": true, - "voicemailDetectionEnabled": true, - "maxCallDurationMinutes": 30 - } + "assistantId": "YOUR_ASSISTANT_ID" }' ``` @@ -1041,13 +1068,13 @@ For speech synthesis, confirm that the selected model and voice support every la ## Next Steps -Just like that, you've built a dynamic multilingual customer support agent that automatically detects and responds in the customer's language with seamless mid-conversation language switching. +You've configured a multilingual support demo with transcription, one multilingual voice, and a Query tool for sample data. Test each language and mid-conversation language changes before connecting callers. Consider reading the following guides to further enhance your multilingual implementation: * [**Squad-based Multilingual Support**](/squads/examples/multilingual-support) - Compare with structured language selection approach * [**Multilingual Configuration Guide**](/customization/multilingual) - Learn about all multilingual configuration options -* [**Function tools**](/tools/custom-tools) - Build advanced multilingual tools and integrations +* [**Query tool**](/knowledge-base/using-query-tool) - Configure file-based knowledge retrieval Need help with multilingual implementation? Ask other developers in the [Vapi Discord community](https://discord.gg/v5Ee6FhAZt) or mention us on [X/Twitter](https://x.com/Vapi_AI). diff --git a/fern/openai-realtime.mdx b/fern/openai-realtime.mdx index 78d6b71b0..12ccdcbe0 100644 --- a/fern/openai-realtime.mdx +++ b/fern/openai-realtime.mdx @@ -17,10 +17,6 @@ OpenAI’s Realtime API enables developers to use a native speech-to-speech mode ## Available models - - The `gpt-realtime-2025-08-28` model is production-ready. - - OpenAI offers three realtime models, each with different capabilities and cost/performance trade-offs: | Model | Status | Best For | Key Features | @@ -53,12 +49,20 @@ Realtime models support a specific set of OpenAI voices optimized for speech-to- ## Configuration -### Basic setup +### Configure an API Request tool + +Use an [API Request tool](/tools/api-request) to fetch current weather directly from [WeatherAPI](https://www.weatherapi.com/docs/). You don't need a custom server or a `tool-calls` webhook handler. + +Create a WeatherAPI account, get an API key, and replace `YOUR_WEATHERAPI_KEY` in the tool's `url` field below. For the TypeScript and Python examples, set `VAPI_API_KEY` to your Vapi private API key and run the code on your server. -Configure a realtime assistant with function calling: + + WeatherAPI authenticates through a URL query parameter. Do not expose the configured URL or your WeatherAPI key in public repositories or browser code. Redact the WeatherAPI key from request logs. + + +The tool's `body` schema defines the `location` argument the model supplies. For this `GET` request, Vapi inserts that argument into the URL and sends no HTTP request body. The `url_encode` filter encodes spaces and other special characters in the city name. -```json title="Assistant Configuration" +```json title="Assistant configuration" { "model": { "provider": "openai", @@ -66,27 +70,28 @@ Configure a realtime assistant with function calling: "messages": [ { "role": "system", - "content": "You are a helpful assistant. Be concise and friendly." + "content": "You are a concise, friendly weather assistant. If the caller has not provided a location, ask for one. If the city is ambiguous, ask for the missing region or country before using getWeather. Call getWeather for each new current-weather request, including a request for another city. Pass the complete location, preserving any region/state and country the caller supplied. Use only the latest successful result for the requested location and report the returned location with the weather. If the returned city, region, or country conflicts with the request, clarify before reporting weather. Differences in spelling or formatting alone are not a location mismatch. If the lookup fails or current-weather data is missing, explain that current weather is unavailable. Do not invent weather or reuse an earlier result after a failed lookup." } ], "temperature": 0.7, "maxTokens": 250, "tools": [ { - "type": "function", - "function": { - "name": "getWeather", - "description": "Get the current weather", - "parameters": { - "type": "object", - "properties": { - "location": { - "type": "string", - "description": "The city name" - } - }, - "required": ["location"] - } + "type": "apiRequest", + "name": "getWeather", + "description": "Get current weather for the caller's complete requested location. Call getWeather for every request for current weather, and use the returned location to confirm that the result matches the request.", + "method": "GET", + "url": "https://api.weatherapi.com/v1/current.json?key=YOUR_WEATHERAPI_KEY&q={{location|url_encode}}", + "timeoutSeconds": 10, + "body": { + "type": "object", + "properties": { + "location": { + "type": "string", + "description": "The complete location requested by the caller, preserving the city and any supplied region/state and country; for example, Springfield, Illinois, USA." + } + }, + "required": ["location"] } } ] @@ -98,9 +103,11 @@ Configure a realtime assistant with function calling: } ``` ```typescript title="TypeScript SDK" -import { Vapi } from '@vapi-ai/server-sdk'; +import { VapiClient } from "@vapi-ai/server-sdk"; -const vapi = new Vapi({ token: process.env.VAPI_API_KEY }); +const apiKey = process.env.VAPI_API_KEY; +if (!apiKey) throw new Error("Set VAPI_API_KEY to your Vapi private API key"); +const vapi = new VapiClient({ token: apiKey }); const assistant = await vapi.assistants.create({ model: { @@ -108,25 +115,26 @@ const assistant = await vapi.assistants.create({ model: "gpt-realtime-2025-08-28", messages: [{ role: "system", - content: "You are a helpful assistant. Be concise and friendly." + content: "You are a concise, friendly weather assistant. If the caller has not provided a location, ask for one. If the city is ambiguous, ask for the missing region or country before using getWeather. Call getWeather for each new current-weather request, including a request for another city. Pass the complete location, preserving any region/state and country the caller supplied. Use only the latest successful result for the requested location and report the returned location with the weather. If the returned city, region, or country conflicts with the request, clarify before reporting weather. Differences in spelling or formatting alone are not a location mismatch. If the lookup fails or current-weather data is missing, explain that current weather is unavailable. Do not invent weather or reuse an earlier result after a failed lookup." }], temperature: 0.7, maxTokens: 250, tools: [{ - type: "function", - function: { - name: "getWeather", - description: "Get the current weather", - parameters: { - type: "object", - properties: { - location: { - type: "string", - description: "The city name" - } - }, - required: ["location"] - } + type: "apiRequest", + name: "getWeather", + description: "Get current weather for the caller's complete requested location. Call getWeather for every request for current weather, and use the returned location to confirm that the result matches the request.", + method: "GET", + url: "https://api.weatherapi.com/v1/current.json?key=YOUR_WEATHERAPI_KEY&q={{location|url_encode}}", + timeoutSeconds: 10, + body: { + type: "object", + properties: { + location: { + type: "string", + description: "The complete location requested by the caller, preserving the city and any supplied region/state and country; for example, Springfield, Illinois, USA." + } + }, + required: ["location"] } }] }, @@ -137,6 +145,8 @@ const assistant = await vapi.assistants.create({ }); ``` ```python title="Python SDK" +import os + from vapi import Vapi vapi = Vapi(token=os.getenv("VAPI_API_KEY")) @@ -147,25 +157,26 @@ assistant = vapi.assistants.create( "model": "gpt-realtime-2025-08-28", "messages": [{ "role": "system", - "content": "You are a helpful assistant. Be concise and friendly." + "content": "You are a concise, friendly weather assistant. If the caller has not provided a location, ask for one. If the city is ambiguous, ask for the missing region or country before using getWeather. Call getWeather for each new current-weather request, including a request for another city. Pass the complete location, preserving any region/state and country the caller supplied. Use only the latest successful result for the requested location and report the returned location with the weather. If the returned city, region, or country conflicts with the request, clarify before reporting weather. Differences in spelling or formatting alone are not a location mismatch. If the lookup fails or current-weather data is missing, explain that current weather is unavailable. Do not invent weather or reuse an earlier result after a failed lookup." }], "temperature": 0.7, "maxTokens": 250, "tools": [{ - "type": "function", - "function": { - "name": "getWeather", - "description": "Get the current weather", - "parameters": { - "type": "object", - "properties": { - "location": { - "type": "string", - "description": "The city name" - } - }, - "required": ["location"] - } + "type": "apiRequest", + "name": "getWeather", + "description": "Get current weather for the caller's complete requested location. Call getWeather for every request for current weather, and use the returned location to confirm that the result matches the request.", + "method": "GET", + "url": "https://api.weatherapi.com/v1/current.json?key=YOUR_WEATHERAPI_KEY&q={{location|url_encode}}", + "timeoutSeconds": 10, + "body": { + "type": "object", + "properties": { + "location": { + "type": "string", + "description": "The complete location requested by the caller, preserving the city and any supplied region/state and country; for example, Springfield, Illinois, USA." + } + }, + "required": ["location"] } }] }, @@ -177,6 +188,15 @@ assistant = vapi.assistants.create( ``` +#### Test the weather tool + +After you create the assistant, test these cases: + +- Ask for the current weather in a city and include its region or country. Confirm that `getWeather` receives the complete location and the spoken answer matches the returned location and weather. +- Ask about another city during the same call. Confirm that `getWeather` runs again and the answer uses the new result. +- Ask about an ambiguous city. Confirm that the assistant requests the missing region or country before calling `getWeather`. +- Trigger a failed lookup after a successful one. Confirm that the assistant explains the failure without guessing or reusing the earlier weather. + ### Using realtime-exclusive voices To use the enhanced voices only available with realtime models: @@ -386,4 +406,4 @@ Handle edge cases gracefully: Now that you understand OpenAI Realtime models: - **[Phone Calling Guide](/phone-calling):** Set up inbound and outbound calling - **[Assistant Hooks](/assistants/assistant-hooks):** Add custom logic to your conversations -- **[Voice providers](/providers/voice/overview):** Explore other voice options \ No newline at end of file +- **[Voice providers](/providers/voice/overview):** Explore other voice options diff --git a/fern/server-url/server-authentication.mdx b/fern/server-url/server-authentication.mdx index 1b21996aa..a2f348384 100644 --- a/fern/server-url/server-authentication.mdx +++ b/fern/server-url/server-authentication.mdx @@ -266,7 +266,7 @@ For maximum security, use HMAC signature-based authentication to verify request Reference credentials in your assistant's server configuration: -```json title="API Request" +```json title="Assistant server configuration" { "server": { "url": "https://api.example.com/webhook", @@ -313,7 +313,7 @@ assistant = client.assistants.create( Assign credentials to phone numbers for incoming call authentication: -```json title="API Request" +```json title="Phone number server configuration" { "phoneNumber": "+1234567890", "server": { @@ -343,7 +343,7 @@ const phoneNumber = await client.phoneNumbers.create({ Secure your function tool endpoints with credentials: -```json title="API Request" +```json title="Function tool configuration" { "type": "function", "function": { diff --git a/fern/static/spreadsheets/multilingual-support/customers.csv b/fern/static/spreadsheets/multilingual-support/customers.csv index 94178c906..02fa20e03 100644 --- a/fern/static/spreadsheets/multilingual-support/customers.csv +++ b/fern/static/spreadsheets/multilingual-support/customers.csv @@ -1,16 +1,10 @@ customer_id,name,email,phone,preferred_language,region,account_status,support_tier -C001,Sarah Johnson,sarah.johnson@email.com,+1-555-0101,english,north_america,active,premium -C002,María González,maria.gonzalez@email.com,+34-600-123456,spanish,spain,active,standard -C003,Jean Dubois,jean.dubois@email.com,+33-1-23456789,french,france,active,premium -C004,Carlos Restrepo,carlos.restrepo@email.com,+52-55-12345678,spanish,mexico,active,standard -C005,Emily Chen,emily.chen@email.com,+1-555-0102,english,north_america,active,enterprise -C006,Sophie Martin,sophie.martin@email.com,+1-514-1234567,french,canada,active,premium -C007,Antonio Silva,antonio.silva@email.com,+34-91-2345678,spanish,spain,inactive,standard -C008,Michael Thompson,michael.thompson@email.com,+44-20-12345678,english,uk,active,standard -C009,Luisa Fernández,luisa.fernandez@email.com,+57-1-3456789,spanish,colombia,active,premium -C010,Pierre Leblanc,pierre.leblanc@email.com,+33-4-56789012,french,france,active,standard -C011,Jennifer Davis,jennifer.davis@email.com,+1-555-0103,english,north_america,active,standard -C012,Isabel Rodríguez,isabel.rodriguez@email.com,+52-33-45678901,spanish,mexico,suspended,standard -C013,François Moreau,francois.moreau@email.com,+1-418-5678901,french,canada,active,enterprise -C014,David Wilson,david.wilson@email.com,+1-555-0104,english,north_america,active,premium -C015,Carmen López,carmen.lopez@email.com,+34-93-6789012,spanish,spain,active,standard \ No newline at end of file +C001,Sarah Johnson,sarah.johnson@example.com,+14155550101,english,north_america,active,premium +C003,Jean Dubois,jean.dubois@example.com,+33199000103,french,france,active,premium +C005,Emily Chen,emily.chen@example.com,+14155550105,english,north_america,active,enterprise +C006,Sophie Martin,sophie.martin@example.com,+15145550106,french,canada,active,premium +C008,Michael Thompson,michael.thompson@example.com,+442079460108,english,uk,active,standard +C010,Pierre Leblanc,pierre.leblanc@example.com,+33465710110,french,france,active,standard +C011,Jennifer Davis,jennifer.davis@example.com,+14155550111,english,north_america,active,standard +C013,François Moreau,francois.moreau@example.com,+14185550113,french,canada,active,enterprise +C014,David Wilson,david.wilson@example.com,+14155550114,english,north_america,active,premium