VAPI + PostgreSQL: capture calls into bookings
Your phone rings during the lunch rush, someone asks for a table “around 7,” and you scribble it on whatever’s nearby. Later, you can’t read it. Or you forget to confirm it. That’s how bookings quietly disappear.
This kind of mess hits restaurant owners first, but front-of-house managers and the marketing person running “Book now” campaigns feel it too. With VAPI booking automation, calls turn into confirmed reservations stored in PostgreSQL, so you’re not playing catch-up all night.
Below you’ll see exactly what the workflow does, what you get out of it, and what you’ll need to run it reliably.
How This Automation Works
The full n8n workflow, from trigger to final output:
n8n Workflow Template: VAPI + PostgreSQL: capture calls into bookings
flowchart LR
subgraph sg0["Flow 1"]
direction LR
n0["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/webhook.dark.svg' width='40' height='40' /></div><br/>Trigger: Voice Request (VAPI)"]
n1["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/postgres.svg' width='40' height='40' /></div><br/>Update Data (Table Booking /.."]
n2["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/webhook.dark.svg' width='40' height='40' /></div><br/>Respond: Booking/Order Confi.."]
n3@{ icon: "mdi:cog", form: "rounded", label: "Wait For Response", pos: "b", h: 48 }
n3 --> n1
n0 --> n3
n1 --> n2
end
subgraph sg1["Flow 2"]
direction LR
n4@{ icon: "mdi:cog", form: "rounded", label: "Wait For Response1", pos: "b", h: 48 }
n5["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/webhook.dark.svg' width='40' height='40' /></div><br/>Trigger: Info Request (VAPI)"]
n6["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/postgres.svg' width='40' height='40' /></div><br/> Get Restaurant Info (Postgr.."]
n7["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/webhook.dark.svg' width='40' height='40' /></div><br/>Respond: Restaurant Details .."]
n4 --> n7
n5 --> n6
n6 --> n4
end
%% Styling
classDef trigger fill:#e8f5e9,stroke:#388e3c,stroke-width:2px
classDef ai fill:#e3f2fd,stroke:#1976d2,stroke-width:2px
classDef aiModel fill:#e8eaf6,stroke:#3f51b5,stroke-width:2px
classDef decision fill:#fff8e1,stroke:#f9a825,stroke-width:2px
classDef database fill:#fce4ec,stroke:#c2185b,stroke-width:2px
classDef api fill:#fff3e0,stroke:#e65100,stroke-width:2px
classDef code fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
classDef disabled stroke-dasharray: 5 5,opacity: 0.5
class n1,n6 database
class n0,n2,n5,n7 api
classDef customIcon fill:none,stroke:none
class n0,n1,n2,n5,n6,n7 customIcon
The Problem: Phone Calls Create “Invisible” Booking Loss
Reservation calls are deceptively expensive. Not because each one takes forever, but because they always land at the worst possible moment: a packed host stand, servers asking questions, a line forming at the door. You put someone on hold, they hang up. Or you take the details quickly and never get a proper confirmation out. Then there’s the follow-up headache: searching call logs, re-entering details into a system later, and trying to remember which “John” wanted a booth. It’s exhausting, honestly.
The friction compounds. A single missed call is annoying. A few per week becomes a revenue problem.
- Calls interrupt service, which means your team splits attention during peak hours.
- Handwritten notes and “I’ll enter it later” routines lead to double bookings and no-shows.
- Customers expect instant confirmation, and silence makes them book somewhere else.
- Even when you capture the booking, records end up inconsistent, so reporting and staffing decisions get messy.
The Solution: VAPI Answers, Confirms, and Writes to PostgreSQL
This workflow turns incoming voice requests into clean, structured database records. When someone calls to book a table, the workflow accepts the request through VAPI, waits for the conversation to finish, then saves the reservation into your PostgreSQL bookings table with the important details (name, phone number, party size, date, time, special requests, and status). After that, it returns a confirmation back to the caller in a natural voice response, so the customer hears the details and you get a proper record instantly.
It also handles the other kind of call that eats time: “Are you open on Sundays?” or “Where do I park?” Those info requests go through a second intake path, pull the right answer from your PostgreSQL restaurant_info table, and reply back over VAPI. You update the info once in the database and the assistant stays consistent, even when your staff rotates.
The workflow starts with two webhooks (one for bookings, one for info). Then Wait nodes give the voice interaction time to complete and data to load properly. Finally, PostgreSQL is updated or queried, and a voice response is returned through the webhook response.
What You Get: Automation vs. Results
| What This Workflow Automates | Results You’ll Get |
|---|---|
|
|
Example: What This Looks Like
Say your restaurant gets about 20 booking or info calls on a Friday. Manually, even a “fast” call takes maybe 4 minutes between answering, clarifying details, and confirming, which is roughly 80 minutes of interruptions. With this workflow, you spend close to 0 minutes on most of those calls: the webhook triggers instantly, VAPI handles the conversation, and PostgreSQL is updated in the background. You may only step in for the odd edge case, so you’re buying back about an hour on the nights that matter.
What You’ll Need
- n8n instance (try n8n Cloud free)
- Self-hosting option if you prefer (Hostinger works well)
- VAPI to receive and respond to voice calls
- PostgreSQL for bookings, orders, and restaurant info tables
- VAPI API credentials (get them from your VAPI dashboard)
Skill level: Intermediate. You’ll connect accounts, set webhook endpoints, and create the PostgreSQL tables from the provided schema.
Don’t want to set this up yourself? Talk to an automation expert (free 15-minute consultation).
How It Works
A customer calls and the voice request hits n8n. The workflow begins with a webhook that receives the VAPI call payload, which includes what the caller is trying to do and the extracted details from the conversation.
The workflow waits for the conversation to settle. A short Wait is used so the assistant has time to finish gathering the booking details (party size, requested date and time, and special requests) before anything gets stored or replied to.
Bookings are saved (or updated) in PostgreSQL. The workflow upserts into your bookings table, so you get one clean record per reservation, with a status and timestamp you can audit later.
The caller gets a confirmation or an info response. For bookings, the webhook response returns a spoken confirmation with the reservation details. For info requests, PostgreSQL is queried from the restaurant_info table, then a natural language answer is returned to VAPI.
You can easily modify the confirmation wording to match your tone based on your needs. See the full implementation guide below for customization options.
Step-by-Step Implementation Guide
Step 1: Configure the Webhook Trigger
Set up the two webhook entry points that start each flow: booking requests and info requests.
- Add a Voice Request Intake webhook node and set HTTP Method to
POST. - Set Path to
9f6b9125-0b75-41c2-87a9-1b6746c89e2eand set Response Mode toresponseNode. - Add an Info Request Intake webhook node and set HTTP Method to
POST. - Set Path to
efe2c13f-1ba5-46e1-9996-57bdc6041973and set Response Mode toresponseNode.
⚠️ Common Pitfall: Both webhook nodes must use responseNode so the corresponding Return Booking Confirmation and Return Restaurant Info nodes can send the HTTP response.
Step 2: Connect Postgres for Data Operations
Configure database nodes to upsert bookings and retrieve restaurant details.
- Add Upsert Booking Records and set Operation to
upsert, Schema topublic, and Table toid. - Credential Required: Connect your postgres credentials in Upsert Booking Records.
- Add Fetch Restaurant Details and set Operation to
select, Schema topublic, and Table toid. - Credential Required: Connect your postgres credentials in Fetch Restaurant Details.
⚠️ Common Pitfall: Verify the id table and columns exist in the public schema before running the workflow, otherwise the upsert/select will fail.
Step 3: Set Up Wait Nodes for Asynchronous Replies
These wait nodes pause execution until a callback or external action resumes the flow.
- Add Await Booking Reply and connect Voice Request Intake → Await Booking Reply.
- Add Await Info Reply and connect Fetch Restaurant Details → Await Info Reply.
- Ensure Await Booking Reply outputs to Upsert Booking Records and Await Info Reply outputs to Return Restaurant Info to match the execution flow.
The execution order is linear with no parallel branches: Voice Request Intake → Await Booking Reply → Upsert Booking Records → Return Booking Confirmation, and Info Request Intake → Fetch Restaurant Details → Await Info Reply → Return Restaurant Info.
Step 4: Configure Webhook Responses
Return JSON responses to the original webhook callers with tool call IDs and results.
- In Return Booking Confirmation, set Respond With to
jsonand Response Body to={ "results": [ { "toolCallId": "{{ $('Voice Request Intake').item.json.body.message.toolCalls[0].id }}", "result": "{{ $json.status }}" } ] }. - In Return Restaurant Info, set Respond With to
jsonand Response Body to={ "results": [ { "toolCallId": "{{ $('Info Request Intake').item.json.body.message.toolCalls[0].id }}", "result": "{{ $json.available }}" } ] }. - Connect Upsert Booking Records → Return Booking Confirmation and Await Info Reply → Return Restaurant Info.
⚠️ Common Pitfall: The response body expressions reference Voice Request Intake and Info Request Intake. Ensure those nodes run in the same execution so the expressions resolve.
Step 5: Test and Activate Your Workflow
Validate both webhook paths and ensure database operations and responses work end-to-end.
- Use Execute Workflow and send a POST request to the Voice Request Intake webhook URL with sample booking payload data.
- Confirm Upsert Booking Records runs and Return Booking Confirmation returns a JSON response containing the
toolCallIdandstatus. - Send a POST request to the Info Request Intake webhook URL and verify Fetch Restaurant Details runs, then Return Restaurant Info returns the
availablevalue. - When testing is successful, toggle the workflow to Active to enable production use.
Common Gotchas
- VAPI credentials can expire or need specific permissions. If things break, check your VAPI dashboard keys and webhook settings first.
- If you’re using Wait nodes or external voice processing, processing times vary. Bump up the wait duration if downstream nodes fail on empty responses.
- PostgreSQL inserts fail quietly when the table schema doesn’t match your fields. Double-check column names like booking_time, party_size, and status before blaming the webhook.
Frequently Asked Questions
About 45 minutes if your PostgreSQL database is ready.
No. You’ll mostly connect VAPI, paste credentials, and map fields into PostgreSQL. You may do a tiny bit of copy-paste for the table schema.
Yes. n8n has a free self-hosted option and a free trial on n8n Cloud. Cloud plans start at $20/month for higher volume. You’ll also need to factor in VAPI’s per-minute voice costs for live calls.
Two options: n8n Cloud (managed, easiest setup) or self-hosting on a VPS. For self-hosting, Hostinger VPS is affordable and handles n8n well. Self-hosting gives you unlimited executions but requires basic server management.
Yes, but plan your data model first. Most teams add a location_id field to the bookings table, then route calls to the right location based on the dialed number or a quick question in the voice flow. You can also split the intake by using separate webhooks per location in n8n, then writing into the same PostgreSQL database with different location values. If you want different scripts per location, change the confirmation text returned in the “Return Booking Confirmation” response.
Usually it’s an invalid or rotated API key in VAPI, or the webhook URL in VAPI doesn’t match your n8n production URL. Also check that your n8n workflow is active and reachable from the public internet (self-hosted instances often get blocked by firewall rules). If failures happen only during rush periods, you may be hitting rate limits or timeouts, so increasing the Wait time can help.
It depends on your hosting, but it’s built to handle multiple simultaneous voice requests. On n8n Cloud you’ll be limited by your monthly executions, while self-hosting is mostly limited by your server resources and database performance. For many small restaurants, handling dozens of calls per hour is realistic if PostgreSQL is indexed and your VAPI plan supports the volume. If you expect heavy spikes, test with a busy-hour simulation before going live.
For voice workflows like this, n8n is usually a better fit because you control the webhooks, the waits, and the database writes without paying extra for branching logic. Zapier and Make can work, but they get awkward when you need two separate intakes (booking vs info) and you want to upsert into PostgreSQL reliably. Another practical point: self-hosting n8n can keep execution costs predictable when call volume grows. If your use case is just “send me an email when someone calls,” Zapier is fine. If you want confirmed bookings in a real database, this is the kind of workflow n8n shines at. Talk to an automation expert if you want a quick recommendation.
Once this is running, the phone can ring all it wants. Your bookings still land in PostgreSQL, confirmations still go out, and your team gets to stay focused on the guests in front of them.
Need Help Setting This Up?
Our automation experts can build and customize this workflow for your specific needs. Free 15-minute consultation—no commitment required.