Spam call rejection

Screen inbound calls and reject known spam using your Server URL

Use your Server URL to filter inbound calls before they reach your assistant. When an inbound call arrives, Vapi can ask your server which assistant to use via an assistant-request. In that moment, you can check the caller’s phone number against your spam list:

  • If the number is flagged as spam: return an error message to be spoken to the caller and end the call.
  • If the number is allowed: return a transient assistant configuration to proceed with the conversation.

Learn more about the request/response shapes on the Server events page.

How it works

  1. Configure a Server URL on the phone number, assistant, or organization.
  2. On inbound calls without a fixed assistantId (or if you prefer to decide dynamically), Vapi sends your server an assistant-request webhook.
  3. Your server validates the calling number and responds with either an error or an assistant object.

Your server must respond within ~7.5 seconds or the call may fail.

Example implementation

Below is a simple example using Node.js/Express. It checks the inbound caller (E.164) against a local spam list, then either rejects with an error or returns a transient assistant:

1import express from "express";
2
3const app = express();
4app.use(express.json());
5
6// Replace with your own data store or third‑party spam reputation API
7const spamNumbers = new Set(["+11234567890", "+15558675309"]);
8
9app.post("/webhooks/vapi", async (req, res) => {
10 const messageType = req.body?.message?.type;
11 if (messageType !== "assistant-request") {
12 return res.sendStatus(204);
13 }
14
15 const incomingNumber = req.body?.call?.from?.phoneNumber;
16
17 if (incomingNumber && spamNumbers.has(incomingNumber)) {
18 // Reject spam callers with a spoken error message
19 return res.json({
20 error: "Sorry, your number is blocked due to spam reports. If this is a mistake, please contact support."
21 });
22 }
23
24 // Allow the call: return a transient assistant configuration
25 return res.json({
26 assistant: {
27 name: "Inbound Receptionist",
28 firstMessage: "Hi there! How can I help you today?",
29 model: {
30 provider: "openai",
31 model: "gpt-4o",
32 messages: [
33 {
34 role: "system",
35 content: "You are a helpful receptionist. Answer succinctly and route the caller if needed."
36 }
37 ]
38 },
39 voice: {
40 provider: "11labs",
41 voiceId: "shimmer"
42 }
43 }
44 });
45});
46
47app.listen(3000, () => console.log("Server listening on port 3000"));

Response examples

  • Reject with a spoken error message:
1{ "error": "Sorry, your number is blocked due to spam reports." }
  • Proceed with a transient assistant configuration:
1{
2 "assistant": {
3 "firstMessage": "Hey there! How can I help you today?",
4 "model": {
5 "provider": "openai",
6 "model": "gpt-4o",
7 "messages": [
8 { "role": "system", "content": "You are a friendly inbound assistant." }
9 ]
10 },
11 "voice": { "provider": "11labs", "voiceId": "shimmer" }
12 }
13}

Tips

  • Keep your spam list in a database or use a reputation API for accuracy.
  • If you prefer to use a saved assistant, return { "assistantId": "asst_..." } instead of an inline assistant.
  • For local testing, see Developing locally.