Contents
REST API - Plugixa Chauffeur
Everything the admin app and the booking wizard do, they do over REST, under the
namespace plugixa-chauffeur/v1. Anything the screens can do is therefore
scriptable, and every rule is enforced at the route rather than in the page.
This is the API the plugin’s own screens use. It is not a separately versioned public API, and the plugin makes no promise that routes, parameters or response shapes stay the same between versions. Pin the plugin version you build against, and test after updating.
Authentication
There are two kinds of route.
Managed routes are for staff. The plugin adds no authentication of its own: it relies on whatever WordPress provides, then checks the permissions of the user WordPress identified.
| Caller | How |
|---|---|
| The admin app | The logged-in cookie plus a REST nonce in the X-WP-Nonce header, the normal WordPress way |
| A script or another system | Any method WordPress accepts for REST requests, such as an application password for an account that holds the permissions below |
Public routes, under /public, are open to visitors because the booking
wizard runs for people who are not logged in. They are described in
Public routes.
Permissions
| Called in the tables below | What the caller needs |
|---|---|
| Manage | The plugixa_chauffeur_manage capability |
| Manage + delete | plugixa_chauffeur_manage and plugixa_chauffeur_delete |
| Administrator | The WordPress manage_options capability |
| Public | Nothing |
Activation gives administrators five capabilities: plugixa_chauffeur_manage,
plugixa_chauffeur_edit, plugixa_chauffeur_delete,
plugixa_chauffeur_publish and plugixa_chauffeur_settings. Version 1.0.0
checks two of them, plugixa_chauffeur_manage and plugixa_chauffeur_delete.
The other three are granted but no route tests them.
Every DELETE route needs both capabilities. Deleting is a separate grant
from managing so that you can give day-to-day booking work to a role that cannot
destroy records. A caller with manage but without delete gets 403 on DELETE
and can still create and edit.
Both names can be changed with the plugixa_chauffeur_manage_capability and
plugixa_chauffeur_delete_capability filters. See
Hooks reference.
A caller who fails the check, logged in or not, gets status 403 with the code
rest_forbidden and one of these messages:
| Route kind | Message |
|---|---|
| Manage | “You do not have permission to perform this action.” |
| Manage + delete | “You do not have permission to delete this item.” |
| Administrator | “Administrator access required.” |
Request and response shape
Send request bodies as JSON with Content-Type: application/json. The write
routes read the JSON body only; form-encoded fields are ignored.
A successful response wraps its payload:
{
"success": true,
"message": "",
"data": { }
}
A refusal is a standard WordPress REST error with a readable message and an
HTTP status.
| Code | Status | When |
|---|---|---|
rest_forbidden |
403 | The permission check failed |
rest_error |
400, 404, 500 or 502 | Validation failed, the record does not exist, the write failed, or Stripe refused |
plugixa_chauffeur_unavailable |
422 | The pickup time is outside the availability rules |
rest_no_route |
404 | The route does not exist, which includes every Pro route on a free site |
List parameters
The list routes share these query parameters.
| Parameter | Meaning |
|---|---|
limit or per_page |
Rows per page, 20 by default. -1 returns everything. |
offset |
Rows to skip. Or pass page and let it be calculated. |
orderby or sort_by |
A column from the route’s own list; anything else falls back to its default |
order or sort_order |
ASC or DESC |
search |
Text to match |
filter |
An object holding any of the filters, for example filter[status]=pending |
A list response’s data holds items, total, limit and offset.
Routes
Paths are relative to /wp-json/plugixa-chauffeur/v1.
Settings and dashboard
| Method | Route | Needs | What it does |
|---|---|---|---|
| GET | /settings |
Administrator | Every setting, with defaults filled in for keys never saved |
| POST | /settings |
Administrator | Merge the keys in the body into the stored settings. Keys you leave out are kept. |
| GET | /settings/dashboard |
Manage | Counts, the five latest bookings, the next five pickups, and 30 days of totals by day, service, vehicle and status, with the previous 30 days for comparison |
The settings keys are listed in Settings.
Bookings
| Method | Route | Needs | What it does |
|---|---|---|---|
| GET | /bookings |
Manage | List bookings. search matches number, customer name and email; status filters. Sort by created_at, pickup_datetime, status, price_total or booking_number. The response adds status_counts. |
| POST | /bookings |
Manage | Create a booking by hand. See the note below. |
| GET | /bookings/calendar |
Manage | Bookings whose trip overlaps from to to (dates, default the current month), optionally one status or one vehicle_id. Returns events with start and end. |
| GET | /bookings/{id} |
Manage | One booking, with vehicle_name and driver_name |
| PUT | /bookings/{id} |
Manage | Update the fields sent |
| DELETE | /bookings/{id} |
Manage + delete | Delete the booking |
Writable booking fields: status, service_type, transfer_type,
pickup_address, dropoff_address, pickup_datetime, return_datetime,
customer_name, customer_email, customer_phone, notes, payment_method,
payment_status, currency, booking_form_id, vehicle_id, driver_id,
passengers, luggage, travel_minutes, pickup_lat, pickup_lng,
dropoff_lat, dropoff_lng, duration_hours, distance_km, price_base,
price_distance and price_time.
status is one of pending, processing, completed, cancelled, on_hold,
refunded or failed; anything else is saved as pending.
Three behaviours to know about:
price_totalcannot be set directly. On create it is the sum ofprice_base,price_distanceandprice_time. On update it is recalculated as that sum only when at least one of the three is in the request; otherwise the stored total, including any pricing-rule adjustment, is left alone.POST /bookingsdoes no pricing or availability work. It does not call the fare calculator, does not run pricing rules, does not check availability and does not send the booking emails. It stores what you send.- A status change fires the status action, which sends the customer’s status email. See Emails.
Booking forms
| Method | Route | Needs | What it does |
|---|---|---|---|
| GET | /booking-forms |
Manage | List forms. search matches the name. |
| POST | /booking-forms |
Manage | Create a form. name is required. |
| GET | /booking-forms/{id} |
Manage | One form |
| PUT | /booking-forms/{id} |
Manage | Update the fields sent |
| DELETE | /booking-forms/{id} |
Manage + delete | Delete the form |
Fields: name, enable_distance, enable_hourly, enable_flat,
enable_return, default_service_type, currency, min_lead_time (minutes),
min_passengers, status (published or draft), display_order and
settings.
Vehicles
| Method | Route | Needs | What it does |
|---|---|---|---|
| GET | /vehicles |
Manage | List vehicles. Filters: search, status, vehicle_type_id. |
| POST | /vehicles |
Manage | Create a vehicle. name is required. A new vehicle is a draft unless status says published. |
| GET | /vehicles/{id} |
Manage | One vehicle |
| PUT | /vehicles/{id} |
Manage | Update the fields sent |
| DELETE | /vehicles/{id} |
Manage + delete | Delete the vehicle |
| POST | /vehicles/reorder |
Manage | Set display order. Body: items, a list of { "id", "display_order" }. |
Fields: name, slug, description, vehicle_type_id, image_id, gallery
(attachment IDs), max_passengers, max_luggage, base_location_id,
base_price, price_per_distance, price_per_hour, min_price, status and
display_order.
Vehicle types
| Method | Route | Needs | What it does |
|---|---|---|---|
| GET | /vehicle-types |
Manage | List vehicle types. search filters. |
| POST | /vehicle-types |
Manage | Create a type. name is required. |
| GET | /vehicle-types/{id} |
Manage | One type |
| PUT | /vehicle-types/{id} |
Manage | Update the fields sent |
| DELETE | /vehicle-types/{id} |
Manage + delete | Delete the type. Its vehicles are kept and lose their type. |
| POST | /vehicle-types/reorder |
Manage | Set display order, as for vehicles |
Locations
| Method | Route | Needs | What it does |
|---|---|---|---|
| GET | /locations |
Manage | List locations. Filters: search, type. |
| POST | /locations |
Manage | Create a location. name is required. Other fields: address, latitude, longitude, place_id, type, display_order. |
| GET | /locations/{id} |
Manage | One location |
| PUT | /locations/{id} |
Manage | Update the fields sent |
| DELETE | /locations/{id} |
Manage + delete | Delete the location |
| POST | /locations/reorder |
Manage | Set display order, as for vehicles |
Availability
| Method | Route | Needs | What it does |
|---|---|---|---|
| GET | /availability |
Manage | The availability rules |
| PUT | /availability |
Manage | Replace the availability rules |
| POST | /availability |
Manage | The same as PUT |
Body: enabled, lead_time_minutes, horizon_days, business_hours (keys
1 for Monday to 7 for Sunday, each with open, start and end as
HH:MM) and blackout_dates (a list of start, end and label, dates as
YYYY-MM-DD). The body replaces the stored rules as a whole, so send all of
it. See Availability.
Drivers PRO
| Method | Route | Needs | What it does |
|---|---|---|---|
| GET | /drivers |
Manage | List drivers with a booking_count. search matches name, email and phone; status filters. |
| POST | /drivers |
Manage | Create a driver. name is required. |
| GET | /drivers/{id} |
Manage | One driver |
| PUT | /drivers/{id} |
Manage | Update the fields sent |
| DELETE | /drivers/{id} |
Manage + delete | Delete the driver and clear them from every booking |
Fields: name, slug, email, phone, photo_id, bio, status (active
or inactive) and display_order.
Pricing rules PRO
| Method | Route | Needs | What it does |
|---|---|---|---|
| GET | /pricing-rules |
Manage | List rules in running order. search matches the name. |
| POST | /pricing-rules |
Manage | Create a rule. name is required. |
| GET | /pricing-rules/{id} |
Manage | One rule |
| PUT | /pricing-rules/{id} |
Manage | Update the fields sent |
| DELETE | /pricing-rules/{id} |
Manage + delete | Delete the rule |
Fields: name, status, priority, adjustment_type (set_value,
increase_value, decrease_value, increase_percent or decrease_percent),
adjustment_value, stop_processing, display_order and conditions.
conditions is an object with any of service_types, vehicle_ids,
days_of_week (0 for Sunday to 6 for Saturday), date_from, date_to,
min_distance, max_distance, min_passengers and max_passengers. Sending
conditions replaces the whole object. vehicle_ids is honoured by the engine
but has no field in the admin form. See
Pricing rules.
Routes PRO
| Method | Route | Needs | What it does |
|---|---|---|---|
| GET | /routes |
Manage | List flat-rate routes. search matches the name and both labels. |
| POST | /routes |
Manage | Create a route. name is required. |
| GET | /routes/{id} |
Manage | One route |
| PUT | /routes/{id} |
Manage | Update the fields sent |
| DELETE | /routes/{id} |
Manage + delete | Delete the route |
Fields: name, pickup_label, dropoff_label, price, status (active or
inactive) and display_order.
Reports PRO
| Method | Route | Needs | What it does |
|---|---|---|---|
| GET | /reports/summary |
Manage | Totals, breakdowns, a daily series and up to 1,000 booking rows for bookings created between from and to |
from and to are YYYY-MM-DD. Without them the range is the last 30 days.
Public routes
These four routes take no capability and no login. Each is limited in what it can read or write.
| Method | Route | What it does |
|---|---|---|
| GET | /public/form/{id} |
The configuration of one published booking form |
| POST | /public/quote |
Prices for a trip, one per suitable vehicle |
| POST | /public/book |
Create a booking. Needs the booking nonce. |
| POST | /public/stripe-webhook |
Receive payment confirmations from Stripe. Needs a valid signature. |
The read routes only ever return published forms and published vehicles, and only the columns a visitor is meant to see. A draft form answers 404, “Booking form not found.”
GET /public/form/{id}
Returns id, name, currency, service_types, default_service_type,
enable_return, min_passengers, min_lead_time, distance_unit,
payment_methods and availability. With Pro and flat rate enabled on the
form, it also returns routes.
POST /public/quote
| Parameter | Meaning |
|---|---|
form_id |
The booking form. Required. |
service_type |
distance, hourly, or flat with Pro |
transfer_type |
one_way or return |
distance_km |
The trip distance, for distance bookings |
duration_hours |
The hours booked, for hourly bookings |
passengers |
Vehicles with fewer seats are left out |
pickup_datetime |
YYYY-MM-DD HH:MM, or with a T between date and time, in the site’s time zone |
route_id |
The chosen route, for flat-rate bookings |
Returns currency and vehicles. Each vehicle has vehicle_id, name,
description, image_url, vehicle_type_name, max_passengers,
max_luggage, price_base, price_distance, price_time and price_total.
The pickup time is checked against the availability rules, so a quote for a closed day is refused with status 422. Nothing is written.
POST /public/book
This is the one public route that writes, and it is gated on a nonce.
The nonce. When the booking form’s shortcode is rendered, the page receives
a WordPress nonce for the action plugixa_chauffeur_frontend. The wizard sends
it back as nonce in the JSON body; the X-Plugixa-Chauffeur-Nonce header is
accepted instead. A request without a valid nonce is refused with status 403,
“Security check failed. Please refresh and try again.” A WordPress nonce
belongs to the user it was made for and expires, within a day at most, so a
page left open or served from a long-lived cache can hold a stale one. See
Troubleshooting.
The body takes everything /public/quote takes, plus:
| Parameter | Meaning |
|---|---|
nonce |
The booking nonce. Required. |
vehicle_id |
The chosen vehicle. Must be published and have enough seats. |
customer_name, customer_email |
Required. The email must be valid. |
customer_phone, notes |
Optional |
pickup_address, dropoff_address |
The addresses as text |
luggage |
Number of bags |
payment_method |
stripe, cash, wire or pickup. A method that is not enabled is replaced by the first enabled one. |
return_url |
Where Stripe sends the customer back to. Must be on this site, or the home page is used. |
What the server does, in order: checks the nonce, loads the published form,
checks the pickup time against the availability rules, checks it against the
form’s own minimum lead time, validates the name and email, loads the published
vehicle, and recalculates the fare itself. Any price in the request is
ignored. The booking is created with status pending and payment status
unpaid.
The response holds booking_id, booking_number, status, price_total,
currency, vehicle_name, payment_method, payment_label, payment_type
and payment_instructions. For a Stripe booking it also holds checkout_url,
the Stripe Checkout page to send the customer to.
POST /public/stripe-webhook
Stripe calls this route server to server, so it cannot carry a WordPress login or nonce. It is authenticated by Stripe’s signature instead.
The signature check. The plugin reads the Stripe-Signature header and the
raw request body, and verifies them against the Webhook signing secret from
Settings before reading anything
from the payload:
- The header must contain a timestamp
tand at least onev1signature. - The timestamp must be within 300 seconds of the server’s clock.
- An HMAC-SHA256 of
timestamp.body, keyed with the signing secret, must equal one of thev1signatures, compared in constant time.
If any step fails the response is status 400 with {"error": "invalid_signature"} and nothing is changed. An empty signing secret fails
the check, so a site with no secret configured rejects every call.
A verified checkout.session.completed event whose session is paid marks the
booking named in the session’s metadata as paid, and moves it from pending
to processing. A booking that is already paid is left alone, so a repeated
delivery is harmless. Every other verified event is acknowledged with
{"received": true} and ignored.
The endpoint to register in your Stripe dashboard is:
https://example.com/wp-json/plugixa-chauffeur/v1/public/stripe-webhook
See Payments.
A worked example
Quote a 25 km one-way trip for three passengers on form 1:
curl -X POST https://example.com/wp-json/plugixa-chauffeur/v1/public/quote \
-H "Content-Type: application/json" \
-d '{"form_id":1,"service_type":"distance","transfer_type":"one_way","distance_km":25,"passengers":3,"pickup_datetime":"2026-10-10 20:00"}'
List pending bookings as a member of staff, using an application password:
curl -u "dispatcher:xxxx xxxx xxxx xxxx xxxx xxxx" \
"https://example.com/wp-json/plugixa-chauffeur/v1/bookings?status=pending&limit=50"
Mark booking 42 as completed:
curl -X PUT -u "dispatcher:xxxx xxxx xxxx xxxx xxxx xxxx" \
-H "Content-Type: application/json" \
-d '{"status":"completed"}' \
https://example.com/wp-json/plugixa-chauffeur/v1/bookings/42
Adding your own routes
The plugixa_chauffeur_register_rest_routes action fires on rest_api_init
with the namespace, after the plugin’s own routes are registered. See
Hooks reference.