Build an AI Voice Agent with Vapi

Build a voice AI receptionist for a pizza restaurant using Vapi.

Introduction

30 Second Summary

Ever called a restaurant and been greeted by a voice that sounds human but is actually AI? Voice agents are replacing hold music and missed calls for businesses everywhere.

In this project, you will build an AI voice receptionist for a fictional pizza restaurant. You'll configure its personality, give it tools to look up the menu and take orders, and embed it as a voice widget on a web page.

What You'll Build

A voice-powered AI receptionist for "Cosmo's Pizza" that greets callers, answers menu questions, and takes pizza orders through a web-based voice widget.

By the end of this project, you'll have:

  • A fully configured Vapi voice assistant with a custom persona and system prompt.
  • Function tools attached to the assistant for menu lookup and order-taking.
  • A local HTML page with an embedded voice widget for real-time conversation.
  • Secret Mission: Add structured data extraction to automatically capture order details as JSON after each call.

Are there any prerequisites?

None. This project includes setup for all required tools. You just need a web browser and a microphone.

Set Up Your Vapi Account

Before you can build your voice agent, you need an account on the platform that hosts it. Vapi is a voice AI platform that handles the entire speech pipeline for you.

In this step, you will create your Vapi account, locate your Public API Key, and install the code editor you will use later to build the voice widget.

In this step, get ready to:
  • Create a Vapi account with $10 in free credits.
  • Find and note your Public API Key.
  • Install VS Code for building the web widget later.
Create a Vapi account

Vapi gives every new account $10 in free credits. No credit card is required. That is more than enough to cover all the testing in this project.

  • Open your browser and go to dashboard.vapi.ai.
  • Click Sign Up and create your account using your email or a social login.
  • After signing up, you will land on the Vapi Dashboard home page.

What is Vapi?

Vapi is a developer platform for building AI voice agents. It connects speech-to-text, a large language model, and text-to-speech into a single pipeline so your agent can hold natural phone or web conversations.

Your $10 in free credits covers approximately 100+ minutes of voice testing at the platform rate of $0.05 per minute plus provider costs.

Orient yourself in the Dashboard

The Vapi Dashboard is where you will build, configure, and test your voice assistant. Getting familiar with the sidebar now saves time in later steps.

  • Look at the left sidebar. You will see sections for Assistants, Phone Numbers, Tools, and Logs.
  • Click on your profile icon in the top right corner of the Dashboard.
  • Select Vapi API Keys from the dropdown menu.
  • Find your Public Key and copy it somewhere safe (a sticky note, a text file, or your clipboard). You will need this later for the web widget.

Why do I need the Public API Key?

The Public API Key lets the voice widget on your web page connect to your Vapi account. Without it, the widget would not know which assistant to reach.

Keep your key accessible

Paste the key into a temporary text file or note-taking app. You will use it in Step 4 when you build the HTML page.

Install VS Code

You will use VS Code to create the HTML file for your voice widget. It is a free code editor that runs on macOS, Windows, and Linux.

  • Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
  • Type Visual Studio Code and press Enter.

✔️ VS Code opened

You are all set. VS Code is already installed on your machine.

ⓧ I don't have VS Code yet

  • Open your browser and go to code.visualstudio.com.
  • Click the download button for your operating system (macOS or Windows).
  • Run the installer and follow the on-screen prompts to complete the installation.
  • Once installed, open VS Code using the search method above.

VS Code won't open after installing?

On macOS, make sure you dragged the app into your Applications folder before opening it. On Windows, try restarting your computer after installation.

Help me troubleshoot my VS Code installation.

Your accounts and tools are ready. Next up, you will create your voice assistant and give it a personality.

Create Your Voice Assistant

Your Vapi account is ready and you know where everything lives in the Dashboard. Now it's time to build the actual voice agent that will answer calls for Cosmo's Pizza.

In this step, you'll create an assistant, write a system prompt that defines its personality, and test it live in the browser. The system prompt is the single most important piece of a voice agent. It controls how the agent greets callers, how long its answers are, and what it does when someone places an order.

In this step, get ready to:
  • Create a new assistant from a blank template.
  • Write a system prompt that defines the agent's persona and rules.
  • Test your voice agent live in the browser.
Create a new assistant

Every voice agent in Vapi starts as an assistant. An assistant holds the system prompt, the model configuration, and the first greeting message the caller hears.

  • In the Vapi Dashboard, click Assistants in the left sidebar.
  • Click Create Assistant.
  • Select Blank Template as your starting point.
  • Change the assistant name to Cosmo's Pizza Receptionist.

Why start with a Blank Template?

Vapi offers pre-built templates, but starting blank gives you full control over the system prompt and model. You'll understand exactly what each setting does because you configured it yourself.

Write the system prompt

The system prompt tells the LLM who it is, how it should behave, and what rules to follow. For a voice agent, keeping responses short is critical because long answers feel unnatural in a phone conversation.

  • In your assistant's configuration, find the System Prompt field.
  • Paste the following system prompt into the field:
You are a friendly receptionist for Cosmo's Pizza. Your job is to greet customers, help them with the menu, and take their orders.

Rules:
- Keep responses under 2 sentences.
- When a customer places an order, confirm it by reading back the details.
- Always offer to help with the menu if the customer seems unsure.
- Be warm, upbeat, and professional.

What does this prompt do?

The first line sets the agent's identity and purpose. The rules section constrains its behavior so conversations feel natural and efficient over voice.

The 2-sentence limit is especially important. Unlike a chatbot, a voice agent that rambles for 30 seconds frustrates callers. Short responses keep the conversation flowing back and forth like a real phone call.

Configure the first message and model

The first message is what callers hear the moment the agent picks up. The model determines how smart and fast the agent's responses are.

  • Find the First Message field in the assistant configuration.
  • Set it to: Thanks for calling Cosmo's Pizza! How can I help you today?.
  • Scroll to the model section and set the model to OpenAI gpt-4o.
  • Click Publish to save your changes.

Why gpt-4o?

GPT-4o balances intelligence with speed. Voice agents need fast responses (Vapi targets around 800 milliseconds end-to-end) and gpt-4o is optimized for low-latency use cases.

Now test your agent to make sure it sounds right.

  • Click Talk to Assistant at the top of the assistant view.
  • Grant microphone access when your browser asks.
  • Say something like "What's on the menu?" and listen to the agent's response.
  • End the call when you're done testing.

You should hear the agent greet you with the first message and respond to your questions in short, friendly sentences.

Agent not responding?

Make sure you clicked Publish before testing. Unpublished changes won't take effect in the test call.

Check that your browser has microphone permissions enabled for the Vapi Dashboard. Help me troubleshoot my Vapi assistant not responding during a test call.

Your voice agent now has a personality and can hold a conversation. Next up, you'll give it function tools so it can actually look up the menu and take orders.

Add Function Tools

Your assistant can hold a conversation, but right now it only knows what's in its system prompt. What happens when a caller asks about today's specials or wants to place an order?

Function tools give your assistant the ability to take actions beyond conversation. In this step, you'll create two tools that let Cosmo's Pizza Receptionist look up menu items and take orders.

In this step, get ready to:
  • Create a menu lookup tool that retrieves pizza categories.
  • Create an order tool that captures customer pizza orders.
  • Attach both tools to your assistant and test the conversation.
Create a menu lookup tool

Tools in Vapi are functions your assistant can call during a conversation. The LLM decides when to trigger a tool based on the tool's description and the caller's request.

  • Click Tools in the left sidebar of the Vapi Dashboard.
  • Click Create Tool.
  • Select Function as the tool type.
  • Enter check_menu as the tool name.
  • In the Description field, enter: Look up available pizza menu items, toppings, and prices.
  • Add a parameter called category with type string.
  • Set the parameter description to: The menu category to look up: pizzas, toppings, sides, or drinks.
  • Save the tool.

What is function calling?

Function calling is how an LLM triggers actions in the outside world. You define a function's name, description, and parameters. During conversation, the model reads the description and decides when it's appropriate to call that function.

In a production setup, these function calls would hit a server endpoint that returns real data. For this project, the LLM handles responses gracefully based on your system prompt, which still teaches you the architecture.

Create an order tool

The second tool handles the other half of a pizza restaurant's job: taking orders. This tool needs more parameters because placing an order requires the pizza size, type, and customer name.

  • Return to the Tools page and click Create Tool again.
  • Select Function as the tool type.
  • Enter place_order as the tool name.
  • In the Description field, enter: Place a pizza order for the customer.
  • Add a parameter called pizza_size with type string and description: small, medium, or large.
  • Add a parameter called pizza_type with type string and description: the type of pizza.
  • Add a parameter called customer_name with type string and description: the customer's name for the order.
  • Save the tool.

Why separate tools instead of one big tool?

Each tool has a single responsibility. The LLM uses a tool's description to decide when to call it. A focused description like "look up menu items" is easier for the model to match to a caller's intent than a generic "do everything" tool.

Attach tools to your assistant and test

Creating tools makes them available in your account, but your assistant can only use tools that are explicitly attached to it.

  • Click Assistants in the left sidebar.
  • Select Cosmo's Pizza Receptionist.
  • Scroll down to the Tools section and expand it.
  • Add check_menu.
  • Add place_order.
  • Scroll up to the system prompt and update it to mention these tools. Add instructions telling the assistant to use check_menu when a caller asks about available items or prices, and place_order when a caller wants to order a pizza.
  • Click Publish to save your changes.

Why update the system prompt?

The LLM uses your system prompt as its primary instructions. Mentioning the tools by name and explaining when to use them makes the model more likely to call the right tool at the right time during a conversation.

Now test the updated assistant to see how it handles tool-related requests.

  • Click Talk to Assistant to start a voice conversation in your browser.
  • Ask about the menu (for example, "What pizzas do you have?").
  • Try placing an order (for example, "I'd like a large pepperoni pizza for Alex").

Your assistant should attempt to use the tools during conversation. It will acknowledge menu requests and confirm order details based on your system prompt.

Assistant not mentioning the menu or orders?

Make sure you clicked Publish after adding the tools and updating the system prompt. Changes in the Dashboard only take effect after publishing.

Check that both check_menu and place_order appear in the Tools section of your assistant's configuration. If they're missing, expand the Tools accordion and add them again.

Help me troubleshoot why my Vapi assistant isn't using the function tools I attached.

Your assistant now has real capabilities beyond basic conversation. Next up, you'll embed it as a voice widget on a web page so anyone can talk to your pizza receptionist in a browser.

Embed the Voice Widget on a Web Page

Your assistant now has tools at its disposal and holds natural conversations in the dashboard. Next, you'll bring it to life on an actual web page that anyone can visit and talk to.

Vapi provides a lightweight web widget that adds a floating voice button to any page. You'll build a simple HTML page for Cosmo's Pizza and embed the widget so visitors can start a conversation directly from their browser.

In this step, get ready to:
  • Create a styled HTML landing page for Cosmo's Pizza.
  • Embed the Vapi voice widget using your API key and assistant ID.
  • Test a live voice conversation through your browser.
Create the HTML file

Your voice agent needs a home on the web. You'll create a simple landing page that visitors see before they click the voice button.

  • Switch to VS Code.
  • Press Cmd+N (macOS) or Ctrl+N (Windows) to create a new file.
  • Press Cmd+S (macOS) or Ctrl+S (Windows) to save it. Name the file index.html and save it to your Desktop.
  • Paste the following code into your new file:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Cosmo's Pizza</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        body {
            font-family: Arial, sans-serif;
            background: #1a1a2e;
            color: #fff;
            min-height: 100vh;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            text-align: center;
            padding: 20px;
        }
        h1 {
            font-size: 3rem;
            margin-bottom: 10px;
        }
        .emoji {
            font-size: 4rem;
            margin-bottom: 20px;
        }
        p {
            font-size: 1.2rem;
            color: #ccc;
            max-width: 500px;
            line-height: 1.6;
        }
        .hint {
            margin-top: 40px;
            font-size: 0.9rem;
            color: #888;
        }
    </style>
</head>
<body>
    <div class="emoji">🍕</div>
    <h1>Cosmo's Pizza</h1>
    <p>Welcome! Click the voice button in the bottom-right corner to talk to our AI receptionist. Ask about our menu or place an order!</p>
    <p class="hint">Powered by Vapi Voice AI</p>
</body>
</html>

What does this code do?

This sets up a simple, centered landing page with a dark background. The <style> block uses Flexbox to center all content vertically and horizontally.

The body content includes a pizza emoji, the restaurant name, a message telling visitors how to use the voice button, and a subtle footer credit.

  • Save index.html with Cmd+S (macOS) or Ctrl+S (Windows).
  • Double-click index.html on your Desktop to open it in your browser.
  • You should see a dark page with a pizza emoji, "Cosmo's Pizza" as a heading, and the welcome message centered on screen.

See a blank page?

  • Make sure you saved the file with the .html extension, not .txt. VS Code sometimes defaults to plain text for new files.
  • Check that the file is saved to your Desktop and you are opening that same file in the browser.

Help me figure out why my HTML page is blank.

Add the Vapi widget script

The widget is a small JavaScript snippet that loads Vapi's SDK from a CDN and renders a floating voice button on your page. You'll need two values from the Vapi Dashboard: your Public API Key and your assistant ID.

  • Switch to the Vapi Dashboard in your browser.
  • Click Assistants in the left sidebar.
  • Click on your Cosmo's Pizza Receptionist assistant.
  • Copy the assistant ID displayed on the assistant's page.

Where is the assistant ID?

Navigate to Assistants in the left sidebar and click on your assistant. The ID is a long string of characters visible on the assistant's configuration page.

  • Switch back to VS Code.
  • In index.html, find the closing </p> tag for the hint paragraph (the line that says Powered by Vapi Voice AI).
  • Add the following script block between that </p> tag and the closing </body> tag:
    <script>
        var vapiInstance = null;
        const assistant = "your-assistant-id-here";
        const apiKey = "your-public-api-key-here";
        const buttonConfig = {};

        (function (d, t) {
            var g = document.createElement(t),
                s = d.getElementsByTagName(t)[0];
            g.src =
                "https://cdn.jsdelivr.net/gh/VapiAI/html-script-tag@latest/dist/assets/index.js";
            g.defer = true;
            g.async = true;
            s.parentNode.insertBefore(g, s);

            g.onload = function () {
                vapiInstance = window.vapiSDK.run({
                    apiKey: apiKey,
                    assistant: assistant,
                    config: buttonConfig,
                });
            };
        })(document, "script");
    </script>

What does this script do?

  • It declares two constants: assistant (your assistant's unique ID) and apiKey (your Public API Key from the dashboard).
  • The self-invoking function dynamically creates a <script> element that loads Vapi's widget SDK from the CDN.
  • Once the SDK loads, window.vapiSDK.run() initializes the widget with your credentials and renders a floating voice button in the bottom-right corner of the page.
  • Replace your-assistant-id-here with the assistant ID you copied from the dashboard.
  • Replace your-public-api-key-here with the Public API Key you noted earlier from your profile.
  • Save index.html.

Not sure which key to use?

You need the Public API Key, not the Private one. Click on your profile in the top right of the Vapi Dashboard, then select Vapi API Keys. The Public Key is safe to use in client-side code like this HTML file.

Help me find my Vapi Public API Key.

Test your voice widget

Everything is wired up. Time to have a conversation with your AI receptionist through the browser.

  • Switch to your browser and refresh the index.html page (or double-click the file on your Desktop again if you closed it).
  • Look for a floating voice button in the bottom-right corner of the page.
  • Click the voice button.
  • Your browser will ask for microphone access. Click Allow.
  • Speak to your assistant. Try saying something like "What pizzas do you have?" or "I'd like to place an order."

You should hear your AI receptionist greet you and respond to your questions in real time.

What is happening under the hood?

Your voice goes through a three-stage pipeline. First, Speech-to-Text (STT) converts your audio into text. Then the LLM (gpt-4o) processes the text and generates a response. Finally, Text-to-Speech (TTS) converts the response back into audio you hear.

This STT to LLM to TTS pipeline is the standard architecture behind every production voice agent.

Don't see the voice button?

  • Make sure you saved index.html after adding the script and refreshed the page in your browser.
  • Double-check that your assistant and apiKey values are wrapped in quotes and don't contain extra spaces.
  • Open your browser's developer console (Cmd+Option+J on macOS, Ctrl+Shift+J on Windows) and check for red error messages.

Help me debug why the Vapi voice button isn't appearing.

✔️ Awesome, I've got everything!

Great. Double check that you've saved your file and that the voice button works when you click it.

ⓧ I'd like to double check the full code

Here's the complete index.html file for comparison:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Cosmo's Pizza</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        body {
            font-family: Arial, sans-serif;
            background: #1a1a2e;
            color: #fff;
            min-height: 100vh;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            text-align: center;
            padding: 20px;
        }
        h1 {
            font-size: 3rem;
            margin-bottom: 10px;
        }
        .emoji {
            font-size: 4rem;
            margin-bottom: 20px;
        }
        p {
            font-size: 1.2rem;
            color: #ccc;
            max-width: 500px;
            line-height: 1.6;
        }
        .hint {
            margin-top: 40px;
            font-size: 0.9rem;
            color: #888;
        }
    </style>
</head>
<body>
    <div class="emoji">🍕</div>
    <h1>Cosmo's Pizza</h1>
    <p>Welcome! Click the voice button in the bottom-right corner to talk to our AI receptionist. Ask about our menu or place an order!</p>
    <p class="hint">Powered by Vapi Voice AI</p>

    <script>
        var vapiInstance = null;
        const assistant = "your-assistant-id-here";
        const apiKey = "your-public-api-key-here";
        const buttonConfig = {};

        (function (d, t) {
            var g = document.createElement(t),
                s = d.getElementsByTagName(t)[0];
            g.src =
                "https://cdn.jsdelivr.net/gh/VapiAI/html-script-tag@latest/dist/assets/index.js";
            g.defer = true;
            g.async = true;
            s.parentNode.insertBefore(g, s);

            g.onload = function () {
                vapiInstance = window.vapiSDK.run({
                    apiKey: apiKey,
                    assistant: assistant,
                    config: buttonConfig,
                });
            };
        })(document, "script");
    </script>
</body>
</html>

You now have a fully working voice AI widget on a real web page. In the next section, you'll take things further by automatically extracting structured data from every call.

Secret mission

Add Structured Data Extraction

Your voice agent takes orders, but right now those orders disappear after the call ends. In a real business, every order needs to land in a system. Can you set up automatic data extraction so every call produces clean, structured JSON?

Clean Up Your Resources

Clean Up Your Resources

This project runs on Vapi's free credits and a local HTML file. Resources on Vapi only cost money when you actively make calls, so there are no ongoing charges for leaving your assistant configured.

Decide whether to keep your resources running, pause them to come back later, or delete them entirely.

Resources you used:

  • Vapi assistant ("Cosmo's Pizza Receptionist") on dashboard.vapi.ai.
  • Vapi tools (check_menu, place_order) on dashboard.vapi.ai.
  • Vapi structured output ("Pizza Order") on dashboard.vapi.ai.
  • Local index.html file.

Keep everything running

No action needed. Choose this if you want to keep experimenting with your voice agent or plan to build on it later.

  • Your Vapi assistant, tools, and structured output stay configured at no cost until you make calls.
  • Your index.html file stays on your computer ready to open anytime.
  • Your $10 free credits remain available for future testing.

Pause - I'll come back to this later

Since Vapi only charges per call, there is nothing running in the background to pause. Your resources sit idle for free.

  • Close the browser tab with your Vapi dashboard.
  • Close VS Code if you don't need it for other work.
  • When you're ready to return, open dashboard.vapi.ai and your assistant will be exactly as you left it.

Delete - I don't want to use this again

Remove all project resources from Vapi and your computer. This cannot be undone.

  • In the Vapi dashboard, click Assistants in the left sidebar. Select Cosmo's Pizza Receptionist and delete it.
  • Click Tools in the left sidebar. Select check_menu and delete it. Then select place_order and delete it.
  • Click Structured Outputs in the left sidebar. Select Pizza Order and delete it.
  • Delete the index.html file from your computer. Right-click the file in Finder (macOS) or File Explorer (Windows) and select Move to Trash or Delete.

Nice Work!

Nice Work!

You just built an AI voice agent from scratch. Your Cosmo's Pizza receptionist can hold natural conversations, look up menu items, take orders, and even extract structured data from every call.

You've learned how to:

  • Built a voice AI receptionist with a custom personality and conversation rules using prompt engineering on the Vapi platform.
  • Configured function tools that give your agent capabilities beyond conversation, teaching the core pattern of how LLMs interact with external systems.
  • Deployed your agent as an embeddable web widget on a local HTML page that anyone can use to talk to your AI receptionist.
  • Added structured data extraction to automatically capture order information as JSON after each call.

Ready to quiz yourself?