No description
  • TypeScript 97%
  • Shell 2.8%
  • Dockerfile 0.1%
Find a file
2026-05-23 11:16:28 +10:00
plans Bump to v1.37.1 — add Transfer WPForms webhook 2026-05-19 14:53:49 +10:00
prisma Bump to v1.40.9 — iCal calendar feed for chauffeur schedule 2026-05-20 09:54:31 +10:00
scripts update.sh: use npm install instead of npm ci to handle cross-platform lock file 2026-05-20 14:18:22 +10:00
src Bump to v1.45.0 — fix multi-photo upload (one request per file) 2026-05-23 11:16:28 +10:00
.eslintrc.json Bump to v1.33.5 — ESLint setup, lint fixes, Prisma regen, audit fixes 2026-05-18 13:24:31 +10:00
.gitignore Include remaining signature extraction files in v1.29.2 2026-05-14 20:50:38 +10:00
auth.config.ts Bump to v1.16.1 — fix chauffeur portal redirect 2026-05-04 13:24:58 +10:00
auth.ts Bump to v1.30.0 — photo upload prefixed with chauffeur display name 2026-05-17 07:53:43 +10:00
CHANGELOG.md Bump to v1.45.0 — fix multi-photo upload (one request per file) 2026-05-23 11:16:28 +10:00
DEPLOYMENT.md Rename scripts and deployment guide; update README install instructions 2026-04-29 09:02:36 +10:00
docker-compose.yml Update docker-compose.yml 2026-05-04 09:24:14 +10:00
Dockerfile Build ACC booking management system v1.0 2026-04-28 05:43:06 +10:00
next-auth.d.ts Bump to v1.30.0 — photo upload prefixed with chauffeur display name 2026-05-17 07:53:43 +10:00
next.config.mjs Bump to v1.34.1 — fix deprecated serverComponentsExternalPackages config key 2026-05-18 14:08:58 +10:00
package-lock.json Update package-lock.json 2026-05-20 14:16:27 +10:00
package.json Bump to v1.45.0 — fix multi-photo upload (one request per file) 2026-05-23 11:16:28 +10:00
postcss.config.mjs Build ACC booking management system v1.0 2026-04-28 05:43:06 +10:00
prisma.config.ts Build ACC booking management system v1.0 2026-04-28 05:43:06 +10:00
README.md Bump to v1.42.0 — Vitest unit test suite (112 tests) 2026-05-20 14:16:18 +10:00
tailwind.config.ts Build ACC booking management system v1.0 2026-04-28 05:43:06 +10:00
task.md Bump to v1.45.0 — fix multi-photo upload (one request per file) 2026-05-23 11:16:28 +10:00
tsconfig.json Bump to v1.34.0 — upgrade Next.js 14 → 15, clear all high CVEs 2026-05-18 14:03:34 +10:00
vitest.config.ts Add Vitest unit tests for time-utils, car-utils, overtime-utils, pdf-parse-utils — 112 tests passing 2026-05-20 14:14:04 +10:00

ACC System

Web-based booking schedule for Always Classic Cars, replacing the Excel-based wedding booking spreadsheet.

Features

  • Schedule view — bookings grouped by date, dark slate date headers, past dates hidden by default; delete booking is accessed from the Edit Booking page (not the schedule) to prevent accidental deletion
  • Multi-car bookings — one job can assign multiple cars and chauffeurs
  • Inline editing — change chauffeur, pickup time, and duration directly from the schedule (desktop); mobile shows read-only card view — tap the pencil icon to open the full booking editor
  • Chauffeur status — gray (planning), blue (sent), green (accepted); when sent, tick/cross buttons let the chauffeur accept or decline directly from the schedule
  • Payment tracking — Waiting Deposit, Deposit Paid, Cash on Day, PIF, Hold (badges on schedule and print); per-car pricing with travel cost, discount, and running total; record individual payments (receipt number, date, amount) with live Amount Paid and Balance; deposit required shown as $100/car or full payment if booking is within 2 weeks; saved payments are read-only (delete only) to prevent accidental edits
  • Month/year navigation — click the month or year on the schedule to jump directly to any period
  • Victorian public holidays — displayed as badges on the schedule, fetched from the official VIC Gov iCal feed
  • Fleet management — full CRUD for cars; inactive cars are preserved if they have bookings
  • Chauffeur management — full CRUD for chauffeurs with licence, DOB, address, and DC licence fields; same soft-delete protection
  • Chauffeur availability calendar — mark chauffeurs unavailable for a day or date range (full day or time window); visible in the schedule dropdown; chauffeur portal shows a monthly calendar grid view
  • Availability warnings — unavailable or double-booked chauffeurs show with strikethrough in dropdowns; selecting one prompts a confirmation warning on both the schedule and booking edit pages
  • No more bookings toggle per date
  • Authentication — login required; session-based with JWT
  • Settings — manage admin accounts, booking sources, and integrations (add, edit, delete)
  • Traccar GPS tracking — optional integration with a Traccar GPS server; on multi-car jobs the chauffeur portal shows a "Cars Location" link that generates a day-limited share link showing all cars on the job in real time; uses device share + permissions (no group creation or device group reassignment)
  • Mobile friendly — responsive layout with hamburger drawer, card views, horizontal scroll on tables; mobile booking cards show badge, type, and sheet links on the first row with client name below; car cards show car, chauffeur, time, and route on a single wrapping line
  • Print schedule — date range picker opens a print-ready view showing only dates with bookings
  • Booking type — tag each booking with a type (Wedding, Birthday, School Formal, etc.); types are configurable from Settings and shown as a badge on the schedule
  • WPForms webhooks — webhook endpoints receive form submissions and auto-create bookings; wedding form (POST /api/webhooks/wpforms/wedding), general booking form (POST /api/webhooks/wpforms/general, supporting up to 6 vehicles with pickup/drop-off addresses, "same as previous" address inheritance, signature, booking type, photographer/videographer/contact-on-day), airport transfer form (POST /api/webhooks/wpforms/airport-transfer, supporting Airport Drop-off, Airport Pick-up, and Round Trip — round trips create two separate bookings on the respective departure and return dates with cross-reference notes), and transfer form (POST /api/webhooks/wpforms/transfer, same Drop-off/Pick-up/Round Trip logic with real pickup and drop-off addresses on both legs)
  • Schedule search — search box in the schedule filter bar; searches client names, emails, phone numbers, partner details, wedding planner, contact on day, notes, car names, chauffeur names, and routes; defaults to future bookings; Past / Future / This month filter pills narrow results further; paginated (20 dates per page) with Previous/Next controls
  • iCal calendar feed — chauffeurs subscribe to a personal secret URL in Apple Calendar or Google Calendar; jobs sync automatically with pickup time, car, client name, and address; generated from My Profile; regenerating the link invalidates the old one
  • Overtime on Day — chauffeur portal shows a "Record Overtime" button on today's job cards; chauffeur enters actual completion time, captures the client's signature on screen, and records the signer's name; admin can view, edit, or clear overtime from the Edit Booking form; cost is auto-calculated (⌈minutesOver / 15⌉ × $75, adjustable); completion time, cost, and signature shown on the client PDF; an overtime sign-off box is always printed on the chauffeur PDF
  • PDF booking sheet import — upload a booking PDF to pre-fill a new booking (cars, chauffeurs, times, client details, payment status, Booking Sheet URL auto-populated from OneDrive path); wedding imports also populate partner names/emails/phones, ceremony address, bride arrival time, reception address, wedding planner, contact on day, photographer, videographer, and per-car pickup address and pickup who; re-importing on an existing booking preserves each car's chauffeur status, assigned chauffeur, and notes; pasting an external signature URL into the Signature Image URL field and saving auto-downloads and stores it locally so it can be embedded in PDFs
  • PDF booking sheet generation — client and chauffeur PDFs auto-generated on WPForms webhook import and every booking save; saved to OneDrive with separate Client and Chauffeur Booking Sheet URL fields; chauffeur portal links to the chauffeur-specific PDF; wedding PDFs show Wedding Date, Partner 1/2 columns, Drink Type, and ceremony/reception sections; general booking PDFs show Booking Date, single client name/email/phone, and per-vehicle drop-off addresses; airport transfer PDFs include a Flight Details section (terminal, flight number, departure/arrival times); vehicles grouped by pickup person/address with cost breakdown; night transfer vehicles shown separately; overtime box on chauffeur PDF applies to all booking types; deleting a booking moves the job folder to a Cancelled sub-folder within the same year/month directory; PDFs are skipped for Hold bookings
  • Office signatures — manage staff signature images in Settings → Office Signatures; select the signatory per booking via a dropdown on the Edit Booking form; client signature (left) and office signature (right) appear at the end of the client PDF with signer name and Filled Out Date
  • Terms & Conditions — manage T&C text in Settings → Terms & Conditions; printed as a second page on the client booking PDF
  • Night transfer flag — mark a car row as a night transfer; shown with indigo shading on the schedule
  • Client details — store client names, email, and phone on each booking
  • Chauffeur portal — chauffeurs log in with their own credentials and see only their upcoming jobs, availability calendar, and profile; portal access is created and managed by admins from the chauffeur's profile page; an amber banner appears on all portal pages when profile fields are missing or the DC licence is not active on CPVV
  • Email password reset — chauffeurs can reset their password via a "Forgot password?" link on the login page; a time-limited link is emailed to their address; when admin creates portal access the chauffeur receives a set-password link automatically (no admin-set password required)
  • CPVV DC licence verification — verify a chauffeur's Driver's Certificate against the CPVV (Commercial Passenger Vehicles Victoria) public register; Verify button on the admin and chauffeur profile forms shows live name and accreditation status; DC ✓/✗ status badges on the chauffeurs list; saving with an unverified DC number prompts a confirmation; ABN field on chauffeur profile for invoicing
  • Reports — admin-only Reports tab with year-filtered dashboard: summary stats, bookings per month, jobs per car, chauffeur utilization, bookings by type/source/payment status, and a cross-year jobs-per-car grouped chart
  • Activity Log — admin-only audit trail recording every booking create, update, and delete with field-level diffs (old → new values); covers booking fields, car assignment changes (pickup time, chauffeur, duration, costs, addresses), and payment changes (receipt number, date, amount); chauffeur names resolved; filterable by action type and searchable by record or user; "View activity" button on the Edit Booking form jumps directly to that booking's history

Tech Stack

Installation

One-line install on any fresh Debian 12 or Ubuntu 22.04+ system:

curl -fsSL https://git.bennellit.com.au/sb/ACC-System/raw/branch/main/scripts/install.sh | sudo bash

This installs Node.js 20, clones the repo, builds the app, configures PM2, and creates the first admin account. See DEPLOYMENT.md for the full guide and Docker alternative.

To update an existing installation:

curl -fsSL https://git.bennellit.com.au/sb/ACC-System/raw/branch/main/scripts/update.sh | sudo bash

Production — Docker

docker compose up --build

The app runs on port 3000. The SQLite database is stored in a named Docker volume (acc_data) and survives container rebuilds.

Set AUTH_SECRET and APP_URL as environment variables — do not commit them to source control.

services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - DATABASE_URL=file:/data/acc.db
      - AUTH_SECRET=<your-secret>
      - APP_URL=https://yourdomain.com
    volumes:
      - acc_data:/data
    restart: unless-stopped
volumes:
  acc_data:

Development

Prerequisites

  • Node.js 18+
  • npm
# Install dependencies
npm install

# Apply database migrations and generate Prisma client
npx prisma migrate deploy
npx prisma generate

# Seed cars and chauffeurs
npx tsx prisma/seed.ts

# Create the first admin account
npx tsx prisma/create-user.ts admin@example.com password123 "Admin"

# Start the dev server
npm run dev

# Run unit tests (112 tests — time-utils, car-utils, overtime-utils, pdf-parse-utils)
npm test

Open http://localhost:3000. You will be redirected to the login page.

Environment

Create a .env file at the project root:

DATABASE_URL="file:./prisma/dev.db"
AUTH_SECRET="<generate with: node -e \"require('crypto').randomBytes(32).toString('base64')\">"
APP_URL="http://localhost:3000"   # set to your public URL in production (used in password reset emails)

# WPForms webhooks (shared secret for all three webhook endpoints)
WPFORMS_WEBHOOK_SECRET="<generate with: node -e \"require('crypto').randomBytes(32).toString('hex')\">"

# Signature image storage (defaults to /data/signatures in production)
# SIGNATURES_PATH="/data/signatures"

# Traccar GPS tracking (optional — enable in Settings → Integrations)
TRACCAR_USERNAME="admin@example.com"
TRACCAR_PASSWORD="yourpassword"
# Internal URL for server-side Traccar API calls (use direct IP to bypass Cloudflare/proxy)
# TRACCAR_INTERNAL_URL="http://192.168.1.x:8082"

Database Schema

BookingDate  1 ──< Booking  1 ──< BookingCar >── Car
                                │            >── Chauffeur
                                1──< BookingPayment
                                >── OfficeSignature
ChauffeurUnavailability >── Chauffeur
User >── Chauffeur (optional — chauffeur portal accounts)
User 1──< PasswordResetToken
Model Purpose
BookingDate One record per calendar date
Booking One job (payment, client details, notes, booking sheet URL, flight details, overtime)
BookingCar One car+chauffeur assignment within a job (time, duration, route, night transfer flag, overtime per car)
BookingPayment Individual payment records against a booking (receipt number, date, amount)
Car Fleet vehicle
Chauffeur Chauffeur with profile fields (licence, DOB, address, ABN)
ChauffeurUnavailability Unavailability record per chauffeur per day (optional time window and reason)
BookingSource Configurable booking source list (Website, EasyWeddings, etc.)
BookingType Configurable booking type list (Wedding, Birthday, Airport Transfer, etc.)
OfficeSignature Staff signature image + name for printing on client PDFs
User Admin or chauffeur portal login account
PasswordResetToken Time-limited tokens for chauffeur password reset / setup emails
SystemSettings Singleton row for global feature flags (Traccar enabled, base URL, T&C text)
BookingTraccarShare Cache of Traccar group share tokens per booking + date

Project Structure

src/
├── app/
│   ├── schedule/          # Main schedule view (RSC)
│   ├── bookings/          # New & edit booking forms
│   ├── cars/              # Fleet management
│   ├── chauffeurs/        # Chauffeur management + availability calendar
│   ├── settings/          # Settings (admin accounts, booking sources)
│   ├── reports/           # Reports dashboard
│   └── api/               # REST API routes
├── components/
│   ├── layout/Sidebar.tsx
│   ├── schedule/          # ScheduleView, DateHeader, BookingGroup, BookingCarRow
│   ├── chauffeurs/        # AvailabilityCalendar
│   ├── reports/           # StatCard, YearSelector, Charts
│   ├── forms/             # BookingForm, ChauffeurForm, PdfImportButton
│   └── ui/                # Badge, ConfirmDialog
└── lib/
    ├── prisma.ts           # Singleton PrismaClient (Prisma 7 driver adapter)
    ├── schemas.ts          # Zod validation schemas
    ├── availability.ts     # Shared overlap/unavailability logic
    ├── reports.ts          # Aggregation queries for Reports page
    ├── utils.ts            # formatTime, formatDuration, cn()
    ├── vicHolidays.ts      # Victorian public holidays iCal fetcher
    └── cpvv.ts             # CPVV public register DC licence lookup
auth.ts                     # NextAuth config (credentials + Prisma)
auth.config.ts              # Edge-safe auth config (used by middleware)
src/middleware.ts            # JWT-based route protection
prisma/
├── schema.prisma
├── seed.ts                 # Cars and chauffeurs
├── create-user.ts          # CLI script to create admin accounts
└── migrations/

OneDrive Sync (Booking Sheets)

The ACC System can serve booking sheet PDFs directly from the server, synced from OneDrive, so chauffeurs never need a Microsoft login to open them.

1. Install the onedrive client

Follow the official Debian installation guide (abraunegg/onedrive): https://github.com/abraunegg/onedrive/blob/master/docs/ubuntu-package-install.md

2. Authenticate (one-time)

Run as the user the service will run under. It prints a URL — open it in any browser, sign in with the Always Classic Cars Microsoft 365 account, then paste the response URL back into the terminal:

onedrive

Auth tokens are stored in ~/.config/onedrive/ — back these up.

3. Create the configuration files

mkdir -p /var/www/acc-system/onedrive

cat > ~/.config/onedrive/config << 'EOF'
sync_dir = "/var/www/acc-system/onedrive"
threads = "2"
monitor_interval = "30"
EOF

cat > ~/.config/onedrive/sync_list << 'EOF'
Documents/ACC Bookings
Pictures/000 wedding feedback photos/Uploaded
EOF

Adjust threads to match the number of CPU cores on the server.

4. Run the initial sync

Required once after any config change:

onedrive --sync --resync

Files will appear under:

  • /var/www/acc-system/onedrive/Documents/ACC Bookings/
  • /var/www/acc-system/onedrive/Pictures/000 wedding feedback photos/Uploaded/

5. Create the systemd service

--single-directory only supports one path, so the service runs without it — sync_list restricts what is synced.

printf '[Unit]\nDescription=OneDrive Sync\nAfter=network-online.target\nWants=network-online.target\n\n[Service]\nUser=root\nExecStart=/usr/bin/onedrive --monitor\nRestart=on-failure\nRestartSec=3\n\n[Install]\nWantedBy=multi-user.target\n' > /etc/systemd/system/onedrive.service

systemctl daemon-reload
systemctl enable onedrive
systemctl start onedrive
systemctl status onedrive

The sync_list file limits the sync to only the two configured folders. The service starts automatically on boot.

6. Configure the app

Add to .env:

# Linux / Debian production server
ONEDRIVE_SYNC_PATH="/var/www/acc-system/onedrive/Documents/ACC Bookings"
ONEDRIVE_PHOTOS_PATH="/var/www/acc-system/onedrive/Pictures/000 wedding feedback photos/Uploaded"

# Windows development (use forward slashes)
ONEDRIVE_SYNC_PATH="C:/Users/sb/OneDrive - Always Classic Cars/Documents/ACC Bookings"
ONEDRIVE_PHOTOS_PATH="C:/Users/sb/OneDrive - Always Classic Cars/Pictures/000 wedding feedback photos/Uploaded"

# Traccar GPS tracking (optional — enable in Settings → Integrations)
TRACCAR_USERNAME="admin@example.com"
TRACCAR_PASSWORD="yourpassword"
# Use direct IP to bypass Cloudflare/reverse-proxy for server-side API calls
# TRACCAR_INTERNAL_URL="http://192.168.1.x:8082"

WPForms Webhooks

When a customer submits a booking form on the website, WPForms can POST the data directly to ACC System, automatically creating a booking so staff don't need to re-enter enquiries. There are two webhook endpoints — one for the Wedding form and one for the General Booking form. Both share the same secret.

1. Add the env var

Add to .env:

SECRET=$(node -e 'console.log(require("crypto").randomBytes(32).toString("hex"))') && echo "WPFORMS_WEBHOOK_SECRET=\"$SECRET\"" >> /opt/acc-system/.env

2. Configure WPForms — Wedding form

In WordPress: WPForms → (Wedding form) → Settings → Webhooks → Add New

Setting Value
Request URL https://your-domain.com/api/webhooks/wpforms/wedding?secret=YOUR_SECRET
Request Method POST
Request Format JSON
Enable

Under Request Body, add one row per field using the + button. Leave the Secret field empty (the secret is already in the URL).

Important: For each row, type the key name in the left column, then use the dropdown on the right to select the matching form field — do not type the field ID as text. The field ID column below is only to help you identify the correct field in the dropdown.

Key Field ID
date 7
contactName 13
contactEmail 16
contactPhone 17
role 15
otherRole 19
partner1Name 18
partner1Email 65
partner1Phone 66
partner2Name 67
partner2Email 69
partner2Phone 71
nightTransferOnly 138
vehicle1 30
vehicle1Who 33
vehicle1Address 35
vehicle1Time 37
vehicle1Hours 51
requireVehicle2 41
vehicle2 40
vehicle2Who 45
vehicle2Address 46
vehicle2Time 52
vehicle2Hours 55
requireVehicle3 63
vehicle3 74
vehicle3Who 75
vehicle3Address 77
vehicle3Time 78
vehicle3Hours 82
requireVehicle4 83
vehicle4 85
vehicle4Who 86
vehicle4Address 88
vehicle4Time 89
vehicle4Hours 93
requireVehicle5 94
vehicle5 96
vehicle5Who 97
vehicle5Address 100
vehicle5Time 101
vehicle5Hours 104
requireVehicle6 106
vehicle6 108
vehicle6Who 109
vehicle6Address 111
vehicle6Time 112
vehicle6Hours 115
ceremonyAddress 119
brideArrivalTime 120
ceremonyTime 166
groomArrivalTime 165
receptionAddress 122
receptionTime 123
requireNightTransfer 126
nightVehicle1 139
nightAddress1 125
nightTime1 127
requireNightVehicle2 140
nightVehicle2 141
nightAddress2 142
nightTime2 143
contactOnDay 130
photographer 131
videographer 129
drinkType 164
specialInstructions 132
entryId Entry ID — select Entry ID from the "Other" section of the dropdown (not a regular field)
formSubmittedDate 134
signatureUrl 136
signedBy 137

3. Configure WPForms — General Booking form

In WordPress: WPForms → (General Booking 2026 form) → Settings → Webhooks → Add New

Setting Value
Request URL https://your-domain.com/api/webhooks/wpforms/general?secret=YOUR_SECRET
Request Method POST
Request Format JSON
Enable

Same rules apply — type the key name on the left, select the field from the dropdown on the right.

Key Field ID
date 7
contactName 13
contactEmail 16
contactPhone 17
bookingType 29
bookingTypeOther 19
vehicle1 30
vehicle1PickupAddress 35
vehicle1PickupTime 37
vehicle1DropoffAddress 43
vehicle1DropoffTime 44
vehicle1Hours 51
requireVehicle2 41
vehicle2 40
vehicle2SamePickup 59
vehicle2PickupAddress 46
vehicle2PickupTime 52
vehicle2SameDropoff 73
vehicle2DropoffAddress 53
vehicle2DropoffTime 54
vehicle2Hours 55
requireVehicle3 63
vehicle3 74
vehicle3SamePickup 76
vehicle3PickupAddress 77
vehicle3PickupTime 78
vehicle3SameDropoff 79
vehicle3DropoffAddress 80
vehicle3DropoffTime 81
vehicle3Hours 82
requireVehicle4 83
vehicle4 85
vehicle4SamePickup 87
vehicle4PickupAddress 88
vehicle4PickupTime 89
vehicle4SameDropoff 90
vehicle4DropoffAddress 91
vehicle4DropoffTime 92
vehicle4Hours 93
requireVehicle5 94
vehicle5 96
vehicle5SamePickup 98
vehicle5PickupAddress 100
vehicle5PickupTime 101
vehicle5SameDropoff 102
vehicle5DropoffAddress 103
vehicle5DropoffTime 105
vehicle5Hours 104
requireVehicle6 106
vehicle6 108
vehicle6SamePickup 110
vehicle6PickupAddress 111
vehicle6PickupTime 112
vehicle6SameDropoff 113
vehicle6DropoffAddress 114
vehicle6DropoffTime 116
vehicle6Hours 115
photographer 131
videographer 129
contactOnDay 130
specialInstructions 132
entryId Entry ID — select Entry ID from the "Other" section of the dropdown (not a regular field)
formSubmittedDate 134
signatureUrl 136
signedBy 137

4. Configure WPForms — Airport Transfer form

In WordPress: WPForms → (Airport Transfer form) → Settings → Webhooks → Add New

Setting Value
Request URL https://your-domain.com/api/webhooks/wpforms/airport-transfer?secret=YOUR_SECRET
Request Method POST
Request Format JSON
Enable

Same rules apply — type the key name on the left, select the field from the dropdown on the right.

Key Field
contactName Contact name
contactEmail Contact email
contactPhone Contact phone
airportService Service type ("Airport Drop-off", "Airport Pick-up", or "Round Trip")
vehicle Vehicle preference
departureDate Departure date (Drop-off / Round Trip)
pickupAddress Pickup address (Drop-off)
pickupTime Pickup time (Drop-off)
airportArrivalTime Time car must arrive at airport terminal (Drop-off)
dropoffTerminal Airport terminal (Drop-off)
flightDepartureTime Flight departure time (Drop-off)
returnDate Return date (Pick-up / Round Trip)
dropoffAddress Drop-off address (Pick-up)
flightNumber Flight number (Pick-up)
pickupTerminal Airport terminal (Pick-up)
flightArrivalTime Flight arrival time (Pick-up)
specialInstructions Special instructions
entryId Entry ID — select Entry ID from the "Other" section
formSubmittedDate Form submitted date
signatureUrl Signature URL
signedBy Signed by

5. Configure WPForms — Transfer form

In WordPress: WPForms → (Transfer form) → Settings → Webhooks → Add New

Setting Value
Request URL https://your-domain.com/api/webhooks/wpforms/transfer?secret=YOUR_SECRET
Request Method POST
Request Format JSON
Enable

Same rules apply — type the key name on the left, select the field from the dropdown on the right.

Key Field ID
entryId Entry ID — select Entry ID from the "Other" section
transferService 145
contactName 13
contactEmail 16
contactPhone 17
departureDate 148
pickupAddress 149
pickupTime 150
dropoffAddress 162
returnDate 154
returnPickupAddress 155
returnPickupTime 159
returnDropoffAddress 163
vehicle 160
specialInstructions 132
formSubmittedDate 134
signatureUrl 136
signedBy 137

6. How it works

  • Vehicles are fuzzy-matched against active fleet cars; unmatched vehicles appear in the booking notes
  • General Booking: when a vehicle's pickup or drop-off is marked "same as previous vehicle", the address is inherited from the preceding slot
  • Wedding: for night transfers, pickup address is set from the reception address, drop-off from the night transfer field, duration defaults to 1 hour
  • Airport Transfer: a Round Trip submission creates two separate bookings — one on the departure date (Drop-off) and one on the return date (Pick-up) — with cross-reference notes linking them; "Airport Transfer" booking type is created automatically if it doesn't exist
  • Transfer: same Round Trip → two bookings behaviour; pickup and drop-off addresses on both legs; "Transfer" booking type is created automatically if it doesn't exist
  • Bookings are created with status Waiting Deposit (Hold bookings skip PDF generation)
  • Duplicate submissions (same WPForms entry ID) are silently ignored
  • If the webhook fails, WPForms email notifications act as a fallback — staff can manually create the booking from the notification email

Version

v1.41.0 — see CHANGELOG.md