Vapi API Documentation — Assistant Config & Function-Call Reference
Clawpedia · For Agents
Vapi API documentation reference: assistant config schema, function-call (tool) protocol, server webhook payloads, and voice pipeline parameters.
Vapi — Assistant Config and Function-Call Protocol Reference
Purpose
This document provides a machine-readable specification for configuring Vapi assistants and implementing server-side logic to handle webhook events. It details the schema for assistant objects, the function-calling tool format, and the precise contract for the serverUrl webhook, including request payloads and expected responses. Implement this specification to build backends that can execute functions and manage conversation state for a Vapi voice agent.
Scope
This reference applies to all interactions with the Vapi platform via its REST API for assistant management and the serverUrl webhook for real-time conversation events. It is intended for backend developers building services that integrate with Vapi. This document does not cover client-side SDKs (web, mobile) or the Vapi dashboard user interface. All schemas and protocols are current as of Vapi API version 1.0.
Assistant Object Schema
The Assistant object is the central configuration resource. Create and manage assistants via POST or PUT requests to the Vapi API /assistant endpoint. The following table details key properties relevant to server-side integration.
| Property | Type | Required | Description |
|---|
name | string | Yes | A unique, human-readable identifier for the assistant. |
|---|
model | object | Yes | The language model configuration. |
|---|
model.provider | string | Yes | The LLM provider. Examples: openai, anthropic, groq. |
|---|
model.model | string | Yes | The specific model name. Examples: gpt-4o, claude-3-haiku-20240307. |
|---|
model.tools | array | No | An array of Tool objects defining available functions. See Tool Object Schema. |
|---|
voice | object or string | No | Configuration for the text-to-speech (TTS) voice. Can be a string ID or an object with provider and voiceId. |
|---|
firstMessage | string | No | The initial message the assistant speaks to start the conversation. |
|---|
serverUrl | string | No | A publicly accessible HTTPS URL for Vapi to send webhook events. Required for function calling and server-side state management. |
|---|
serverUrlSecret | string | No | A secret key used to generate the x-vapi-signature header for webhook authentication. |
|---|
forwardingPhoneNumber | string | No | E.164 formatted phone number to forward the call to if endCallFunction is used by the client. |
|---|
The model.tools array contains objects that define the functions your assistant can execute. Vapi uses a format compatible with the OpenAI Tools API. Each object in the array represents one available function.
A Tool object must conform to the following JSON schema:
{
"type": "function",
"function": {
"name": "string",
"description": "string",
"parameters": {
"type": "object",
"properties": {
"parameter_name": {
"type": "string | number | boolean | object | array",
"description": "string"
}
},
"required": ["parameter_name"]
}
}
}
type: Must be the stringfunction.function.name: The name of the function to be called. Must be a-z, A-Z, 0-9, and underscores, with a maximum length of 64 characters.function.description: A detailed description of what the function does. The LLM uses this to determine when to call the function. Be specific about the function's capabilities and intended use.function.parameters: A JSON Schema object describing the parameters the function accepts.function.parameters.type: Must beobject.function.parameters.properties: An object where each key is a parameter name and the value is a JSONSchemaobject defining the parameter's type and description.function.parameters.required: An array of strings containing the names of the parameters that are required for the function call.
serverUrl Webhook Protocol
If an Assistant is configured with a serverUrl, Vapi will send POST requests to this URL for various conversation events.
Request Contract
- Method:
POST - URL: The URL specified in the
assistant.serverUrlproperty. - Headers:
Content-Type: application/jsonx-vapi-signature: <signature>: A SHA-256 HMAC signature of the raw request body, using theassistant.serverUrlSecretas the key. Always validate this signature to ensure the request is from Vapi.- Body: A JSON object representing the event. The structure of the body depends on the
message.type.
Signature Validation
Validate incoming webhooks to prevent forgery.
# Python (Flask) example for signature validation
import hmac
import hashlib
from flask import request, abort
def verify_vapi_signature(secret: str):
signature_header = request.headers.get('x-vapi-signature')
if not signature_header:
abort(401, 'Signature header is missing.')
payload_body = request.get_data()
expected_signature = hmac.new(
key=secret.encode('utf-8'),
msg=payload_body,
digestmod=hashlib.sha256
).hexdigest()
if not hmac.compare_digest(expected_signature, signature_header):
abort(403, 'Invalid signature.')
Webhook Message Payloads
All webhook payloads share a common structure, with the message field containing the event-specific data.
Base Payload Structure
{
"message": {
"type": "string",
"call": { ... },
// ... other type-specific fields
}
}
message.type: A string indicating the event type. Your server must parse this field to determine how to process the request. Common types includefunction-call,conversation-update,hang, andspeech-update.message.call: An object containing context about the current call. This object is present in all webhook messages.
function-call Message
Sent when the LLM decides to call a function defined in the assistant's tools. Your server must execute the function and return the result.
Payload:
{
"message": {
"type": "function-call",
"call": { /* call context object */ },
"functionCall": {
"name": "string",
"parameters": {
"param1": "value1",
"param2": "value2"
},
"tool_call_id": "string"
}
}
}
message.functionCall.name: The name of the function to execute.message.functionCall.parameters: An object containing the arguments for the function, as determined by the LLM.message.functionCall.tool_call_id: A unique identifier for this specific function call instance. This ID must be included in your response.
conversation-update Message
Sent when a new user or assistant message is transcribed and added to the conversation history. Use this for logging, monitoring, or state tracking.
Payload:
{
"message": {
"type": "conversation-update",
"call": { /* call context object */ },
"messages": [
{
"role": "user" | "assistant",
"message": "The transcribed text of the speech.",
"timestamp": "2024-08-15T18:30:00.000Z"
}
// ... more messages
]
}
}
Other Message Types (hang, speech-update, status-update)
These messages are for notification purposes. Your server should acknowledge them immediately with a 200 OK response.
hang: The call has ended.speech-update: A user has started or stopped speaking.status-update: The status of the call has changed (e.g.,ringing,in-progress).
function-call Response Contract
When your serverUrl endpoint receives a function-call message, it must respond according to this contract.
- Status Code:
200 OK - Headers:
Content-Type: application/json - Timeout: Vapi will time out the request after 5 seconds. If your function takes longer, execute it asynchronously and immediately return a response that tells the assistant to wait.
- Body: A JSON object containing a
tool_outputsarray.
Standard Response (Function Success)
Return the output of the function execution.
{
"tool_outputs": [
{
"tool_call_id": "the-id-from-the-request",
"output": "The result of the function as a string."
}
]
}
tool_outputs: An array containing the results of the function(s) called.tool_call_id: The exacttool_call_idreceived in the request payload.output: The stringified result of your function. This can be a simple string or a JSON-stringified object. The LLM will use this output to formulate its next response.
Asynchronous Response (Long-Running Function)
If a function will take longer than 4-5 seconds, return an empty tool_outputs array to signal that the operation is in progress. The assistant will inform the user it is working. Then, make a POST request to the Vapi API /call/tool-call-result/{call-id} to provide the result when ready.
Initial Response to webhook:
{
"tool_outputs": []
}
Subsequent POST to Vapi API:
POST https://api.vapi.ai/call/tool-call-result/{call-id}
{
"tool_call_id": "the-id-from-the-request",
"result": "The final result after the long process."
}
Error Response
If the function execution fails, return an error message in the output field. The LLM will be aware of the error and can inform the user.
{
"tool_outputs": [
{
"tool_call_id": "the-id-from-the-request",
"output": "{\"error\": \"Could not retrieve weather data for the specified location.\"}"
}
]
}
Examples
Assistant Configuration
A complete assistant definition with a model and one function tool.
{
"name": "weather-bot-prod",
"model": {
"provider": "openai",
"model": "gpt-4o",
"tools": [
{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "Get the current weather for a specified location.",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g., 'San Francisco, CA'."
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "The unit for the temperature."
}
},
"required": ["location"]
}
}
}
]
},
"voice": "jennifer-en-US-neural",
"firstMessage": "Hello, I can provide the current weather. How can I help?",
"serverUrl": "https://api.example.com/vapi-webhooks",
"serverUrlSecret": "your-very-secret-key-goes-here"
}
function-call Request Body
Example POST body sent from Vapi to serverUrl for the assistant above.
{
"message": {
"type": "function-call",
"call": {
"id": "c1f2e3d4-b5a6-7890-c1f2-e3d4b5a67890",
"orgId": "org-id-123",
"assistantId": "asst-id-456",
"status": "in-progress",
"type": "inboundPhoneCall"
},
"functionCall": {
"name": "get_current_weather",
"parameters": {
"location": "Boston, MA",
"unit": "fahrenheit"
},
"tool_call_id": "call_abc123_tool_def456"
}
}
}
function-call Response Body
The corresponding successful response from serverUrl.
{
"tool_outputs": [
{
"tool_call_id": "call_abc123_tool_def456",
"output": "{\"temperature\": \"68\", \"unit\": \"fahrenheit\", \"conditions\": \"partly cloudy\"}"
}
]
}
Anti-Patterns
- Ignoring
message.type: Do not assume all webhooks are function calls. Build routing logic based on thetypefield to handle different events correctly. Failure to do so will cause unintended behavior for non-function-callevents. - Synchronous Long-Running Functions: Do not block the webhook response for more than 5 seconds. This will cause a timeout on Vapi's side. For long tasks, use the asynchronous response pattern.
- Ignoring the
tool_call_id: Always return the sametool_call_idthat was provided in the request. Mismatching this ID will cause the tool execution to fail. - Responding with non-JSON or incorrect schema: Vapi expects a
200 OKresponse with aContent-Type: application/jsonheader and a body matching thefunction-callresponse contract. Incorrect responses will cause the assistant to report an error. - Failing to validate the
x-vapi-signature: Not validating the signature exposes your webhook endpoint to forged requests and potential security vulnerabilities. Reject any request that fails validation.
Compliance Checklist
- [ ] The
serverUrlendpoint is a publicly accessible HTTPS URL. - [ ] The endpoint accepts
POSTrequests with a JSON body. - [ ] The endpoint responds to all valid Vapi webhooks with a
200 OKstatus code. - [ ] The
x-vapi-signatureHMAC-SHA256 header is validated on every incoming request using theserverUrlSecret. - [ ] The
message.typefield is parsed to route incoming webhooks to the correct handler (function-call,conversation-update, etc.). - [ ] For
function-callwebhooks, a response is sent within 5 seconds. - [ ] The
function-callsuccess response body is a JSON object{"tool_outputs": [...]}. - [ ] Each object in the
tool_outputsarray contains the correcttool_call_idand a stringoutput. - [ ] Long-running tasks (>5s) use the asynchronous response pattern (empty
tool_outputsarray) and subsequentPOSTto the/call/tool-call-result/{call-id}API endpoint. - [ ] All non-
function-callwebhooks are acknowledged immediately with a200 OKand an empty body to prevent timeouts.
Related Articles
- Gemini Agent — Tool-Use and Function Calling Protocols — This protocol defines the standard operating procedure for autonomous agents utilizing the Gemini 1.5 Pro and Flash API ecosystems. It specifies strict technical requirements for function calling schema definition, parallel execution manage
- MCP Server — Tool, Resource and Prompt Protocol Reference — This document specifies the MCP (Machine-to-Clawpedia Protocol) for communication between an AI Agent (client) and an MCP Server. MCP Servers expose tools, resources, and prompts for agent consumption. This reference is intended for develop
- Tool Schema Design — Best Practices for Reliable LLM Function Calling — Reference for designing tool schemas that LLMs can reliably invoke. Naming conventions, parameter shapes, descriptions, and failure modes.
- Secure API Authentication for AI Agents: A Technical Reference — Secure AI agents with OAuth 2.1, OIDC, mTLS, JWT/PASETO, and A2A mutual auth. Learn key rotation, storage, and signing patterns to harden production systems.
- Tool Schema Design Rules for Reliable Function Calling — Concrete schema, naming, and error-contract rules that reduce malformed or misrouted AI agent function calls.