Conversation will appear here...
) : ( transcript.map((msg, i) => (
tool-calls messages that your frontend can handle.
model.tools array and subscribe to clientMessages: \['tool-calls'].
3. Listen for message.type === 'tool-calls' and perform the desired UI update. No response is sent back to the model.
4. (Optional) Inject context mid-call using vapi.addMessage(...).
## Complete example (React + Web SDK)
```tsx
import Vapi from '@vapi-ai/web';
import { useCallback, useState } from 'react';
const vapi = new Vapi('Start a call and ask the assistant to trigger UI updates
addMessage to provide extra context mid-call. This does not return results for a tool; it adds messages the model can see.
```ts
// Inject system-level context
vapi.addMessage({
role: 'system',
content: 'Context: userId=123, plan=premium, theme=dark',
});
// Inject a user message
vapi.addMessage({
role: 'user',
content: 'FYI: I switched to the settings tab.',
});
```
clientMessages: \['tool-calls'] and handle message.type === 'tool-calls'.
* **Add context**: Use vapi.addMessage to inject data mid-call.
## Next steps
* **Server-based tools**: Learn how to return results back to the model with Custom Tools.
* **API reference**: See Tools API for full configuration options.
***
title: Tool rejection plan
subtitle: Prevent unintended tool calls using conditions based on conversation state
slug: tools/tool-rejection-plan
-------------------------------
## Overview
A rejection plan lets you prevent a tool from executing when certain conditions are met. You attach it to any tool call and it evaluates the recent conversation state to decide whether to reject the call.
* If all conditions match (AND logic), the tool call is rejected.
* To express OR at the top level, use a single group condition with `operator: "OR"`.
* If `conditions` is empty or omitted, the tool always executes.
### 2. Create Calendar Tools
After connecting your Google Calendar account, create the tools:
1. Go to **Dashboard** > **Tools** page
2. Click the **Create Tool** button
3. Select **Google Calendar** from the available options
4. Choose which tool(s) you want to create:
* Google Calendar Create Event Tool
* Google Calendar Check Availability Tool
5. For each tool, provide a name and description explaining when it should be invoked
### 3. Add Tools to Assistant
Now, add your chosen calendar tool(s) to your assistant:
1. Navigate to **Dashboard** > **Assistants** page
2. Select your assistant
3. Go to the **Tools** tab
4. In the tools dropdown, select the calendar tool(s) you want to use
5. Click **Publish** to save your changes
## Tool Configurations
### Google Calendar Create Event Tool
This tool uses the following fields to create events:
* `summary`: The title or description of the calendar event
* `startDateTime`: The start date and time of the event
* `endDateTime`: The end date and time of the event
* `attendees`: A list of email addresses for people to invite to the event
* `timeZone`: The timezone for the event, defaults to UTC
* `calendarId`: The calendar ID to create the event in, defaults to the primary calendar
### Google Calendar Check Availability Tool
This tool uses the following fields to check availability:
* `startDateTime`: The start of the time range to check
* `endDateTime`: The end of the time range to check
* `timeZone`: The timezone for the availability check, defaults to UTC
* `calendarId`: The calendar ID to check availability in, defaults to the primary calendar
### 2. Create GoHighLevel Tools
After connecting your GoHighLevel account, create the tools:
1. Go to **Dashboard** > **Tools** page.
2. Click the **Create Tool** button.
3. Select **GoHighLevel** from the available options.
4. Choose which tool(s) you want to create (e.g., Get Contact, Create Contact, Check Availability, Create Event).
5. For each tool, provide a clear and descriptive name. Adding a description is optional. If you leave it blank, Vapi will automatically generate a default description that explains the tool's purpose and includes the current date, formatted using the timezone you specify in the tool's metadata.
6. For the **Check Availability** and **Create Event** tools, ensure you provide a valid `calendarId`. You can find the `calendarId` for each of your calendars in GoHighLevel by navigating to **Settings** > **Calendars**. Each calendar listed will display its unique ID.
### 3. Add Tools to Assistant
Now, add your chosen GoHighLevel tool(s) to your assistant. For an example scenario where you want your assistant to book appointments, including finding a suitable time and managing contact information, you would add all four tools: Get Contact, Create Contact, Check Availability, and Create Event.
1. Navigate to **Dashboard** > **Assistants** page.
2. Select your assistant.
3. Go to the **Tools** tab.
4. In the tools dropdown, select the GoHighLevel tool(s) you want to use.
5. Click **Publish** to save your changes.
### 4. Configure Assistant System Prompt
After adding the GoHighLevel tools to your assistant, it's crucial to provide a clear system prompt. This prompt guides the assistant on how and when to use each tool to achieve the desired workflow. For a typical appointment booking scenario, your system prompt instructs the AI on the sequence of operations and conditions for using each tool.
Here's an example system prompt to guide your assistant. Remember to replace `ghl_contact_get`, `ghl_contact_create`, `ghl_check_availability`, and `ghl_create_event` with the exact names you gave your tools if they are different.
```text
You are a helpful and efficient scheduling assistant. Your primary goal is to book appointments for users. Follow these steps carefully:
1. **Gather Information**: Start by asking for the caller\'s full name and email address.
2. **Check Existing Contact**: Use the `ghl_contact_get` tool to see if a contact already exists with the provided email.
3. **Create Contact (if needed)**: If no contact is found, use the `ghl_contact_create` tool to create a new contact with their name and email.
4. **Discuss Appointment Time**: Once you have a contact ID (either from an existing contact or a newly created one), ask the user for their preferred date and time for the appointment.
5. **Check Availability**: Use the `ghl_check_availability` tool to check for open slots. It\'s a good idea to check for the entire preferred day to offer alternatives if their initial request isn\'t available.
6. **Confirm Time**: Discuss the available options with the user and agree on a suitable time.
7. **Book Appointment**: Finally, use the `ghl_create_event` tool to book the appointment, ensuring you use the correct contact ID.
**Important Guidelines:**
* Always use `ghl_contact_get` to check for an existing contact *before* attempting to create one with `ghl_contact_create`.
* You *must* have a contact ID (from `ghl_contact_get` or `ghl_contact_create`) *before* you can book an appointment with `ghl_create_event`.
* Always confirm availability with `ghl_check_availability` *before* attempting to book an appointment with `ghl_create_event`.
```
## Tool Configurations
### GoHighLevel Get Contact Tool
This tool uses both or one of the following fields to retrieve an existing contact:
* `email`: The email address of the contact to search for.
* `phone`: The phone number of the contact to search for.
### GoHighLevel Create Contact Tool
This tool uses the following fields to create a new contact:
* `firstName`: The first name of the contact.
* `lastName`: The last name of the contact.
* `email`: The email address of the contact.
* `phone`: The phone number of the contact.
### GoHighLevel Check Availability Tool
This tool uses the following fields to check for open appointment slots:
* `calendarId`: The ID of the GoHighLevel calendar to check.
* `startDate`: The start of the time range to check for availability (epoch time in milliseconds).
* `endDate`: The end of the time range to check for availability (epoch time in milliseconds).
* `timezone`: The timezone for the availability check (e.g., "America/New\_York").
### GoHighLevel Create Event Tool
This tool uses the following fields to book an appointment:
* `calendarId`: The ID of the GoHighLevel calendar in which to create the event.
* `contactId`: The ID of the GoHighLevel contact to associate with the event.
* `title`: The title or summary for the calendar event.
* `startTime`: The start date and time for the event in ISO 8601 format.
* `endTime`: The end date and time for the event in ISO 8601 format.
## Example Usage
Here's how the tools can be configured in your assistant's JSON setup:
```json
{
"model": {
"provider": "openai",
"model": "gpt-4o",
"messages": [
{
"role": "system",
"content": "You are a highly efficient scheduling assistant for appointments. Your goal is to seamlessly book appointments into a calendar. Follow this precise workflow:\\n\\n1. **Gather User Info**: Start by politely asking for the caller's full name and email address.\\n2. **Check Existing Contact**: Use the 'getGHLContact' tool to check if a contact already exists with the provided email.\\n3. **Create New Contact (if necessary)**: If no contact is found with the email, use the 'createGHLContact' tool to create a new contact. You will need their name and email for this.\\n4. **Determine Appointment Needs**: Once you have a contact ID (either from an existing or newly created contact), ask the user for their preferred date and time for the appointment, and the purpose of the appointment (e.g., 'dental checkup', 'initial consultation').\\n5. **Check Calendar Availability**: Use the 'checkGHLAvailability' tool to find open slots for the requested period. Check a broad enough range (e.g., the entire day) to offer alternatives if the exact preferred time is unavailable.\\n6. **Confirm Time with User**: Discuss the available options and confirm a suitable appointment time with the user.\\n7. **Book the Appointment**: Use the 'createGHLEvent' tool to schedule the appointment. Use the purpose of the appointment as the event title.\\n\\n**Critical Notes:**\\n- Always use 'getGHLContact' before 'createGHLContact'.\\n- You MUST have a contactId before calling 'createGHLEvent'.\\n- Always use 'checkGHLAvailability' before 'createGHLEvent'.\\n- Assume all appointments are 30 minutes long unless specified otherwise by the user.\\n- Today's date is {{\"now\" | date: \"%A, %B %d, %Y, %I:%M %p\", \"America/New_York\"}}."
}
],
"tools": [
{
"type": "gohighlevel.calendar.availability.check",
"function": {
"name": "checkGHLAvailability",
"description": "Use this tool to check for available appointment slots in the GoHighLevel calendar. Today's date is {{\"now\" | date: \"%A, %B %d, %Y, %I:%M %p\", \"America/New_York\"}}."
},
"metadata": {
"calendarId": "CALENDAR_ID",
"timeZone": "America/New_York"
}
},
{
"type": "gohighlevel.calendar.event.create",
"function": {
"name": "ghl_create_event",
"description": "Use this tool to create a new appointment (event) in the GoHighLevel calendar. Today's date is {{\"now\" | date: \"%A, %B %d, %Y, %I:%M %p\", \"America/New_York\"}}. - All appointments are 30 minutes long unless specified otherwise by the user."
},
"metadata": {
"calendarId": "CALENDAR_ID"
}
},
{
"type": "gohighlevel.contact.get",
"function": {
"name": "getGHLContact",
"description": "Use this tool to retrieve an existing contact from GoHighLevel using the user's email address. This helps avoid duplicate entries."
}
},
{
"type": "gohighlevel.contact.create",
"function": {
"name": "createGHLContact",
"description": "Use this tool to create a new contact in GoHighLevel."
}
}
]
}
}
```
## Best Practices
1. **Clear Instructions**: Provide clear instructions in your assistant's system message about when to use each calendar tool
2. **Error Handling**: Include fallback responses for cases where either calendar tool fails
3. **Time Zone Awareness**: Always specify the correct timezone for events and availability checks. Also remember to format \{\{now}} with your desired timezone.
4. **Event Details**: Ensure all required fields are properly filled when creating events
5. **Availability Flow**: Check availability before attempting to schedule events to avoid conflicts
6. **Contact Prerequisite for Events**: Remember that creating an event in GoHighLevel requires a `contactId`. Ensure your assistant's logic always fetches or creates a contact (using the `getGHLContact` and `createGHLContact` tools) before attempting to book an appointment with the `createGHLEvent` tool.
#### **Step 2: Configure Your Assistant with the Knowledge Base**
1. Navigate to `Build > Assistant`
2. Select the assistant you want to enhance with the Knowledge Base
3. In the assistant configuration, locate the "Files" or "Knowledge Base" section
4. Select the files you uploaded in Step 1 to associate them with this assistant
#### **Step 3: Publish the Assistant**
1. Instruct your assistant to use the knowledge base when relevant by adding appropriate prompts in your assistant's configuration. This helps ensure the assistant knows when to reference the knowledge base versus using its general knowledge.
For example, if you have a knowledge base about your company's products, you might add this prompt:
```
When users ask about our products, services, or company information, use the knowledge base to provide accurate details.
```
2. Review your assistant configuration to ensure all settings are correct
3. Click the "Publish" button to make your changes live
4. This automatically creates a default knowledge base (using the query tool) with the selected files for the assistant
## **Advanced Configuration Options**
### **Multiple Knowledge Bases**
You can configure multiple knowledge bases within a single query tool:
```json
"knowledgeBases": [
{
"provider": "google",
"name": "product-documentation",
"description": "Contains detailed product specifications, feature descriptions, and technical details",
"fileIds": ["file-id-1", "file-id-2"]
},
{
"provider": "google",
"name": "troubleshooting-guide",
"description": "Contains troubleshooting guides, support procedures, and problem resolution steps",
"fileIds": ["file-id-3", "file-id-4"]
}
]
```
### **Knowledge Base Description**
The description field should explain what content the knowledge base contains:
```json
"description": "Contains pricing information, subscription plans, and billing documentation"
```
### **Assistant System Prompt Integration**
Your credential is now ready to use with encrypted tool arguments.
Conversation will appear here...
) : ( transcript.map((msg, i) => (t
represents
time elapsed in seconds
. This function favors slower responses in the first 30 seconds, then accelerates for human conversations. Adjust the threshold and coefficients to match your IVR timing and human conversation cadence.
### Click on “Create a Phone Number”
### Within the "Free Vapi Number" tab, enter your desired area code
### Vapi will automatically allot you a random phone number — free of charge!
2. Enter your phone number and Twilio credentials, then click "Import".
sip:@sip.vapi.ai
**In this quickstart, you'll learn to:**
* Set up an outbound campaign with customer data
* Configure personalized feedback collection calls
* Launch and monitor campaign performance
* Access detailed call outcomes and analytics
## Prerequisites
* A [Vapi account](https://dashboard.vapi.ai)
* Phone number set up in your organization with a provider like Twilio (Vapi free numbers do not work for Outbound Campaigns)
* Recipient information ready in CSV format
* An existing Assistant configured in your account
***
## 1. Launch a Campaign
## Key benefits
* **Intuitive UI**: Quickly set up campaigns in an easy-to-follow setup page
* **Personalized**: Use dynamic variables to personalized outreach
* **Analytics**: Get real-time monitoring and detailed analysis of call performance and outcomes
## Common use cases
* **Conversion Optimization**: Re-engage potential customers via targeted follow-up calls for abandoned carts
* **Appointment Reminders**: Reduce missed appointments with timely reminder calls
* **Customer Satisfaction**: Conduct post-service feedback and follow-up calls to enhance customer experiences
* **Subscription Renewals**: Facilitate timely renewals with proactive call reminders
* **Insurance Updates**: Verify and update policy details through targeted calls
## Campaign setup process
Outbound Call Campaigns follow a structured process:
Server URLs allow your application to **receive data** & **communicate with Vapi** during conversations. Conversation events can include:
* **Status Updates:** updates on the status of a call
* **Transcript Updates**: call transcripts
* **Function Calls:** payloads delivered when your assistant wants certain actions executed
* **Assistant Requests:** in certain circumstances, Vapi may ping your server to get dynamic configuration for an assistant handling a specific call
* **End of Call Report:** call summary data at the end of a call
* **Hang Notifications:** get notified when your assistant fails to reply for a certain amount of time
In our [quickstart guides](/quickstart) we learned how to setup a basic back-and-forth conversation with a Vapi assistant.
To build more complex & custom applications, we're going to need to get real-time conversation data to our backend. **This is where server URLs come in.**
Server URLs can be set in multiple places in Vapi. Each level has a different priority.
The server URL with the highest priority for a relevant event will be the one that Vapi uses to send the event to.
Server URLs can be set at **4 levels** in Vapi:
* **Account-wide:** you can set a server URL for your broader account
* **Phone Number:** server URLs can be attached to phone numbers themselves
* **Assistant:** assistants can be configured with a server URL
* **Function:** function calls themselves (under an assistant) can have a corresponding server URL
## Setting Server URLs
Here's a breakdown of where you can set server URLs in Vapi:
If no other server URL is set, Vapi will use this one.
assistantId or a minimal assistant, then enrich context asynchronously after the call starts using Live Call Control.
* Host your webhook close to us-west-2 to reduce latency, and target \< \~6s to allow for network jitter.
assistantId, assistant, squadId, and squad are ignored.
You must still respond within 7.5 seconds.
To transfer silently, set destination.message to an empty string.
For caller ID behavior, see Call features.
## Quick solution: Vapi CLI + Tunneling
Use the Vapi CLI webhook forwarder along with a tunneling service to test webhooks locally:
```bash
# Terminal 1: Set up tunnel (example with ngrok)
ngrok http 4242
# Terminal 2: Install and run Vapi CLI
curl -sSL https://vapi.ai/install.sh | bash
vapi listen --forward-to localhost:3000/webhook
```
Copy this public URL that Ngrok provides. This URL will be accessible from the open Internet and will forward traffic to your local machine.
You can now use this as a server URL in the various places you can [set server URLs](/server-url/setting-server-urls) in Vapi.
Feel free to follow any of our [quickstart](/quickstart) guides to get started with building assistants & conducting calls.
## Troubleshooting
Here's a list of a few things to recheck if you face issues seeing payloads:
* Ensure that your local server is running on the port you expect
* Ensure that you input the correct port to the `ngrok http {your_port}` command
* Ensure your route handling server URL events is a `POST` endpoint
* Ensure your path on top of the base forwarding url is set correctly (ex: `/callbacks/vapi`)
***
title: Server authentication
slug: server-url/server-authentication
--------------------------------------
When configuring webhooks for your assistant, you can authenticate your server endpoints by creating **Custom Credentials** and referencing them using a `credentialId`. This approach provides better security, reusability, and centralized management of your authentication credentials.
## Overview
Vapi now uses a **credential-based authentication system** where you:
1. **Create Custom Credentials** through the dashboard
2. **Reference credentials by ID** in your server configurations
3. **Reuse credentials** across multiple assistants, phone numbers, and tools
This replaces the previous inline authentication approach and provides better security and management capabilities.
## Quick start
You can create different types of authentication credentials:
* **Bearer Token**: Simple token-based authentication
* **OAuth 2.0**: OAuth 2.0 client credentials flow
* **HMAC**: HMAC signature-based authentication
## Authentication Types
### Bearer Token Authentication
The most common authentication method using a bearer token in the Authorization header.
#### Standard Authorization Header
The most common Bearer Token configuration uses the standard `Authorization` header with the Bearer prefix:
### OAuth 2.0 Authentication
For OAuth 2.0 protected endpoints, configure client credentials flow with automatic token refresh.
#### OAuth 2.0 Flow
1. Vapi makes a token request to your OAuth endpoint with client credentials
2. Your server validates the credentials and returns an access token
3. Vapi includes the access token in the Authorization header for webhook requests
4. When tokens expire, Vapi automatically requests new ones
#### Token Response Format
Your OAuth server should return:
```json
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600
}
```
### HMAC Authentication
For maximum security, use HMAC signature-based authentication to verify request integrity.
## Using Credentials
### In Assistant Configuration
Reference credentials in your assistant's server configuration:
### In Phone Number Configuration
Assign credentials to phone numbers for incoming call authentication:
### In Tool Configuration
Secure your function tool endpoints with credentials:
### Best Practices
**Agent Capabilities:**
* Greet users and ask about their voice agent needs
* Extract and store user information (name and city)
* Use variables in dynamic responses
* Handle escalation to human agents at any point
**What You'll Build:**
* Multi-node conversation flow with branching logic
* Variable extraction and liquid template usage
* Global escalation nodes for human transfer
* End-call automation with natural conversation termination
## Prerequisites
* A [Vapi account](https://dashboard.vapi.ai)
* For SDK usage: API key from the Dashboard
**Key Benefits:**
* **Visual Conversation Builder:** Easily prototype and demonstrate conversation flows visually.
* **Complex Flow Management:** Ideal for scenarios with numerous interaction paths, such as call centers, customer support, appointment scheduling, and onboarding processes.
* **Reliable Determinism:** Offers stronger control compared to single-prompt Assistants, ensuring predictable conversational paths even in highly complex flows.
* **Developer-Focused Flexibility:** Fully configurable via API, enabling selection of models, transcribers, and voices available throughout the Vapi platform.
* **Multilingual Support:** Seamlessly build multilingual conversation flows with language-specific nodes and prompts.
**Common Use Patterns:**
* **User Intent Manager:** Route user interactions based on specific intents.
* **Human Escalation Paths:** Allow users to transfer to human agents at any workflow stage.
* **Multilingual Flows:** Create dedicated conversation branches for different languages.
* **Customer-Specific Flows:** Differentiate workflows based on user profiles, such as new versus existing customers.
## Workflow structure
Workflows consists of node and edges. There are multiple types of nodes and a Workflow must have a start node, which is the main entry point for the conversation flow.
By default a Conversation Node is the start node, but it can be changed to a different type of note. Start nodes cannot be deleted and a Workflow must have exactly one.
## Node Types and Configuration
### Conversation Node
The Conversation Node is the default type of node. It's highly configurable and it's the main building block for conversation flows.
**Configuration options**
* **First Message**: Specify the initial spoken message when entering the node. This configuration is helpful if developers want the agent to speak first without waiting for user to say something.
* **Prompt**: Provide detailed instructions guiding agent responses and conversation direction, including response style and content. The prompt is the most important part of the Conversation Node. Building reliable and high-quality voice agents heavily depend on the quality of the prompt supplied.
* **Model/Voice/Transcriber Settings**: Individually configure the AI model, voice, and transcription services per node. This is similar to configuring Single Prompt Assistants.
* **Extract Variables**: Extract Variables lets users gather/extract variables from a conversation. These variables can be used as dynamic variables for the rest of the workflow via liquid syntax `{{ variable_name }}`. Variables can be configured by defining variable name and data type (String, Number, Boolean, Integer), writing a clear extraction prompt, and setting enums for String-type variables to constrain values.
### API Request Node
The API Request Node allows developers to make HTTP Requests to their API, custom endpoints, or automation services like Make, n8n, or Zapier. Developers can configure it to perform GET and POST requests. Request bodies must be formatted in [JSON Schema](https://json-schema.org/) (the body UI builder automatically does this).
### Transfer Call Node
Transfer calls to another phone number, including human agents or specialized voice agents.
Developers can specify a phone number destination and a [transfer plan](/call-forwarding#call-transfers-mode), which lets them specify a message or a summary of the call to the person or agent picking up in the destination number before actually connecting the caller.
### End Call Node
Terminal node to end calls explicitly. Configure with an optional closing message (via the first message field) to users before termination.
### Global Node
Allows routing to this node from any point in the workflow, commonly used for escalation purposes e.g. when user wants to jump from the pre-determined conversation flow to speaking to a human to address specific needs. This feature can be enabled via the Global toggle; developers must specify an Enter Condition that defines the condition for routing to the Global Node.
## Edges
A node is connected to another node via an edge. Developers can specify a condition (within the edge) that must be true (satisfied) for the conversation to flow from one node to the next.
#### AI-based conditions
Written in plain language and evaluated by LLMs:
```txt
User wanted to talk about voice agents
```
#### Logical conditions
For precise control using variables:
```txt
{{ city == "San Francisco" }}
```
#### Combined conditions
Mix logical operators with variables:
```txt
{{ customer_tier == "VIP" or total_orders > 50 }}
```
**Best practices for conditions:**
* Use descriptive, natural language for AI-based conditions
* Format conditions as: "User \[verb] \[rest of condition]"
* Extract variables as enums to enable reliable branching
* Test all conditional paths thoroughly
* Keep conditions simple and specific
A useful combination of features is to extract variables as enums and use them to branch conversation flows based on a specific set of tasks that the agent can help users with.
## Best practices
### Planning and design
* **Map conversation flows first** - Plan all possible user journeys before building
* **Use descriptive node names** - Make workflows easier to understand and maintain
* **Handle edge cases** - Add global nodes for common scenarios like user confusion
### Implementation
* **Keep prompts focused** - Each node should have a single, clear purpose
* **Test thoroughly** - Use the built-in calling feature to test all conversation paths
* **Use variables strategically** - Extract only necessary information and use it to personalize conversations
### Optimization
* **Monitor performance** - Review call logs and analytics to optimize workflows over time
* **Plan for scale** - Consider how workflows will perform with high call volumes
* **Version control** - Keep track of workflow changes and test before deploying
## Next steps
Ready to start building? Check out these resources:
* [**Workflows quickstart**](/workflows/quickstart) - Build your first workflow step-by-step
* [**Workflow examples**](/workflows/examples/appointment-scheduling) - Explore pre-built workflows for common use cases
* [**Custom Tools**](/tools/custom-tools) - Integrate external APIs and services into your workflows
* [**Dynamic Variables**](/assistants/dynamic-variables) - Advanced variable usage and personalization techniques
***
title: Appointment scheduling workflow
subtitle: >-
Build an AI receptionist workflow that schedules, reschedules, and cancels
appointments using Vapi workflows.
slug: workflows/examples/appointment-scheduling
description: >-
Build a voice AI appointment scheduling workflow with calendar integration,
availability checking, and automated confirmations using Vapi's workflow
builder.
--------
***
## 1. Create a Knowledge Base
***
## 1. Create a Knowledge Base
***
## 1. Create a Knowledge Base
***
## 1. Create a Knowledge Base
***
## 1. Create a Multilingual Knowledge Base
These three modules can be swapped out with **any provider** of your choosing; OpenAI, Groq, Deepgram, ElevenLabs, PlayHT, etc. You can even plug in your server to act as the LLM.
Vapi takes these three modules, optimizes the latency, manages the scaling & streaming, and orchestrates the conversation flow to make it sound human.
## Overview
The following are the models we currently run, with many more coming soon:
* **Endpointing** – Detects exactly when the user finishes speaking.
* **Interruptions** – Lets users cut in and interrupt the assistant.
* **Background noise filtering** – Cleans up ambient noise in real-time.
* **Background voice filtering** – Ignores speech from TVs, echoes, or other people.
* **Backchanneling** – Adds affirmations like “yeah” or “got it” at the right moments.
* **Emotion detection** – Detects user tone and passes emotion to the LLM.
* **Filler injection** – Adds “um”, “like”, “so” and other natural fillers to assistant responses.
### Endpointing
Endpointing is a fancy word for knowing when the user is done speaking. Traditional methods use silence detection with a timeout. Unfortunately, if we want sub-second response-times, that's not going to work.
Vapi's uses a custom fusion audio-text model to know when a user has completed their turn. Based on both the user's tone and what they're saying, it decides how long to pause before hitting the LLM.
This is critical to make sure the user isn't interrupted mid-thought while still providing sub-second response times when they're done speaking.
### Interruptions (Barge-in)
Interruptions (aka. barge-in in research circles) is the ability to detect when the user would like to interject and stop the assistant's speech.
Vapi uses a custom model to distinguish when there is a true interruption, like "stop", "hold up", "that's not what I mean, and when there isn't, like "yeah", "oh gotcha", "okay."
It also keeps track of where the assistant was cut off, so the LLM knows what it wasn't able to say.
### Background Noise Filtering
Many of our models, including the transcriber, are audio-based. In the real world, things like music and car horns can interfere with model performance.
We use a proprietary real-time noise filtering model to ensure the audio is cleaned without sacrificing latency, before it reaches the inner models of the pipeline.
### Background Voice Filtering
We rely quite heavily on the transcription model to know what's going on, for interruptions, endpointing, backchanneling, and for the user's statement passed to the LLM.
Transcription models are built to pick up everything that sounds like speech, so this can be a problem. As you can imagine, having a TV on in the background or echo coming back into the mic can severely impact the conversation ability of a system like Vapi.
Background noise cancellation is a well-researched problem. Background voice cancellation is not. To solve this, we built proprietary audio filtering model that's able to **focus in** on the primary speaker and block everything else out.
### Backchanneling
Humans like to affirm each other while they speak with statements like "yeah", "uh-huh", "got it", "oh no!"
They're not considered interruptions, they're just used to let the speaker know that their statement has been understood, and encourage the user to continue their statement.
A backchannel cue used at the wrong moment can derail a user's statement. Vapi uses a proprietary fusion audio text model to determine the best moment to backchannel and to decide which backchannel cue is most appropriate to use.
### Emotion Detection
How a person says something is just as important as what they're saying. So we've trained a real-time audio model to extract the emotional inflection of the user's statement.
This emotional information is then fed into the LLM, so knows to behave differently if the user is angry, annoyed, or confused.
### Filler Injection
The output of LLMs tends to be formal, and not conversational. People speak with phrases like "umm", "ahh", "i mean", "like", "so", etc.
You can prompt the model to output like this, but we treat our user's prompts as **sacred**. Making a change like this to a prompt can change the behavior in unintended ways.
To ensure we don't add additional latency transforming the output, we've built a custom model that's able to convert streaming input and make it sound conversational in real-time.
***
title: Vapi Voices
subtitle: Our curated selection of high-quality voices
slug: providers/voice/vapi-voices
---------------------------------
**Click on your assistant and then the "Transcriber" tab.**
**Select "google" on the Provider dropdown.**
**Click on "Publish" and talking with your assistant.**
## Best Practices
* **Operating Point** – Select the **Enhanced** model for the best accuracy in real-time voice agents.
* **Region** – Choose the region closest to your users to optimize latency.
* **Custom Vocabulary** – Use this feature to add key terms (e.g., product names) and leverage the *Sounds Like* option for tricky pronunciations.
***
title: Talkscriber
subtitle: What is Talkscriber?
slug: providers/transcriber/talkscriber
---------------------------------------
**What is Talkscriber?**
Talkscriber is an advanced AI-powered speech-to-text platform designed to deliver high-accuracy transcription and emotion detection. Focused on enterprise-grade solutions, Talkscriber provides secure, cost-effective, and flexible deployment options. This platform enhances business operations by converting spoken language into text and analyzing customer interactions for deeper insights.
**The Evolution of Speech-to-Text:**
Speech-to-text technology has significantly evolved, from basic voice recognition to sophisticated AI-driven transcription systems. Innovations in machine learning and natural language processing have paved the way for more accurate and efficient speech-to-text solutions. Talkscriber leverages these advancements to offer state-of-the-art transcription services that cater to modern enterprise needs.
**Overview of Talkscriber’s Offerings:**
Talkscriber offers a suite of AI-driven tools designed to support various applications:
**AI Transcription:**
Talkscriber’s core service is its AI-powered transcription technology, which converts spoken language into text with high accuracy. This technology supports multiple languages and dialects, making it versatile for global applications.
**Emotion Detection:**
Talkscriber includes advanced emotion detection capabilities, identifying emotions such as anger, joy, sadness, and surprise. This feature provides deeper insights into customer interactions and helps businesses understand their clients better.
**API:**
Talkscriber provides a robust API that allows developers to integrate its speech-to-text capabilities into their applications, ensuring low latency and high availability.
**AI Transcription Technology:**
Talkscriber’s AI transcription technology offers several key features and benefits:
**Features:**
* High Accuracy: Industry-leading transcription accuracy with a Word Error Rate (WER) under 4%.
* Real-time Transcription: Instantaneous conversion of speech to text.
* Multilingual Support: Supports multiple languages and dialects.
**Benefits:**
* Efficiency: Reduces the time needed to transcribe and analyze speech.
* Scalability: Handles large volumes of data efficiently.
* Cost-Effective: Provides high performance at a lower cost compared to other solutions.
**Emotion and Intent Detection:**
Talkscriber’s emotion detection capabilities enhance the analysis of customer interactions:
**Enhancing Interaction Analysis:**
* Emotion Detection: Identifies emotions at the utterance level, providing deeper insights.
* Purchase Intent Detection: Recognizes customer purchase intent, helping businesses tailor their strategies.
**Developer API:**
Talkscriber offers a comprehensive API for easy integration of their capabilities into various applications:
**Integration:**
* SDKs: Available for multiple programming languages.
* Comprehensive Documentation: Detailed guides and support for seamless implementation.
**Use Cases:**
* Business Solutions: Enhance operational efficiency and customer service.
* Market Research: Gain insights into customer behavior and preferences.
**Use Cases for Talkscriber:**
Talkscriber’s platform supports a wide range of applications across various sectors:
**Business Solutions:**
Improve business operations with accurate transcription and emotion detection.
**Customer Service:**
Enhance customer service by understanding and responding to customer emotions and intents.
**Market Research:**
Gain valuable insights into market trends and customer preferences through advanced speech analysis.
**Impact on Business Operations:**
Talkscriber is revolutionizing business operations by providing tools that enhance productivity and insights. By automating transcription and emotion detection, businesses can focus on innovation and strategy rather than manual processes.
**Innovation and Research:**
Talkscriber is committed to continuous innovation and research in speech AI. Their team of experts focuses on advancing the capabilities of AI transcription and emotion detection, exploring new applications, and refining existing technologies to stay at the forefront of the industry.
**AI Safety and Ethics:**
Ensuring the ethical use of AI is a core principle at Talkscriber. They implement robust safeguards to prevent misuse of their technology and are actively involved in promoting responsible AI development. Protecting user data and maintaining transparency in AI operations are central to their mission.
**Integrations and Compatibility:**
Talkscriber’s API allows seamless integration with various platforms and applications. This ensures that users can incorporate Talkscriber’s AI capabilities into their existing systems effortlessly, enhancing functionality and improving user experience.
***
title: AssemblyAI
slug: providers/transcriber/assembly-ai
---------------------------------------
## Universal-Streaming
Universal-Streaming is AssemblyAI's purpose-built speech-to-text model that delivers ultra-fast, immutable transcripts in \~300ms with intelligent endpointing and superior accuracy for voice agents. It eliminates common pain points like misheard account numbers, awkward pauses, and premature cutoffs, enabling more natural and successful voice interactions.
## How to use AssemblyAI as transcriber
This guide details how to setup AssemblyAI as a transcriber for your assistant.
**Click on your assistant and then the "Transcriber" tab.**
**Select "assembly-ai" on the Provider dropdown.**
***
title: GCP Cloud Storage
subtitle: Store recordings of chat conversations in GCP Cloud Storage
slug: providers/cloud/gcp
-------------------------
Your assistants can be configured to record chat conversations and upload
the recordings to a bucket in GCP Cloud Storage when the conversation ends. You will
need to configure the credential and bucket settings in the "Cloud Providers"
section of the "Provider Credentials" page in the Vapi dashboard.
See these [instructions](https://cloud.google.com/iam/docs/keys-create-delete) for generating service account keys for GCP.
See these [instructions](https://cloud.google.com/storage/docs/authentication/hmackeys) for generating HMAC Keys for Cloud Storage.
## Credential Settings
| Setting | Description |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Credential Reference Name | The credential reference name |
| GCP Service Account Key (JSON) | The service account key in JSON format |
| Bucket Name | The name of the bucket to upload recordings to |
| Bucket Region | The name of the region where the bucket is located |
| Bucket Path Prefix | An optional path prefix for recordings uploaded to the bucket. Supports [LiquidJS Date format](https://liquidjs.com/filters/date.html) templating - for example, `{{ "now" \| date: "%Y/%m/%d" }}` renders as YYYY/MM/DD. |
| HMAC Access Key | The HMAC access key for the GCP Cloud Storage API (This is a string of 24 characters when linked to a user account or a string of 61 characters when linked to a service account.) |
| HMAC Secret | The HMAC secret for the GCP Clodu Storage API (This is a 40-character base-64 encoded string.) |
## Example
***
title: Cloudflare R2
subtitle: Store recordings of chat conversations in Cloudflare R2
slug: providers/cloud/cloudflare
--------------------------------
Your assistants can be configured to record chat conversations and upload
the recordings to a bucket in Cloudflare R2 when the conversation ends. You will
need to configure the credential and bucket settings in the "Cloud Providers"
section of the "Provider Credentials" page in the Vapi dashboard.
See these [instructions](https://developers.cloudflare.com/r2/api/s3/tokens/) for generating R2 tokens and access keys.
## Credential Settings
| Setting | Description |
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Cloudflare Account ID | Your customer account id for Cloudflare |
| Cloudflare Account Email | The email address associated with the account id |
| Cloudflare API Key/Token | The value of an API Key/Token generated for the account (Cloudflare uses the terms API Key and API Token interchangeably) |
| Bucket Name | The name of the bucket in R2 to upload recordings to |
| Bucket URL | This is required only for buckets with a custom hostname or domain name. Enter the hostname for the bucket. You will need to set up a CORS policy in R2 for the hostname/domain name. See [instructions](https://developers.cloudflare.com/r2/buckets/cors/) for configuring CORS. |
| Bucket Path Prefix | An optional path prefix for recordings uploaded to the bucket. Supports [LiquidJS Date format](https://liquidjs.com/filters/date.html) templating - for example, `{{ "now" \| date: "%Y/%m/%d" }}` renders as YYYY/MM/DD. |
| Bucket Access Key ID | The access key id associated with the API token you generated for R2 (this a string of 32 characters) |
| Bucket Secret Access Key | The secret access key associated with the API token you generated for R2 (this is a string of 64 characters) |
## Example
***
title: Supabase S3 Storage
subtitle: Store recordings of chat conversations in Supabase Storage
slug: providers/cloud/supabase
------------------------------
Your assistants can be configured to record chat conversations and upload
the recordings to a bucket in Supabase Storage when the conversation ends. You will
need to configure the credential and bucket settings in the "Cloud Providers"
section of the "Provider Credentials" page in the Vapi dashboard.
See these [instructions](https://supabase.com/docs/guides/storage/s3/authentication) for generating Supabase tokens and access keys, and finding your endpoint and region.
## Credential Settings
| Setting | Description |
| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Bucket Name | The name of the bucket in Supabase Storage to upload recordings to |
| Storage Region | The region of the Supabase project |
| Storage Endpoint | The endpoint of the Supabase Storage to upload recordings to |
| Bucket Path Prefix | An optional path prefix for recordings uploaded to the bucket. Supports [LiquidJS Date format](https://liquidjs.com/filters/date.html) templating - for example, `{{ "now" \| date: "%Y/%m/%d" }}` renders as YYYY/MM/DD. |
| Storage Access Key ID | The access key id for Supabase Storage |
| Storage Secret Access Key | The secret access key for Supabase Storage, associated with the access key id |
## Example
***
title: Langfuse Integration with Vapi
description: >-
Integrate Vapi with Langfuse for enhanced voice AI telemetry monitoring,
enabling improved performance and reliability of your AI applications.
slug: providers/observability/langfuse
--------------------------------------
# Langfuse Integration
Vapi natively integrates with Langfuse, allowing you to send traces directly to Langfuse for enhanced telemetry monitoring. This integration enables you to gain deeper insights into your voice AI applications and improve their performance and reliability.
## What is Langfuse?
[Langfuse](https://langfuse.com/) is an open source LLM engineering platform designed to provide better **[observability](/docs/tracing)** and **[evaluations](/docs/scores/overview)** into AI applications. It helps developers track, analyze, and visualize traces from AI interactions, enabling better performance tuning, debugging, and optimization of AI agents.
## Get Started
Example trace in Langfuse: [https://cloud.langfuse.com/project/cloramnkj0002jz088vzn1ja4/traces/50163c14-9784-4cb9-b18e-23e924d0bb66](https://cloud.langfuse.com/project/cloramnkj0002jz088vzn1ja4/traces/50163c14-9784-4cb9-b18e-23e924d0bb66)
userId, assistantType), plus any other context you need.