Contents
On this page

Plugixa Car Rental REST API - Plugixa Car Rental

The integration surface for Plugixa Car Rental: bookings you can search, price, make and move through their statuses, their payments, invoices and inspections, the fleet (categories, models and cars), locations, rate plans, extras and coupons you can list, create, edit and delete, the Pro pricing rules, tax rates, pricing calendar and rentals report, and the public routes the booking form and the customer booking page use. Enough to sync bookings into another system, feed a desk app or a BI tool, or build your own booking front end.

Everything the admin app, the booking form and the customer booking page do, they do over this API, under the namespace plugixa-car-rental/v1. Every rule is enforced at the route, not 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.

Base URL

https://your-site.example/wp-json/plugixa-car-rental/v1

On a site with plain permalinks, pass the route as a parameter instead:

https://your-site.example/?rest_route=/plugixa-car-rental/v1/bookings

Authentication

There are two kinds of route.

Staff routes are everything except the public routes below. The plugin adds no authentication of its own and has no API keys: it relies on whatever WordPress provides, then checks the capabilities of the user WordPress identified. From a script, use a WordPress Application Password (created under Users -> Profile -> Application Passwords) for an account that holds the capabilities below:

curl -s "https://your-site.example/wp-json/plugixa-car-rental/v1/bookings" \
  -u "admin:$WP_APP_PASSWORD"
Caller How it signs in
A script or another system An Application Password, or any other method WordPress accepts for REST requests
The admin app The logged-in cookie plus a REST nonce in X-WP-Nonce, the normal WordPress way
The booking form and the customer booking page Nothing: they call the public routes

Capabilities

Capability What it allows
plugixa_car_rental_view Read records: every list and single record, searches and quotes, the payment ledger, invoices, inspections, the pricing calendar and the report
plugixa_car_rental_create Create records and bookings, record a desk payment, issue an invoice
plugixa_car_rental_edit Change records, change a booking’s status, save and sign inspections
plugixa_car_rental_delete Move records to the trash, restore them, delete them for good, refund a payment
plugixa_car_rental_export Export lists to CSV (not part of this reference)
plugixa_car_rental_manage_settings Read and save the settings and payment credentials (not part of this reference)
plugixa_car_rental_manage Open the admin app. Never needs granting: anyone who holds one of the six above has it

Activation grants all of them to the Administrator role. A user with the WordPress manage_options capability is always treated as holding every one. They are ordinary WordPress capabilities, so any role editor can grant them to other roles. A dedicated integration user with only plugixa_car_rental_view, for example, can read everything and change nothing.

Every check passes through the plugixa_car_rental_user_can filter, so a site can narrow it per kind of record or per record. See Hooks.

Apps

A route belongs to an app in the App manager. Bookings, Fleet, Locations, Pricing (rate plans) and Payments are core apps and are always on. The others can be switched off, and an app that is off takes its routes with it: they answer 404 rest_no_route. Each endpoint page names the app it needs. The Pro routes exist only when Plugixa Car Rental Pro is active.

Responses

A successful staff response wraps its payload:

{
  "success": true,
  "data": { "id": 1, "name": "Paris Gare de Lyon" },
  "meta": { "total": 4, "pages": 1 }
}

meta is only present on lists. Send request bodies as JSON with Content-Type: application/json. Ids and counts are integers and money amounts are numbers. created_at, modified_at and deleted_at are UTC strings in the form 2026-11-12 09:30:00, and so are a booking’s pickup_at and return_at. Pickup and return times you send are the opposite: local time at the location, YYYY-MM-DD HH:MM, without an offset. See Create Booking.

Updates

PUT and PATCH work the same way on every record: only the fields you send are changed, and the others keep their stored value.

Edit conflicts

Every record carries modified_at. When an update sends back the modified_at it read, the plugin compares it with the stored one and answers 409 plugixa_car_rental_conflict if they differ: somebody else saved the record in between. The error’s data carries expected and current.

The check is opt-in: an update that sends no modified_at is not checked. Two saves inside the same second cannot be told apart. A script that reads, changes and writes back a record should send modified_at so it never overwrites a change made by staff in the meantime.

Lists and pagination

Every list endpoint accepts the same parameters, and puts the totals in meta, not in headers (X-WP-Total is not sent).

Parameter Type Default Description
page integer 1 Page to return, from 1
per_page integer 50 Rows per page, 1 to 200
search string Substring search over the columns each endpoint lists
orderby string id One of the sortable columns each endpoint lists. Anything else falls back to id
order string desc asc or desc
view string trash lists trashed records only

Filtering lists

Besides search, a list can be narrowed field by field with query parameters of the form <field>__<operator>=<value>:

GET /plugixa-car-rental/v1/bookings?status__in=confirmed,picked_up&pickup_at__between=2026-12-01,2026-12-31
Operator Meaning
eq, ne Equal, not equal
gt, gte, lt, lte Greater or less than, for dates
between Two values, comma-separated, both included
in Any of several values, comma-separated
contains Text contains the value
empty, not_empty The field has no value, or has one. The value sent is ignored

Which fields and operators a list accepts depends on the resource, and each list page names its fields. Every list can be filtered on created_at and modified_at. Dates are YYYY-MM-DD on the site’s calendar: between takes in the whole of both days. Asking for a field the list does not have, or an operator that does not work on it, is refused with a 400 rather than ignored, so a typo never quietly returns a wider list.

Trash

DELETE on a record moves it to the trash; it stops appearing in lists and single reads, and comes back with view=trash on its list. A vehicle model, a car or a location that upcoming bookings still use cannot be trashed, nor a model that still has cars, a location that is still a car’s home, or a category that still holds models: the answer is 409 plugixa_car_rental_in_use, with the reasons as sentences in data.blockers. Each Delete page says what stops it.

Two more routes exist for every resource that has a Delete endpoint:

Method Route What it does
POST /<resource>/{id}/restore Bring the record back from the trash. Answers {"restored": true} in data (a booking answers with the booking itself)
DELETE /<resource>/{id}/purge Delete it for good. Answers {"purged": true} in data (a booking answers {"id": ...})

Both need plugixa_car_rental_delete. <resource> is the path of the resource’s list, for example vehicle-units or rate-plans. An id that does not exist, or a restore of a record that is not in the trash, answers 404 plugixa_car_rental_not_found (a booking answers 409 plugixa_car_rental_restore_failed). Restoring a car, a location or a coupon whose plate, VIN or code another live record has taken since is refused with 409, and so is a rate plan whose days now overlap another rate.

Bookings are stricter: a booking can only be purged from the trash (409 plugixa_car_rental_not_trashed otherwise), and a booking that ever had a payment completed on it is never purged (409 plugixa_car_rental_kept): it stays in the trash as a financial record. Its price lines go with it.

Note. For every resource except bookings, purge does not require the record to be in the trash first, and it skips the checks that stop a trash: a location that is a car’s home, or a model with upcoming bookings, is deleted for good without complaint. Trash a record first and purge it from the trash.

Endpoints

Staff routes, for a signed-in user with the capabilities above:

Resource Endpoints
Bookings List, Create, Get, Change status, Delete, Search availability, Quote
Payments List, Record, Refund
Invoices Get, Issue, Download PDF PRO
Inspections PRO List, Update, Sign, Download signed PDF
Vehicle categories List, Create, Get, Update, Delete
Vehicle models List, Create, Get, Update, Delete
Vehicle units (cars) List, Create, Get, Update, Delete
Locations List, Create, Get, Update, Delete
Rate plans List, Create, Get, Update, Delete
Extras List, Create, Get, Update, Delete
Coupons List, Create, Get, Update, Delete
Pricing rules PRO List, Create, Get, Update, Delete, Pricing calendar
Tax rates PRO List, Create, Get, Update, Delete
Reports PRO Rentals

Public routes, for the booking form, the customer booking page or your own front end:

Resource Endpoints
Booking form Options, Search cars, Hold a car, Get held booking, Apply coupon, Check out, Release hold
Customer portal View booking, Cancel booking, Find booking

A booking front end calls them in this order: Options once, Search cars for the dates, Hold a car for the chosen model, which returns a token, then Apply coupon if the visitor has one and Check out with the token.

Public routes

The public routes run without a WordPress login and need no nonce. A public route cannot ask who is calling, so it checks three things, cheapest first.

  1. Honeypot. Hold a car, Check out and Find booking refuse a request whose hidden website field is filled in, with 400 plugixa_car_rental_rejected.
  2. Rate limit. Counted per visitor address and per route, see below.
  3. CAPTCHA. Nothing is bundled. A site adds one with the plugixa_car_rental_public_request_captcha filter, which receives the request’s captcha_token; a refusal answers 403 plugixa_car_rental_captcha_failed.

A held booking is opened by the token Hold a car returns, and a customer’s booking by the manage link in their emails. Both are long random values, and nothing else opens a booking from the public side. Public responses carry Cache-Control: no-store, and are not passed through the plugixa_car_rental_filter_output filter.

Rate limits

Route Requests per hour
GET /public/options 300
POST /public/search 120
POST /public/holds 15
POST /public/release 30
POST /public/booking 120
POST /public/coupon 20
POST /public/checkout 15
POST /public/manage 60
POST /public/manage/cancel 10
POST /public/manage/find 5

Over the limit the answer is 429 plugixa_car_rental_rate_limited, with no Retry-After header. The staff routes have no rate limit.

The counter is kept per address, and the address is read from REMOTE_ADDR only. On a site behind a proxy or a CDN every visitor shares the proxy’s address and therefore one counter: use the plugixa_car_rental_client_ip filter to read the header your proxy sets. See Hooks.

Routes not for you to call

/public/payment/return, where a payment provider sends the customer’s browser back, and /public/payment/webhook/{gateway}, where a provider reports a payment, are for the providers. With Pro, /public/manage/invoice and /public/manage/contract serve the customer’s PDFs from their manage link, and /calendar/...ics serves the calendar feeds set up under Calendar sync.

Errors

Errors use the standard WordPress shape:

{
  "code": "plugixa_car_rental_forbidden",
  "message": "You are not allowed to do that.",
  "data": { "status": 403 }
}

These can come back from any endpoint. Each endpoint page lists its own errors on top of them.

Status Code When
401 plugixa_car_rental_forbidden A staff route was called without a signed-in user: no credentials, or a cookie without its nonce.
401 incorrect_password WordPress refused the Application Password before the plugin saw the request.
403 plugixa_car_rental_forbidden The user is signed in but lacks the capability.
404 plugixa_car_rental_not_found No record with that id, or it is in the trash.
409 plugixa_car_rental_conflict The modified_at you sent is not the stored one. See Edit conflicts.
400 plugixa_car_rental_unknown_filter A list filter names a field the list does not have.
400 plugixa_car_rental_unknown_operator A list filter uses an operator that does not work on that field.
400 plugixa_car_rental_missing_value A list filter has fewer values than its operator needs.
400 plugixa_car_rental_invalid_date A list filter on a date field has a value that is not a date.
400 rest_invalid_param A list parameter failed validation, for example per_page above 200 or order other than asc or desc.
422 plugixa_car_rental_invalid_choice, plugixa_car_rental_not_a_number, plugixa_car_rental_number_too_large, plugixa_car_rental_negative_number, plugixa_car_rental_too_long A body field failed validation. data.field names the field; data.allowed lists the accepted values of a choice, and data.max the longest text allowed. Numbers are capped at 99999999999999.
429 plugixa_car_rental_rate_limited A public route’s rate limit was reached.
404 rest_no_route No such route or method, an app that is switched off, or a Pro route on a site without Pro.

plugixa_car_rental_too_long has two meanings: a text longer than its column (with data.max), and on a booking, a rental longer than the booking rules allow (with data.field set to return_at).

Filtering what comes back

Hook Changes
plugixa_car_rental_filter_output Every successful staff payload, with the kind of record, before it is sent. The place to hide fields from some users
plugixa_car_rental_user_can The verdict of every capability check
plugixa_car_rental_public_options What Booking Form Options returns
plugixa_car_rental_portal_view What View Booking returns
plugixa_car_rental_client_ip The address a public request is counted against
plugixa_car_rental_public_request_captcha Adds a CAPTCHA check to the public routes
plugixa_car_rental_public_request_refusal Refuses a public search or hold before any car is looked at

Register your own routes on the plugixa_car_rental_register_rest_routes action, which passes the namespace (and the plugin’s service container as a second argument):

add_action( 'plugixa_car_rental_register_rest_routes', function ( $namespace ) {
	register_rest_route(
		$namespace,
		'/fleet-status',
		array(
			'methods'             => 'GET',
			'callback'            => fn() => rest_ensure_response( array( 'open' => true ) ),
			'permission_callback' => fn() => current_user_can( 'plugixa_car_rental_view' ),
		)
	);
} );

See Hooks for the full set, including the actions that fire when a booking is created, changes status or is paid.

Troubleshooting

Symptom Usual cause
401 from a script The Application Password is wrong or missing, or the host strips the Authorization header before PHP sees it.
401 or 403 from the browser The REST nonce is missing or stale. Reload the admin.
403 with a valid login The user lacks the capability. Grant it with a role editor, or use an administrator account.
404 rest_no_route The app is switched off in the App manager, or the route is Pro and Pro is not active.
422 plugixa_car_rental_invalid_datetime on a booking A bare date, or a time with an offset. Send local time at the location, YYYY-MM-DD HH:MM.
422 plugixa_car_rental_not_priced No published rate plan covers that rental length for the model. Add one under Rates.
429 on a public route behind a proxy Every visitor shares the proxy’s address. Set plugixa_car_rental_client_ip.
409 on an update Somebody saved the record after you read it. Read it again and reapply your change.

See also

Quick Links

Share