There are two ways to book a rental for a customer through the API, and they suit different jobs. A headless storefront or mobile app adds the rental to a WooCommerce cart with the public Store API and lets WooCommerce run the checkout, payment and emails: the customer pays, and the reservation is created by the same code as a normal checkout. A back-office system (a point of sale, a CRM, a migration) creates the order directly with WooCommerce’s orders API and the rental is booked from the order’s line-item meta. Both are described below; the conventions are in the REST API overview.
Adding a rental to the cart (Store API) #
WooCommerce’s Store API lives at /wp-json/wc/store/v1/, needs no API key, and identifies the cart with a Cart-Token header instead of a cookie. Bookings & Tours extends its cart/add-item endpoint with the rental fields, so the request carries the same values the product page’s calendar posts, and goes through the same validation: the start date cannot be in the past or too close, neither date can fall on a closed day, and the requested quantity must be free for the whole period including turnover buffers.
| Field | Value |
|---|---|
id | The product id (or variation id) — a WooCommerce field. |
quantity | How many units — a WooCommerce field. |
sibooking_from | Start date, Y-m-d. Required for a rental. |
sibooking_to | End date, Y-m-d. Required for a rental (send the same day as the start for a one-day hire). |
sibooking_from_time | Start time, HH:mm. Only for products rented by date and time. |
sibooking_to_time | End time, HH:mm. Only for products rented by date and time. |
isbookingpurchase | 1 to buy a rentable product outright instead of renting it (for products that offer both). No dates are needed then. |
The hyphenated names the product form uses (sibooking-from, sibooking-to, …) are accepted as well. A fixed-length product still needs both dates: send the end date the plugin’s calendar would have chosen (start plus the fixed length).
Step by step #
1. Get a cart token. Any Store API cart request returns a Cart-Token response header; keep it and send it back on every following request. It is valid for 48 hours and identifies this customer’s cart.
curl -i https://your-store.com/wp-json/wc/store/v1/cart
# … Cart-Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…
2. Check availability first. Before offering the dates, ask the rental API whether enough units are free for them. This needs your API key, so make the call from your server (or your app’s backend), never from the browser. The answer uses the same buffers and closed-day rules as the cart, so what it accepts the cart will accept too.
curl -u "ck_your_key:cs_your_secret" \
"https://your-store.com/wp-json/wc-sibooking/v1/availability?product_id=123&start=2026-10-03&end=2026-10-05&quantity=1"
{ "product_id": 123, "max_quantity": 3, "booked": 1, "available": 2, "requested": 1, "ok": true }
Only continue when ok is true. To grey out unavailable days in your own date picker before the customer picks anything, load GET /wc-sibooking/v1/availability/calendar?product_id=123 once (also from the server) and use its fully_booked_days. See the availability endpoints.
3. Add the rental.
curl -X POST https://your-store.com/wp-json/wc/store/v1/cart/add-item \
-H "Content-Type: application/json" \
-H "Cart-Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…" \
-d '{
"id": 123,
"quantity": 1,
"sibooking_from": "2026-10-03",
"sibooking_to": "2026-10-05"
}'
The response (status 201) is the whole cart. The rental line shows the dates under item_data, and totals already reflects the rental price for those dates and quantity, calculated by the product’s pricing rules:
{
"items": [
{
"key": "a4df80da711d84c874fcb1d7dfb7260c",
"id": 123,
"name": "Canon EOS R6 body",
"quantity": 1,
"item_data": [
{ "key": "Start Date", "value": "October 3, 2026" },
{ "key": "End Date", "value": "October 5, 2026" }
],
"totals": { "line_total": "7500", "currency_minor_unit": 2 }
}
],
"items_count": 1,
"totals": { "total_items": "7500", "total_price": "7500", "currency_code": "USD", "currency_minor_unit": 2 }
}
Amounts in the Store API are strings in the currency’s minor unit (cents), as for every WooCommerce cart. When the rental cannot be added, the answer is a 400 with the same message the customer would see on the product page:
{ "code": "woocommerce_rest_add_to_cart_error", "message": "The start or end date is disabled", "data": { "status": 400 } }
{ "code": "woocommerce_rest_add_to_cart_error", "message": "Not enough inventory for the dates selected", "data": { "status": 400 } }
{ "code": "woocommerce_rest_add_to_cart_error", "message": "Please enter the booking dates", "data": { "status": 400 } }
A refusal here means the calendar changed between the availability check and the add: another customer took the last unit, or the dates crossed a closed day. Show the message and let the customer pick again.
4. Check out. The Store API checkout takes the addresses and the payment method; card gateways that support the block checkout accept their payment_data here as documented by WooCommerce.
curl -X POST https://your-store.com/wp-json/wc/store/v1/checkout \
-H "Content-Type: application/json" \
-H "Cart-Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…" \
-d '{
"billing_address": { "first_name": "Jane", "last_name": "Smith", "address_1": "1 High Street", "city": "Leeds", "postcode": "LS1 1AA", "country": "GB", "email": "[email protected]" },
"shipping_address": { "first_name": "Jane", "last_name": "Smith", "address_1": "1 High Street", "city": "Leeds", "postcode": "LS1 1AA", "country": "GB" },
"payment_method": "bacs"
}'
When the order is placed the plugin creates the reservation from the order (the same woocommerce_store_api_checkout_order_processed path the block checkout uses), sends the usual emails, and the booking is visible at GET /wc-sibooking/v1/bookings?order_id=….
The same flow in JavaScript #
const store = 'https://your-store.com/wp-json/wc/store/v1';
let cartToken = '';
async function storeApi(path, options = {}) {
const headers = { 'Content-Type': 'application/json', ...(cartToken ? { 'Cart-Token': cartToken } : {}) };
const res = await fetch(store + path, { ...options, headers });
cartToken = res.headers.get('Cart-Token') || cartToken; // keep the cart between calls
const body = await res.json();
if (!res.ok) throw new Error(body.message); // "The start or end date is disabled", …
return body;
}
await storeApi('/cart'); // 1. obtain the token
// 2. (on your server) GET /wc-sibooking/v1/availability?product_id=123&start=…&end=… and only go on when ok === true
const cart = await storeApi('/cart/add-item', { // 3. add the rental
method: 'POST',
body: JSON.stringify({ id: 123, quantity: 1, sibooking_from: '2026-10-03', sibooking_to: '2026-10-05' })
});
console.log(cart.totals.total_price); // "7500"
const order = await storeApi('/checkout', { // 4. place the order
method: 'POST',
body: JSON.stringify({ billing_address: {…}, shipping_address: {…}, payment_method: 'bacs' })
});
console.log(order.order_id, order.status);
From a page that is part of the WordPress site itself (a theme or a block), send the Nonce header WooCommerce prints as wcSettings.storeApiNonce (or the wc_store_api nonce) instead of a Cart-Token, and the customer’s normal session cart is used.
Creating an order with a rental (wc/v3) #
For orders taken outside the storefront, create them with WooCommerce’s POST /wp-json/wc/v3/orders (API key required) and put the rental dates on the line item as meta. Bookings & Tours books every line item that carries sibooking-from and sibooking-to, exactly as it does for a checkout, and later updates to the same line item’s dates through PUT /wc/v3/orders/{id} move the reservation rather than adding a second one.
curl -u "ck_your_key:cs_your_secret" -X POST \
-H "Content-Type: application/json" \
https://your-store.com/wp-json/wc/v3/orders \
-d '{
"payment_method": "bacs",
"set_paid": false,
"billing": { "first_name": "Jane", "last_name": "Smith", "email": "[email protected]" },
"line_items": [
{
"product_id": 123,
"quantity": 1,
"meta_data": [
{ "key": "sibooking-from", "value": "2026-10-03 00:00:00" },
{ "key": "sibooking-to", "value": "2026-10-05 23:59:00" }
]
}
]
}'
- The meta values are full datetimes. Use
00:00:00for the start and23:59:00for the end of a date-only rental; for a timed rental use the real times. - The reservation takes the order’s status into account: a cancelled, refunded or failed order releases its units, and putting it back to processing or completed reserves them again.
- Unlike the cart, this path does not refuse an overbooking (WooCommerce’s orders API has no validation hook for line items). Call
GET /wc-sibooking/v1/availabilityfirst and only create the order whenokis true. - The line’s price is what you send in
total/subtotal(or the product’s regular price if you send nothing). To charge the rental price for the dates, read it from the product’s pricing rules on your side, or add the item to a cart with the Store API and take the total from there.
Which one to use #
| Store API cart | wc/v3 orders | |
|---|---|---|
| Who calls it | The customer’s browser or app | Your server |
| Authentication | None (Cart-Token) | API key |
| Dates validated against the calendar | Yes, same rules as the product page | No, check /availability first |
| Rental price | Calculated by the plugin | Sent by you |
| Payment | Taken at checkout by the gateway | Recorded by you (set_paid, transaction id) |
| Emails | Normal order emails | Normal order emails |
