setup-webhook
This skill configures webhook endpoints to receive real-time events from Vapi during calls, including transcripts, tool calls, and call summaries.
Identity proven by GitHub's verified organisation badge (VapiAI)
- Agents
- Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode
- License
- MIT (permissive)
- Pin
- ecd56bdpinned Oct 9, 2026
- Context cost
- about 2,000 tokenswhen the skill loads
- GitHub stars
- 66on vapiai/skills
- Scripts
- None found
What it does
“Configure Vapi server URLs and webhooks to receive real-time call events, transcripts, tool calls, and end-of-call reports. Use when setting up webhook endpoints, building tool servers, or integrating Vapi events into your application.”
Generated summary from the skill's own text
This skill configures webhook endpoints to receive real-time events from Vapi during calls, including transcripts, tool calls, and call summaries. It provides setup instructions for assistants, phone numbers, and organization-level URLs, along with example webhook servers in Express.js and Python that handle different event types. The skill also covers webhook authentication using Vapi credentials and local development techniques for testing.
When to use it
- Building a webhook server to receive Vapi call events and transcripts
- Implementing dynamic assistant configuration based on caller information
- Handling tool calls from Vapi assistants and returning results
- Processing end-of-call reports and call analytics
When not to
- Creating Vapi assistants or phone numbers without webhooks
- Integrating with services that do not support HTTP webhooks
Install
These commands install from the publisher's repository and need no account.
skills CLI
npx skills add vapiai/skills --skill setup-webhookInstalls from the repository's default branch, which may have changed since the commit we checked.
GitHub CLI 2.90 or later
gh skill install vapiai/skills setup-webhook@ecd56bd32688be8ea6fe54029445b536333d8d9cInstalls the commit we checked (ecd56bd).
Copy by hand
Download the folder at ecd56bd and put it in .claude/skills/setup-webhook for Claude Code and in .agents/skills/setup-webhook for Codex, Cursor, Gemini CLI, GitHub Copilot and OpenCode.
Copy for your agent
A prompt for any coding agent. It installs this skill from GitHub at the pinned commit, copies the files as they are, and runs nothing unless you ask.
Prompt
Install the agent skill "setup-webhook" by Vapi. Source, pinned to commit ecd56bd32688be8ea6fe54029445b536333d8d9c: https://github.com/vapiai/skills/tree/ecd56bd32688be8ea6fe54029445b536333d8d9c/setup-webhook 1. Download that folder at exactly this commit. Do not use the default branch. 2. Copy every file unchanged, keeping the folder structure, into .claude/skills/setup-webhook/ for Claude Code and .agents/skills/setup-webhook/ for Codex, Cursor, Gemini CLI, GitHub Copilot and OpenCode. Create the folders if they do not exist. 3. Do not edit the files, and do not run any script in the folder unless I ask you to. 4. When you are done, list the files you copied and where you put them. Listing and checks: https://www.agentnative.dev/skills/vapi/setup-webhook-skills
SKILL.md at the pin
---
name: setup-webhook
description: Configure Vapi server URLs and webhooks to receive real-time call events, transcripts, tool calls, and end-of-call reports. Use when setting up webhook endpoints, building tool servers, or integrating Vapi events into your application.
license: MIT
compatibility: Requires internet access and a Vapi API key (VAPI_API_KEY).
metadata:
author: vapi
version: "1.0"
---
# Vapi Webhook / Server URL Setup
Configure server URLs to receive real-time events from Vapi during calls — transcripts, tool calls, status changes, and end-of-call reports.
> **Setup:** Ensure `VAPI_API_KEY` is set. See the `setup-api-key` skill if needed.
## Overview
Vapi uses "Server URLs" (webhooks) to communicate with your application. Unlike traditional one-way webhooks, Vapi server URLs support bidirectional communication — your server can respond with data that affects the call.
## Where to Set Server URLs
### On an Assistant
```bash
curl -X PATCH https://api.vapi.ai/assistant/{id} \
-H "Authorization: Bearer $VAPI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"server": {
"url": "https://your-server.com/vapi/webhook",
"credentialId": "cred_abc123"
}
}'
```
Create the optional `credentialId` in **Dashboard > Custom Credentials**. Omit it only for a deliberately public endpoint.
### On a Phone Number
Phone-number updates also use a `server` object with `url` and optional `credentialId`. When updating through the API, first retrieve the number and preserve its existing `provider` discriminator in the PATCH body. The dashboard is the safest choice when the provider is unknown.
### At the Organization Level
Set a default server URL in the Vapi Dashboard under **Settings > Server URL**.
Priority order: Tool server URL > Assistant server URL > Phone Number server URL > Organization server URL.
## Event Types
| Event | Description | Expects Response? |
|-------|-------------|-------------------|
| `assistant-request` | Request for dynamic assistant config | Yes — return assistant config |
| `tool-calls` | Assistant is calling a tool | Yes — return tool results |
| `status-update` | Call status changed | No |
| `transcript` | Real-time transcript update | No |
| `end-of-call-report` | Call completed with summary | No |
| `hang` | Assistant failed to respond | No |
| `speech-update` | Speech activity detected | No |
## Webhook Server Example (Express.js)
```typescript
import express from "express";
const app = express();
app.use(express.json());
app.post("/vapi/webhook", (req, res) => {
const { message } = req.body;
switch (message.type) {
case "assistant-request":
// Dynamically configure the assistant based on the caller
res.json({
assistant: {
name: "Dynamic Assistant",
firstMessage: `Hello ${message.call.customer?.name || "there"}!`,
model: {
provider: "openai",
model: "gpt-4.1",
messages: [
{ role: "system", content: "You are a helpful assistant." },
],
},
voice: { provider: "vapi", voiceId: "Elliot", version: 2 },
transcriber: { provider: "deepgram", model: "nova-3", language: "en" },
},
});
break;
case "tool-calls":
// Handle tool calls from the assistant
const results = (message.toolCallList || []).map((toolCall: any) => ({
toolCallId: toolCall.id,
result: handleToolCall(
toolCall.name,
toolCall.parameters || toolCall.arguments
),
}));
res.json({ results });
break;
case "end-of-call-report":
// Process the call report
console.log("Call ended:", {
callId: message.call.id,
endedReason: message.endedReason,
cost: message.cost,
analysis: message.analysis,
artifact: message.artifact,
});
res.json({});
break;
case "status-update":
console.log("Call status:", message.status);
res.json({});
break;
case "transcript":
console.log(`[${message.role}]: ${message.transcript}`);
res.json({});
break;
default:
res.json({});
}
});
function handleToolCall(name: string, args: any): string {
// Implement your tool logic here
return `Result for ${name}`;
}
app.listen(3000, () => console.log("Webhook server running on port 3000"));
```
## Webhook Server Example (Python / Flask)
```python
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route("/vapi/webhook", methods=["POST"])
def vapi_webhook():
data = request.json
message = data.get("message", {})
msg_type = message.get("type")
if msg_type == "assistant-request":
return jsonify({
"assistant": {
"name": "Dynamic Assistant",
"firstMessage": "Hello! How can I help?",
"model": {
"provider": "openai",
"model": "gpt-4.1",
"messages": [
{"role": "system", "content": "You are a helpful assistant."}
],
},
"voice": {"provider": "vapi", "voiceId": "Elliot", "version": 2},
"transcriber": {"provider": "deepgram", "model": "nova-3", "language": "en"},
}
})
elif msg_type == "tool-calls":
results = []
for tool_call in message.get("toolCallList", []):
results.append({
"toolCallId": tool_call["id"],
"result": f"Handled {tool_call['name']}",
})
return jsonify({"results": results})
elif msg_type == "end-of-call-report":
print(f"Call ended: {message['call']['id']}")
print(f"Summary: {message.get('analysis', {}).get('summary')}")
return jsonify({})
if __name__ == "__main__":
app.run(port=3000)
```
## Webhook Authentication
Use a Vapi Custom Credential and place its ID in `server.credentialId`. Vapi supports Bearer Token, OAuth 2.0 client credentials, and HMAC credentials. Verify requests according to the credential you configured; HMAC header names, algorithms, timestamps, and payload formats are configurable, so do not assume a fixed `x-vapi-signature` format.
For a bearer credential, compare the incoming `Authorization: Bearer <token>` value with the token stored securely by your server. Never put the secret itself in an assistant or phone-number payload.
## Local Development
Use the Vapi CLI with a public tunnel. The CLI forwards from port 4242 to your app, but it does not create the public URL itself:
```bash
# Install the CLI
curl -sSL https://vapi.ai/install.sh | bash
# Terminal 1: expose the CLI listener
ngrok http 4242
# Terminal 2: forward events from the CLI to your app
vapi listen --forward-to localhost:3000/vapi/webhook
```
Set the Vapi server URL to the public ngrok URL. To skip the CLI and tunnel directly to the Express or Flask server instead:
```bash
ngrok http 3000
# Copy the ngrok URL and set it as your server URL
```
## End-of-Call Report Fields
The `end-of-call-report` event includes:
| Field | Description |
|-------|-------------|
| `call` | Full call object with metadata |
| `endedReason` | Why the call ended |
| `artifact` | Recording, transcript, messages, and other enabled artifacts |
| `analysis` | Configured summaries, structured data, and success evaluation |
| `cost` | Total call cost |
| `startedAt` / `endedAt` | Call timing, when included |
## References
- [Common Server URL Events](references/webhook-events.md) — Common event payloads and responses
- [Setting Server URLs](https://docs.vapi.ai/server-url/setting-server-urls) — Placement and priority
- [Server Authentication](https://docs.vapi.ai/server-url/server-authentication) — Custom Credentials
- [Local Development](https://docs.vapi.ai/server-url/developing-locally) — Testing webhooks locally
## Additional Resources
Vapi provides a **documentation MCP server** that gives compatible AI agents access to the Vapi knowledge base. Use its documentation search for advanced configuration, troubleshooting, SDK details, and anything beyond this skill.
To add the Vapi documentation MCP server manually in Claude Code, run:
```bash
claude mcp add vapi-docs -- npx -y mcp-remote https://docs.vapi.ai/_mcp/server
```
See the [Vapi MCP integration guide](https://docs.vapi.ai/cli/mcp) for setup instructions across supported agents.
From vapiai/skills at ecd56bd, shown as plain text under its license: MIT (permissive). The license text is in setup-webhook/SKILL.md.
View SKILL.md on GitHub at ecd56bdFiles
- SKILL.md8.5 KB · e62c559f1233
- references/
- webhook-events.md3.4 KB · 6336da69e753
2 files, 12 KB in total. Each file has a sha256 in the pin's manifest; the first 12 characters are shown.
Skill folder on GitHub at ecd56bdMore from Vapi
create-assistant
Designs and creates Vapi voice assistants for phone and web by managing system prompts, provider selection, tool integration, and API validation.
Claude Code, Codex, Cursor +4 · about 2.3K tokens · pinned 6 days ago
create-assistant
This skill designs and creates Vapi voice assistants for phone and web calls.
Claude Code, Codex, Cursor +4 · about 2.3K tokens · pinned 6 days ago
create-call
This skill creates one-off outbound phone calls, web calls, and batch calls via the Vapi API.
Claude Code, Codex, Cursor +4 · about 1.5K tokens · pinned 6 days ago
create-call
This skill enables agents to create outbound phone calls, web calls, and batch calls via the Vapi API.
Claude Code, Codex, Cursor +4 · about 1.5K tokens · pinned 6 days ago
create-campaign
This skill enables agents to create, manage, and diagnose Vapi outbound campaigns for reaching multiple contacts with personalized calls using the…
Claude Code, Codex, Cursor +4 · about 3.1K tokens · pinned 6 days ago
create-campaign
This skill creates, manages, and monitors Vapi outbound calling campaigns for multi-contact operations.
Claude Code, Codex, Cursor +4 · about 3.1K tokens · pinned 6 days ago
Related in Backend and APIs
databricks-apps-python
Enables agents to build Python backends for Databricks Apps using FastAPI, Flask, Dash, Streamlit, Gradio, or Reflex.
by DatabricksOfficial publisher
Contains scripts
Claude Code, Codex, Cursor +3 · about 2.9K tokens · pinned 6 days ago
setup-webhook
This skill configures Vapi server URLs and webhooks to receive real-time events from voice calls, including transcripts, tool calls, and end-of-call reports.
by VapiOfficial publisher
Contains scripts
Claude Code, Codex, Cursor +3 · about 2K tokens · pinned 6 days ago
speech-engine
This skill integrates ElevenLabs Speech Engine to add real-time voice conversations to custom agent runtimes.
by ElevenLabsOfficial publisher
Claude Code, Codex, Cursor +4 · about 2.4K tokens · pinned 6 days ago
airflow-plugins
Builds Airflow 3.1+ plugins that embed FastAPI apps, custom UI pages, React components, middleware, macros, and operator links directly into the Airflow UI…
by AstronomerOfficial publisher
Claude Code, Codex, Cursor +4 · about 5.8K tokens · pinned 6 days ago
authoring-go-sdk-tasks
Enables writing Airflow task logic in Go by implementing the Go SDK's native API.
by AstronomerOfficial publisher
Claude Code, Codex, Cursor +4 · about 2K tokens · pinned 6 days ago
authoring-java-sdk-tasks
This skill teaches how to write Airflow task logic in Java, Kotlin, or other JVM languages using the Airflow Java SDK.
by AstronomerOfficial publisher
Claude Code, Codex, Cursor +4 · about 2.4K tokens · pinned 6 days ago
Open roles at Vapi
5 of 11 open roles on the jobs board
- Member of Technical Staff, Agentic Release Engineer
San Francisco (Hybrid)
- Member of Technical Staff, DevOps
San Francisco, California, United States (Remote)
- Member of Technical Staff, Frontend
San Francisco, California, United States (Remote)
- Member of Technical Staff, Agentic Developer Experience
San Francisco (Remote)
- Solutions Engineer - NY
New York, New York, United States (Remote)