View Categories

REST API: balances and late fees

21 min read

The REST API for booking-deposit balances and late fees: list what customers still owe, record a payment taken at the counter, send the payment link again, waive or charge a balance, and review, edit, bill, refund or waive late fees. The actions are the same ones staff use on Rentals > Balances, Rentals > Late fees and the order screen, so an outside system (an accounting tool, a point-of-sale till, a collections dashboard) can do the same. How deposits and late fees work for staff is in Booking deposit and Late fees. The setup and the conventions shared by every endpoint (keys, errors, pagination) are in REST API overview and authentication.

  • A balance is the money still owed on a booking order after the customer paid a booking deposit at checkout. Once the deposit is paid, the plugin creates a separate WooCommerce order for the rest (the balance order: Pending payment, its parent is the booking order) and tracks it with a due date until it is paid, waived or cancelled.
  • A late fee is the charge for rental units that come back after their due time and the grace period. Each booking order has one open late fee at a time, numbered LF-<order number>-<n>, which collects every late check-in. While late units are still out it keeps growing (accruing); once everything is back it waits for staff (to_review) before anything is billed.

Base URL and sign-in #

NamespaceWhat lives thereNeeds
/wp-json/wc-sibooking/v1/balances (list, read, mark paid, payment link, waive, charge) and late-fees (list, read, edit, accept, counter payment, payment link, waive, refund, recalculate, retry)Rentals & Bookings Regular. Balances appear once “Let customers pay a booking deposit” is on (Rentals > Settings > Booking Deposit), late fees once “Charge late fees” is on (Rentals > Settings > Late fees). The routes answer either way
  • wc-sibooking/v1 takes a WooCommerce REST API key (WooCommerce > Settings > Advanced > REST API) sent as HTTP Basic, like the other rental endpoints. A read key can call the GET routes; the routes that change something need a read/write key. The key’s user decides what the call may do (next section).
  • A WordPress Application Password (Users > Profile > Application Passwords) sent as HTTP Basic works too, and inside wp-admin the logged-in cookie with an X-WP-Nonce header.
  • The balances routes are in Rentals & Bookings Regular 1.0.76 and later, the late-fee routes in 1.0.79 and later.
  • Send bodies as JSON (Content-Type: application/json).
  • Money comes twice: as a decimal number in the store’s currency (total: 150) and in minor units (total_minor: 15000, cents for USD). Amounts you send are decimals, as a string or a number ("12.50").
  • Times without a suffix (due, returned) are store time, Y-m-d H:i:s. Fields ending in _gmt are UTC.
  • Lists take page and per_page (default 20, at most 200) and answer the X-WP-Total and X-WP-TotalPages headers.
  • Errors use the WordPress shape {"code", "message", "data": {"status"}}, with codes starting sibooking_rest_. An action the record’s state does not allow answers 409.
  • These calls can move money: POST /balances/{id}/charge and POST /late-fees/{id}/retry charge a saved card, POST /late-fees/{id}/accept may keep part of a security deposit or charge a saved card, and POST /late-fees/{id}/refund can refund through the payment gateway. The payment-link actions email the customer.
STORE="https://example.com/wp-json"
curl -u "ck_your_key:cs_your_secret" "$STORE/wc-sibooking/v1/balances?status=due,overdue"

Who may do what #

AbilityWho has itOpens
manage_woocommerceShop managers and administratorsEvery balances endpoint
edit_shop_ordersShop managers and administrators (WooCommerce gives it to both), and any role or user given itEvery late-fees endpoint, like the Rentals > Late fees screen. A user with this ability alone can use the late-fee endpoints but not the rest of the rental API

A user without the ability gets 401 (not signed in) or 403, code sibooking_rest_forbidden.

Balances #

Statuses #

StatusMeaning
scheduledThe deposit is paid; the balance is due later
dueThe due date has come; waiting for the payment
chargingAn automatic charge is running
failedAn automatic charge was declined. It is tried again a day later, then 3 days after that (next_attempt_gmt)
needs_actionThe bank asks the customer to confirm the payment
overdueStill unpaid a day after the due date (two days for needs_action), or after the last retry
paidPaid in full
waivedStaff waived it
cancelledThe booking order, or the balance order itself, was cancelled or refunded
releasedThe balance was not paid, so the booking order was cancelled (“When the balance is not paid: Cancel the booking after a number of days” in Rentals > Settings > Booking Deposit). The booking deposit is kept

The first six are open: money is still owed and the actions below work. The last four are closed.

The balance object #

FieldNotes
idThe balance id
order_id, order_numberThe booking order
balance_order_id, balance_order_numberThe balance order the customer pays
status, status_textOne of the statuses above, and the words staff see (“Deposit paid · balance due Tue 1 Dec”)
currencyThe order’s currency
amount, tax, totalBefore tax, the tax, and what the customer pays; each also as amount_minor, tax_minor, total_minor
due, due_gmtWhen it is due, store time and UTC
collectHow it is collected: link (the customer pays from a payment link), auto (charged to the saved card on the due date) or pickup (paid at pick-up)
attempts, next_attempt_gmt, last_errorAutomatic charge attempts so far, the next retry, and the last decline or problem
paid_via, paid_gmtHow and when it was paid: online, auto, counter_cash, counter_card, counter_bank or counter_other; null before
payment_urlThe balance order’s payment page while the balance is open; null otherwise
customerid (0 for a guest), name and email from the booking order
{
  "id": 12,
  "order_id": 1042,
  "order_number": "1042",
  "balance_order_id": 1043,
  "balance_order_number": "1043",
  "status": "scheduled",
  "status_text": "Deposit paid · balance due Tue 1 Dec",
  "currency": "USD",
  "amount": 150,
  "tax": 0,
  "total": 150,
  "amount_minor": 15000,
  "tax_minor": 0,
  "total_minor": 15000,
  "due": "2026-12-01 10:00:00",
  "due_gmt": "2026-12-01 15:00:00",
  "collect": "link",
  "attempts": 0,
  "next_attempt_gmt": null,
  "last_error": "",
  "paid_via": null,
  "paid_gmt": null,
  "payment_url": "https://example.com/checkout/order-pay/1043/?pay_for_order=true&key=wc_order_AbC123",
  "customer": {"id": 0, "name": "Sarah Miller", "email": "[email protected]"}
}

GET /wc-sibooking/v1/balances #

The list, the same as Rentals > Balances. Sorted by due date, earliest first.

ParameterNotes
statusComma separated: scheduled, due, charging, failed, needs_action, overdue, paid, waived, cancelled, released. Every status when left out
due_from, due_toStore date (Y-m-d), a date and time, or ISO 8601. A bare due_to date runs through the end of that day
order_idThe booking order’s id, or its balance order’s id
page, per_pageDefault 1 and 20; per_page at most 200

Answers an array of balance objects.

ErrorWhen
400 sibooking_rest_invalid_statusA status not in the list
400 sibooking_rest_invalid_datedue_from or due_to is not a date
400 rest_invalid_paramper_page above 200

GET /wc-sibooking/v1/balances/{id} #

One balance. 404 sibooking_rest_not_found when there is none.

POST /wc-sibooking/v1/balances/{id}/mark-paid #

Record payment: the whole balance was paid at the counter. There is no partial counter payment.

ParameterNotes
methodcash, card (card terminal), bank (bank transfer) or other (default)
referenceOptional: a receipt or terminal reference. It becomes the balance order’s transaction id and goes in its order note

The balance order gets the payment method title “Paid at the counter: Cash” (and so on) and is marked paid; the balance answers status paid and paid_via counter_cash (and so on). Refused while an automatic charge runs (409 sibooking_rest_charging).

POST /wc-sibooking/v1/balances/{id}/invoice #

Emails the customer the “Your balance is due” email: the rental and its dates, the amount, the due date and a Pay button that opens payment_url. It goes out even when the automatic balance reminder is switched off. No body. Answers the balance, unchanged.

POST /wc-sibooking/v1/balances/{id}/waive #

Waives the balance: it becomes waived, the unpaid balance order is cancelled, and the booking order keeps what was paid.

ParameterNotes
reasonOptional; goes in the booking order’s note

POST /wc-sibooking/v1/balances/{id}/charge #

Charge now: charges the payment method saved on the booking. It must be one of the payment methods ticked under “Automatic charges with” (Rentals > Settings > Booking Deposit). Works on a balance that is scheduled, due or failed. No body.

  • Paid: answers the balance with status paid and paid_via auto.
  • The payment method cannot be charged automatically, or the saved card has expired: the balance switches to collect link, the customer is emailed the payment link, and the call answers 409 sibooking_rest_charge_manual.
  • The bank asks the customer to confirm: the balance is needs_action, the customer is emailed, and the call answers 409 sibooking_rest_charge_needs_action.
  • Declined: the balance is failed (retried a day later and 3 days after that, then overdue) and the call answers 409 sibooking_rest_charge_failed with the gateway’s message. When the gateway gave no clear answer the balance is failed without a retry: check the payment in the gateway before you charge again.

Errors of the actions #

ErrorWhen
404 sibooking_rest_not_foundNo such balance, or its booking order is gone
409 sibooking_rest_no_balanceThe balance is closed (paid, waived, cancelled or released)
409 sibooking_rest_no_balance_orderThe balance order is gone
409 sibooking_rest_chargingmark-paid while an automatic charge runs
409 sibooking_rest_already_paidmark-paid when the balance order is already paid
409 sibooking_rest_no_email, 409 sibooking_rest_not_sentinvoice: the order has no billing email, or the email could not be sent
409 sibooking_rest_charge_busycharge while another charge runs
409 sibooking_rest_charge_skippedcharge on a balance that is not scheduled, due or failed, or whose balance order turned out to be paid already
409 sibooking_rest_charge_manual, ..._charge_needs_action, ..._charge_failedcharge: see above
400 rest_invalid_parammethod not in the list
curl -u "ck_your_key:cs_your_secret" -X POST \
  -H "Content-Type: application/json" \
  -d '{"method":"card","reference":"Terminal 4471"}' \
  "$STORE/wc-sibooking/v1/balances/12/mark-paid"

The payment object on bookings and orders #

Bookings (see Bookings, availability and serials) and Regular’s orders list (see Pricing and orders) carry payment: null for an order without a booking deposit, {"type": "balance", "balance_of": 1042} for a balance order, and for a booking order:

FieldNotes
typedeposit
status, status_textThe open balance’s status (else the newest balance’s); deposit_unpaid while the booking order is not paid yet
deposit, deposit_minorThe booking deposit, paid at checkout
balance_due, balance_due_minorWhat is still owed: the open balances, with tax
due, collectAs on the balance
balance_id, balance_order_idThe balance and its balance order, for the calls above
payment_urlWhile a balance is open

Late fees #

Statuses #

StatusMeaningWhat you can do
accruingLate units are still out; the fee grows until they are back. Nothing is billedEdit the notes, recalculate, waive
to_reviewEverything is back; staff decideEdit, recalculate, accept, counter-payment, waive
chargingA card charge is runningNothing until it ends
pay_link_sentA late-fee order exists and the customer pays it from a linksend-link, counter-payment, waive
failedA card charge was declinedretry, send-link, counter-payment, waive
needs_actionThe bank asks the customer to confirm the card paymentsend-link, counter-payment, waive
paidPaidrefund
part_refundedPart of it was refundedrefund (what is left)
refunded, waivedFinishedNothing
cancelledNothing was late after all (a corrected return time), or the booking order was cancelled or refundedNothing

The late-fee object #

FieldNotes
id, numberThe id and LF-1042-1
order_idThe booking order
status, status_textOne of the statuses above, and the words staff see
currencyThe order’s currency
amount, tax, totalBefore tax, the tax, and the total; each also as amount_minor, tax_minor, total_minor
dueThe earliest due time of its lines, store time
returnedThe last late check-in, store time; null while nothing is back
charge_order_idThe late-fee order (a WooCommerce order, parent = the booking order) once it is billed; null before, and for a fee kept from the security deposit
routeHow it is collected: deposit, card, link or counter; null before
paid_via, paid_gmtHow and when it was paid: online (from the pay link), card, deposit, counter_cash, counter_card, counter_bank or counter_other; null before
payment_urlThe late-fee order’s payment page while the fee is unpaid (pay_link_sent, failed, needs_action, charging); null otherwise
so_farWhile accruing: the charges so far, before tax, in minor units. null otherwise
linesThe charges (below)
calculated_minorWhat the late-fee rules came to, before any staff edit
adjustedtrue once staff changed an amount or added a line
note_customerThe note to the customer; it goes on the late-fee order
staff_reasonThe staff note on an edit
waive_reasonWhy it was waived
location_idWhere the last late units were checked in (Multi Location Inventory); null without one

Each entry in lines:

FieldNotes
keyThe line’s key, used by amounts in an edit: b789-r321 (a check-in), b789-out (units still out), flat (the fixed late fee), x1, x2 (staff lines)
kindreturn (a late check-in), running (units still out), flat (the fixed “Late return fee”) or extra (a line staff added)
nameThe product, or the line’s own name. A product name comes as WordPress stores it, so an & arrives as &#038;
booking_id, quantityThe booking and how many units the line charges for
due, returnedThe due time and the check-in time (Y-m-d H:i). For a running line, returned is the time it was last measured up to
late_minutes, units, unitHow late, and what it was charged by: units of hour, day or week
amount, amount_minorThe line’s amount, as entered (before tax)
calculated_minorWhat the rules came to for this line
editedtrue when staff changed the amount
price_missingtrue when the rental price for the late time could not be worked out. Such a fee cannot be accepted until the line’s amount is entered with an edit
{
  "id": 456,
  "number": "LF-1042-1",
  "order_id": 1042,
  "status": "to_review",
  "status_text": "To review",
  "currency": "USD",
  "amount": 80,
  "tax": 0,
  "total": 80,
  "amount_minor": 8000,
  "tax_minor": 0,
  "total_minor": 8000,
  "due": "2026-11-03 23:59:00",
  "returned": "2026-11-05 10:15:00",
  "charge_order_id": null,
  "route": null,
  "paid_via": null,
  "paid_gmt": null,
  "payment_url": null,
  "so_far": null,
  "lines": [{
    "key": "b789-r321", "kind": "return", "name": "Party tent",
    "booking_id": 789, "quantity": 1,
    "due": "2026-11-03 23:59", "returned": "2026-11-05 10:15",
    "late_minutes": 2056, "units": 2, "unit": "day",
    "amount": 80, "amount_minor": 8000, "calculated_minor": 8000,
    "edited": false, "price_missing": false
  }],
  "calculated_minor": 8000,
  "adjusted": false,
  "note_customer": "",
  "staff_reason": "",
  "waive_reason": "",
  "location_id": null
}

GET /wc-sibooking/v1/late-fees #

The list, the same as Rentals > Late fees. Newest first.

ParameterNotes
statusComma separated: accruing, to_review, charging, pay_link_sent, failed, needs_action, paid, waived, cancelled, refunded, part_refunded; or all. Every status when left out
order_idOne booking order
customerA user id or a billing email; matches that customer’s newest 1,000 orders. With order_id, both must match
searchA late-fee number or part of one (LF-1042), or an order id (the booking order or its late-fee order)
created_after, created_beforeWhen the late fee was created: a store date (Y-m-d), a date and time, or ISO 8601. A bare created_before date runs through the end of that day
page, per_pageDefault 1 and 20; per_page at most 200

Answers an array of late-fee objects.

ErrorWhen
400 sibooking_rest_invalid_statusA status not in the list
400 sibooking_rest_invalid_customercustomer is neither a number nor an email address
400 sibooking_rest_invalid_datecreated_after or created_before is not a date
curl -u "ck_your_key:cs_your_secret" \
  "$STORE/wc-sibooking/v1/late-fees?status=to_review&[email protected]"

GET /wc-sibooking/v1/late-fees/{id} #

One late fee. 404 sibooking_rest_not_found when there is none.

PATCH /wc-sibooking/v1/late-fees/{id} #

Edits a late fee (PUT works too). Amounts and extra lines can change while the fee is to_review; the two notes also while it is accruing. Send any of:

FieldNotes
amountsAn object of line key to the new amount: {"b789-r321": "60.00"}. Amounts are 0 or more; an empty value leaves the line as it is. A changed line is marked edited and keeps its amount until recalculate. Alias: lines
extrasThe staff lines, as a list of {"name", "amount"}. It replaces every staff line there is; [] removes them. Alias: extra, with title for the name
note_customerThe note to the customer
staff_reasonThe staff note, added to the order note of the edit. Alias: reason_staff

Answers the late fee with the new totals. An edit that changes something adds an order note listing the changes.

ErrorWhen
400 sibooking_rest_nothing_to_changeNone of the fields was sent
400 sibooking_rest_invalid_paramA line key the fee does not have
400 rest_invalid_paramamounts is not an object, or extras is not a list
400 sibooking_rest_bad_amountAn amount that is not a number, or below 0
400 sibooking_rest_bad_extraA staff line without a name or an amount
409 sibooking_rest_late_fee_stateAmounts or extras on a fee that is not to_review, or notes on a fee that is billed or closed
curl -u "ck_your_key:cs_your_secret" -X PATCH \
  -H "Content-Type: application/json" \
  -d '{"amounts":{"b789-r321":"60.00"},"extras":[{"name":"Cleaning","amount":"15.00"}],"staff_reason":"First late return: one day off"}' \
  "$STORE/wc-sibooking/v1/late-fees/456"

POST /wc-sibooking/v1/late-fees/{id}/accept #

Bills a fee that is to_review. Every line must have a price (409 sibooking_rest_price_missing otherwise) and the total must be above 0 (409 sibooking_rest_nothing_to_bill: waive it instead).

ParameterNotes
routedeposit, card or link. Left out (or auto): the first that works

The routes, in this order, keeping the ones ticked under “How to collect” (Rentals > Settings > Late fees) that can work for this fee:

  • deposit: Refundable Security Deposits holds an untaxed deposit on the booking order and what is left of it covers the whole fee. The fee is kept from the deposit and is paid at once (paid_via deposit, no late-fee order, no tax).
  • card: the booking was paid with a payment method that can be charged without the customer, the customer has an account, agreed to late-fee charges at checkout, and has a saved card. A late-fee order is created and charged now; the fee answers paid, failed, needs_action, or pay_link_sent when the card can no longer be charged (the customer is emailed the pay link).
  • link: a late-fee order is created (Pending payment, its parent is the booking order, one fee line per charge, note_customer as its customer note), the fee is pay_link_sent, and the customer gets the “Late fee: please pay” email with the lines and the pay link (payment_url). The “Late fee: still unpaid” reminders follow 3 and 7 days later; they stop once the fee is paid or waived. It is also the fallback when no ticked route can work, even when link is not ticked.

All three are ticked until the setting is saved. A route that cannot start (the deposit was refused, the card could not be prepared) hands over to the next one, and finally to the link. A declined card still answers 200: read status. A route that is not ticked or cannot work for this fee answers 400 sibooking_rest_route_unavailable.

curl -u "ck_your_key:cs_your_secret" -X POST \
  -H "Content-Type: application/json" \
  -d '{"route":"link"}' \
  "$STORE/wc-sibooking/v1/late-fees/456/accept"

POST /wc-sibooking/v1/late-fees/{id}/counter-payment #

Records the whole fee as paid at the counter. Works on to_review (the late-fee order is created first, route counter), pay_link_sent, failed and needs_action. Alias: /mark-paid.

ParameterNotes
methodcash (default), card (card terminal), bank (bank transfer) or other
referenceOptional receipt or terminal reference

The late-fee order is marked paid and Completed, with the payment method title “Paid at the counter: Cash” (“Card terminal”, and so on) and reference as its transaction id; no gateway is involved. The fee answers paid with paid_via counter_cash (and so on); a fee billed by link keeps route link. The customer gets the “Late fee: receipt” email. Refused while a card charge runs (409 sibooking_rest_charging).

POST /wc-sibooking/v1/late-fees/{id}/send-link #

Emails the customer the pay link again (the “Late fee: please pay” email) and adds an order note. Works on pay_link_sent, failed and needs_action. No body. Answers the fee, unchanged; the reminders keep their dates. Alias: /invoice.

POST /wc-sibooking/v1/late-fees/{id}/waive #

Waives the fee. Works on accruing, to_review, pay_link_sent, failed and needs_action; an unpaid late-fee order is cancelled. The customer is not emailed. The bookings on a waived fee are not charged again, neither for the time still out nor for their check-in; a later late check-in of another booking on the same order opens a new fee (LF-1042-2).

ParameterNotes
reasonRequired, not blank: saved as waive_reason and in the order note

POST /wc-sibooking/v1/late-fees/{id}/refund #

Refunds a paid or part_refunded fee, in part or in full.

ParameterNotes
amountDecimal ("12.50"). All that is left when left out
reasonOptional; goes in the refund’s reason

A fee paid from the link or by card is refunded on its late-fee order: a WooCommerce refund that goes through the payment gateway when the gateway can refund. A fee paid at the counter is only recorded as refunded: give the money back yourself. A fee kept from the security deposit goes back to the deposit (Refundable Security Deposits must be active, else 409 sibooking_rest_no_deposits). The fee answers part_refunded or refunded; it does not show how much was refunded, so read the refunds on its late-fee order (charge_order_id). WooCommerce emails the customer about the refund as usual, and a full refund leaves the late-fee order Refunded. 400 sibooking_rest_bad_amount when the amount is not above 0 or more than is left; a refund WooCommerce or the gateway refuses answers 409 with its message. A fee that is already refunded answers 409 sibooking_rest_late_fee_state.

POST /wc-sibooking/v1/late-fees/{id}/recalculate #

Works the amounts out again from the late-fee rules, and re-measures units still out. Staff edits and staff lines are dropped; the two notes stay. Works on accruing and to_review. No body.

POST /wc-sibooking/v1/late-fees/{id}/retry #

Charges the saved card again now, for a fee that is failed after a card charge (409 sibooking_rest_not_card for another route). No body. Answers the fee; read status for the outcome.

Errors of the actions #

ErrorWhen
404 sibooking_rest_not_foundNo such late fee
409 sibooking_rest_late_fee_stateThe action does not fit the fee’s status (the message says why: still growing, already paid, waived, cancelled, already billed)
409 sibooking_rest_busyAnother request is billing or charging the fee
409 sibooking_rest_price_missing, 409 sibooking_rest_nothing_to_billaccept or counter-payment on a fee with an unpriced line, or a total of 0
409 sibooking_rest_chargingcounter-payment while a card charge runs
409 sibooking_rest_no_charge_order, 409 sibooking_rest_no_orderThe late-fee order or the booking order is gone
409 sibooking_rest_no_emailsend-link: the booking order has no billing email
409 sibooking_rest_not_cardretry on a fee that is not charged to a card
409 sibooking_rest_no_depositsrefund of a deposit-paid fee without Refundable Security Deposits
400 sibooking_rest_route_unavailableaccept with a route that is not ticked or cannot work for this fee
400 sibooking_rest_reason_requiredwaive with a blank reason (400 rest_missing_callback_param without one)
400 sibooking_rest_bad_amountrefund with an amount that is not above 0, or more than is left
400 rest_invalid_paramroute or method not in its list
curl -u "ck_your_key:cs_your_secret" -X POST \
  -H "Content-Type: application/json" \
  -d '{"reason":"Our delivery van broke down"}' \
  "$STORE/wc-sibooking/v1/late-fees/456/waive"

Late fees on a return #

A return that creates or changes a late fee (POST /bookings/{id}/return in Bookings, availability and serials, POST /return and POST /return/scan in Sending and returning rentals) adds late_fees to its answer: each fee in the short form, which is the late-fee object without lines, calculated_minor, adjusted, the notes and location_id. Use its id with the calls above.

Hooks #

To react inside WordPress instead of polling, use the actions sibooking_balance_order_created, sibooking_balance_paid and sibooking_balance_waived, and sibooking_late_fee_created, sibooking_late_fee_updated, sibooking_late_fee_cancelled, sibooking_late_fee_accepted, sibooking_late_fee_paid, sibooking_late_fee_waived and sibooking_late_fee_refunded. The filter sibooking_late_fee_routes changes the ways a late fee can be collected, sibooking_late_fee_reminder_days the reminder days (default 3 and 7), and sibooking_late_fee_refund_via_gateway decides whether a late-fee refund goes through the gateway.