- Base URL and sign-in
- Who may do what
- Tickets
- GET /wc-sibooking/v1/maintenance/tickets
- GET /wc-sibooking/v1/maintenance/tickets/{id}
- POST /wc-sibooking/v1/maintenance/tickets
- PATCH /wc-sibooking/v1/maintenance/tickets/{id}
- GET /wc-sibooking/v1/maintenance/statuses
- POST /wc-sibooking/v1/maintenance/tickets/{id}/status
- POST /wc-sibooking/v1/maintenance/tickets/{id}/comments
- POST /wc-sibooking/v1/maintenance/tickets/{id}/assign
- POST /wc-sibooking/v1/maintenance/tickets/{id}/write-off
- Example: open a ticket, comment, move it on
- Photos and uploads
- Service schedules
- GET /wc-sibooking/v1/maintenance/schedules
- GET /wc-sibooking/v1/maintenance/schedules/{id}
- POST /wc-sibooking/v1/maintenance/schedules
- PATCH /wc-sibooking/v1/maintenance/schedules/{id}
- DELETE /wc-sibooking/v1/maintenance/schedules/{id}
- GET /wc-sibooking/v1/maintenance/due
- POST /wc-sibooking/v1/maintenance/schedule-units/{id}/done
- POST and DELETE /wc-sibooking/v1/maintenance/schedule-units/{id}/snooze
- POST /wc-sibooking/v1/maintenance/schedule-units/{id}/ticket
- Checklists and inspections
- Costs, parts and vendors
- GET /wc-sibooking/v1/maintenance/tickets/{id}/costs
- POST /wc-sibooking/v1/maintenance/tickets/{id}/costs
- PATCH /wc-sibooking/v1/maintenance/costs/{id}
- DELETE /wc-sibooking/v1/maintenance/costs/{id}
- POST /wc-sibooking/v1/maintenance/tickets/{id}/timer
- POST /wc-sibooking/v1/maintenance/tickets/{id}/vendor
- GET /wc-sibooking/v1/maintenance/parts
- GET /wc-sibooking/v1/maintenance/parts/{id}
- POST /wc-sibooking/v1/maintenance/parts and PATCH /wc-sibooking/v1/maintenance/parts/{id}
- DELETE /wc-sibooking/v1/maintenance/parts/{id}
- GET /wc-sibooking/v1/maintenance/vendors and GET /wc-sibooking/v1/maintenance/vendors/{id}
- POST, PATCH and DELETE on /wc-sibooking/v1/maintenance/vendors
- Damage charges
- Reports
- Needs service on a return
- Hooks
The REST API for Maintenance & Inspections: repair and service tickets for rental units, photos, service schedules and the units that are due, checklists and inspections, costs, parts and vendors, damage charges and the reports. Everything the Maintenance screens do goes through these endpoints, so an outside system (a technician app, a parts system, your accounting tool) can open a ticket, log time or record an inspection the same way. The setup and the conventions shared by every endpoint (keys, errors, pagination) are in REST API overview and authentication.
Base URL and sign-in #
| Namespace | What lives there | Needs |
|---|---|---|
/wp-json/ | Tickets, statuses, uploads, schedules, due units, checklists, inspections, costs, timer, vendor, parts, vendors, damage charges, reports | Maintenance & Inspections 1.0.0 or newer, with Rentals & Bookings Regular |
wc-sibooking/v1is awc-namespace, so it takes a WooCommerce REST API key (WooCommerce › Settings › Advanced › REST API) sent as HTTP Basic, like the other rental endpoints. The key’s user decides what the key may do (next section). Give the key Read/Write permission: a Read key can only send GET requests.- Send bodies as JSON (
Content-Type: application/json). Photos and invoices are the exception: they are sent asmultipart/form-data. - Dates in tickets (
opened_at,hold_start,expected_back,closed_at) are the store’s local time,Y-m-d H:i:s. Timeline events, photos and inspections give GMT (created,created_gmt). Cost lines and damage charges give an ISO 8601 time in GMT without an offset, such as2026-11-11T01:25:44. - Money fields on tickets, costs, parts and charges are strings with the store’s decimals (
"55.50"). The reports give plain numbers. - Errors use the WordPress shape
{"code", "message", "data": {"status"}}. The plugin’s codes start withsimaintenance_and are listed with each endpoint. A missing or invalid parameter answers400withrest_ormissing_ callback_ param rest_invalid_param.
STORE="https://example.com/wp-json"
curl -u "ck_your_key:cs_your_secret" "$STORE/wc-sibooking/v1/maintenance/tickets?tab=open&per_page=20"
Who may do what #
The checks follow the Maintenance screens. A user without the ability gets 401 (not signed in) or 403 with simaintenance_.
| Ability | Who has it | Opens |
|---|---|---|
sibooking_ | Shop managers and administrators, and any role given it | Reading every ticket, statuses, schedules, due units, checklists, inspections, parts, vendors and the reports (not the cost report) |
sibooking_ | Shop managers and administrators | Opening, editing, assigning and writing off tickets; pending uploads; changing schedules, checklist rules, parts and vendors; recording an inspection |
sibooking_ | Administrators, and any user or role given it. This is the technician ability: the plugin gives it to a manager who clicks “Assign to me” | A technician sees the tickets assigned to them and can move them on, comment, add photos, set the vendor, add costs and run the timer on those tickets. The ticket list shows only their own tickets. Also reads statuses, schedules, due units, checklists and inspections |
sibooking_ | Shop managers and administrators | Every cost line (read, change, delete), “billable”, the costs totals on a ticket and the cost report |
sibooking_ | Shop managers and administrators | Damage charges: opening, collecting, waiving, refunding. Reading the charge list also works with the costs ability |
manage_woocommerce | Shop managers and administrators | Counts as every ability above |
Tickets #
A ticket is one repair, service or inspection job for one product: for named units (serial numbers) or for a number of units without serial numbers. kind is repair, service or inspection. source says where it came from: manual, checkin, checkout, inspection, customer, schedule, api or import. priority is low, normal, high or urgent. A ticket that blocks (hold_mode is block) keeps its units out of availability until it is done; none only logs the job.
GET /wc-sibooking/v1/maintenance/tickets #
The ticket list, the same as the board. Answers an array of tickets with X-WP-Total and X-WP-TotalPages headers. Needs sibooking_, or the technician ability (then it lists only the user’s own tickets).
| Parameter | Notes |
|---|---|
tab | open (default), mine, overdue, waiting, services (open service tickets from a schedule), done or all |
status | A status code from GET /maintenance/statuses |
product_id | A product id |
serial | A serial code. Matches the tickets that unit is on. X-WP-Total counts the text matches before this filter, so it can be higher than the rows returned |
assignee_id | A user id; -1 = unassigned |
priority, kind | Values above |
order_id, booking_id | The rental order or booking the ticket came from |
search | Ticket number, title, product, serial or customer |
orderby | number, priority, expected_back or updated |
order | asc or desc |
page, per_page | Page 1 up; per_page 1-100, default 20 |
GET /wc-sibooking/v1/maintenance/tickets/{id} #
One ticket, with the same fields as a list row plus timeline.
| Field | Notes |
|---|---|
id, number | Ticket id and its number (MT-123) |
kind, source, priority, title, problem, description | As set |
status, status_label, category | The status code, its label and its category: open, waiting or closed |
product_id, product_name, sku, location | The product, and the location when Multi Location Inventory is used |
hold_mode, hold_start, expected_back, overdue | The block: block or none, when it starts, the expected date (or null) and whether that date has passed |
opened_at, closed_at, outcome | outcome is fixed, no_fault, replaced or written_off once closed, otherwise empty |
assignee | {id, name} or null |
booking_id, order_id, return_id, customer, from_checkin | Where it came from (0 for none). customer is {id, name} or null |
may_charge, charge_decided | The customer may be charged, and whether staff have decided (charge or no charge) |
vendor | null, or {id, name, ref, due, sent, quote, late} when the ticket is with a vendor |
lines | The units: id, serial_id, serial, quantity, hold ({start, end, quantity, location} or null), hold_state, covers_now |
costs | {total, billable}. Only with sibooking_ |
timeline | Events: id, type, text, actor (staff, system), actor_name, created (GMT), payload |
Errors: 404 simaintenance_.
POST /wc-sibooking/v1/maintenance/tickets #
Opens a ticket. Needs sibooking_. Answers 201 with the ticket, and conflicts ({short, bookings}) listing the bookings the block overlaps.
| Parameter | Notes |
|---|---|
product_id | Required. A product or variation id |
serial_ids | Array of serial ids of that product |
serials | Array of serial codes of that product, instead of or besides serial_ids |
quantity | Units, for a product without serial numbers. Default 1, at most the stock |
kind | Default repair |
priority | Default normal |
title | Default: the problem, or “Maintenance” |
problem, description, note | Free text. problem is one of the store’s problem list or your own text |
hold_mode | block or none. Default: the store’s Blocking setting |
hold_start | Store time Y-m-d H:i. Default now |
expected_back | Y-m-d or Y-m-d H:i. Default: the store’s usual repair time, if set |
assignee_id | A user id |
location | A location the product has (Multi Location Inventory) |
order_id, booking_id | Link the ticket to a rental order or booking |
may_charge | true when the customer may be charged for the damage |
Errors:
| Error | When |
|---|---|
400 simaintenance_product | product_id is not a product |
400 simaintenance_serial | A serial is not a unit of the product |
400 simaintenance_retired | The unit is retired |
409 simaintenance_ | The unit is already on an open ticket. data.ticket_id names it |
400 simaintenance_ | More units than the product has in stock |
400 simaintenance_ | The location does not have this product |
400 simaintenance_ | expected_back is not a date |
PATCH /wc-sibooking/v1/maintenance/tickets/{id} #
Changes a ticket (PUT works too). Needs sibooking_. Send any of title, problem, description, priority, kind, expected_back, hold_mode, hold_start, location; other keys are ignored. Answers the ticket with changed, the names of the fields that changed. Status and assignee have their own endpoints below. Errors: 404 simaintenance_; 400 simaintenance_title (empty title), simaintenance_, simaintenance_.
GET /wc-sibooking/v1/maintenance/statuses #
The statuses. Needs sibooking_ or the technician ability. Each has code, label, category (open, waiting or closed), blocks_stock and system. The built-in codes are reported, new, in_progress, waiting_parts, at_vendor, done (“Ready to rent”), written_off and cancelled; the store can rename them and add its own.
POST /wc-sibooking/v1/maintenance/tickets/{id}/status #
Moves a ticket to another status. Needs sibooking_, or the technician ability on a ticket assigned to the user. Answers the ticket (and conflicts when it is still blocking).
| Parameter | Notes |
|---|---|
status | Required. A status code. Moving to a closed status releases the block; moving a closed ticket to an open status reopens it and blocks again from now |
note | Added to the timeline as a comment |
outcome | fixed (default), no_fault or replaced. Used when closing as done |
Errors: 400 simaintenance_status (unknown status); 400 simaintenance_ (written_off is only reached through the write-off endpoint); 404 simaintenance_.
POST /wc-sibooking/v1/maintenance/tickets/{id}/comments #
Adds a comment to the timeline. Same access as the status endpoint. Body: text (required). Answers 201 with the event (id, type, text, actor, actor_name, created, payload). Error: 400 simaintenance_empty.
POST /wc-sibooking/v1/maintenance/tickets/{id}/assign #
Assigns a technician. Needs sibooking_. Body: user_id (required; 0 = nobody) and make_technician (default false: give that user the technician ability). Answers the ticket. The technician gets the “Maintenance job assigned” email, unless the user assigns the ticket to themselves.
POST /wc-sibooking/v1/maintenance/tickets/{id}/write-off #
Retires the units of the ticket and closes it as written_off. Needs sibooking_.
| Parameter | Notes |
|---|---|
reason | Required: damaged, lost, stolen, sold or end_of_life |
reduce_stock | Default true: lower the product’s stock count by the units written off. false leaves the stock alone |
value, note | Optional |
Answers the ticket with stock_before, stock_after and short (details when the lower stock leaves bookings short, otherwise null). Error: 409 simaintenance_ (already written off).
curl -X POST -u "ck_your_key:cs_your_secret" \
-H "Content-Type: application/json" \
-d '{"reason": "damaged", "reduce_stock": false, "note": "Beyond repair"}' \
"$STORE/wc-sibooking/v1/maintenance/tickets/123/write-off"
Example: open a ticket, comment, move it on #
curl -X POST -u "ck_your_key:cs_your_secret" \
-H "Content-Type: application/json" \
-d '{"product_id": 456, "serials": ["PW-04"], "kind": "repair", "priority": "high", "problem": "Damaged", "title": "Cracked lance", "expected_back": "2026-11-20"}' \
"$STORE/wc-sibooking/v1/maintenance/tickets"
curl -X POST -u "ck_your_key:cs_your_secret" \
-H "Content-Type: application/json" \
-d '{"text": "Ordered a new lance."}' \
"$STORE/wc-sibooking/v1/maintenance/tickets/123/comments"
curl -X POST -u "ck_your_key:cs_your_secret" \
-H "Content-Type: application/json" \
-d '{"status": "done", "outcome": "fixed", "note": "New lance fitted"}' \
"$STORE/wc-sibooking/v1/maintenance/tickets/123/status"
The first call answers 201:
{
"id": 123,
"number": "MT-123",
"kind": "repair",
"source": "api",
"status": "new",
"status_label": "New",
"category": "open",
"priority": "high",
"title": "Cracked lance",
"problem": "Damaged",
"product_id": 456,
"product_name": "Pressure Washer",
"hold_mode": "block",
"hold_start": "2026-11-11 12:25:00",
"expected_back": "2026-11-20",
"overdue": false,
"assignee": null,
"customer": null,
"vendor": null,
"lines": [
{ "id": 17021, "serial_id": 71161, "serial": "PW-04", "quantity": 1, "hold_state": "held", "covers_now": true, "...": "..." }
],
"costs": { "total": "0.00", "billable": "0.00" },
"conflicts": { "short": false, "bookings": [] },
"...": "..."
}
A ticket cannot be deleted through the API. Close it with done or cancelled, or write it off.
Photos and uploads #
Photos are sent as multipart/form-data with the file in the field file (JPEG, PNG or WebP, up to 10 MB). Rentals & Bookings stores them in its private photo store and may convert them to JPEG, so mime can differ from what you sent. The thumb and url links in an answer open only for a user who is logged in to wp-admin.
GET /wc-sibooking/v1/maintenance/tickets/{id}/attachments #
The photos of a ticket. Needs access to the ticket (see above). Each has id, name, mime, size, context (repair, checkin, checkout, customer or invoice), thumb, url and created (GMT).
POST /wc-sibooking/v1/maintenance/tickets/{id}/attachments #
Adds a photo to the timeline of a ticket. Needs sibooking_, or the technician ability on a ticket assigned to the user. Fields: file (required) and note (optional caption). Answers 201 with the photo. Errors: 400 simaintenance_no_file; 400 for a file that is not an image or is too large; 404 simaintenance_.
POST /wc-sibooking/v1/maintenance/uploads #
Uploads a photo before its ticket exists, for example at a return. Needs sibooking_. Fields: file (required) and serial_id (optional). Answers 201 with {"id": 918, "name": "lance.jpg", "status": "pending"}. Pass the id in maintenance.photo_ids when you return the units (see Needs service on a return); the ticket adopts the photos. Photos nobody adopts are cleared after a day.
curl -X POST -u "ck_your_key:cs_your_secret" \
-F "file=@/path/to/lance.jpg" \
"$STORE/wc-sibooking/v1/maintenance/uploads"
Service schedules #
A schedule says when a product (or one unit) is due for service: every so many days, weeks, months or years (interval), rentals, days on rent, or meter hours. Each unit of the product gets its own state. A due unit can open a service ticket, as the schedule says in on_due.
GET /wc-sibooking/v1/maintenance/schedules #
Lists the schedules. Needs sibooking_ or the technician ability. Answers an array with X-WP-Total and X-WP-TotalPages. Parameters: product_id, active (boolean), search, page, per_page (1-100, default 20).
GET /wc-sibooking/v1/maintenance/schedules/{id} #
One schedule, with its units. Error: 404 simaintenance_.
| Field | Notes |
|---|---|
id, name, product_id, active | |
scope | product (every unit) or serial (one unit, in serial_id) |
interval | null, or a number and a unit: 365d, 12w, 6mo, 1y |
rentals, rental_days, hours | Other triggers, or null. hours reads the meter field meter_field_id |
due_soon_percent, due_soon | When “due soon” starts: a percent of the interval, or {days, rentals, rentalDays, hours} |
on_due | ticket_block (open a ticket and block the unit at its next check-in), ticket (open a ticket, no block) or remind (remind only) |
checklist_id, assignee_id, priority, est_minutes, starts_on | What the opened ticket gets; starts_on is Y-m-d |
description, plan | A readable summary, and the schedule as the rules engine reads it |
units | The unit states (below) |
A unit state:
| Field | Notes |
|---|---|
id, schedule_id, schedule_name, product_id, serial_id, serial | serial_id and serial are null for a product without serial numbers |
state, state_text | ok, due_soon, due, overdue or snoozed, and a readable line |
unsnoozed | The state without a snooze |
trigger, next_due, next_due_estimated, triggers | What is due first, the date, and each trigger with every, used, left and state |
last_done_at, last_done_rentals, last_done_rental_days, last_done_meter | The last service |
snooze_until, snooze_rentals, snooze_reason | An active snooze |
open_ticket_id, not_reopened | The open service ticket for this unit, and whether a closed one is not reopened automatically |
POST /wc-sibooking/v1/maintenance/schedules #
Creates a schedule. Needs sibooking_. Answers 201 with the schedule and its units. Send a JSON body with the fields in the table above (name, product_id, scope, serial_id, interval, rentals, rental_days, hours, meter_field_id, due_soon_percent, due_soon, on_due, checklist_id, assignee_id, priority, est_minutes, starts_on, active). product_id and at least one trigger are required. assignee_id must be a user with the technician ability, otherwise it is dropped. For a product without serial numbers only interval works.
Errors:
| Error | When |
|---|---|
400 simaintenance_product | product_id is not a product |
400 simaintenance_serial | scope is serial and serial_id is not a unit of the product |
400 simaintenance_ | interval is not a number of days, weeks, months or years |
400 simaintenance_number | rentals, rental_days or hours is not above 0 |
400 simaintenance_ | A rentals, rental days or hours trigger on a product without serial numbers |
400 simaintenance_meter | hours without a meter field in meter_field_id |
400 simaintenance_ | No trigger given |
PATCH /wc-sibooking/v1/maintenance/schedules/{id} #
Changes a schedule (PUT works too). Send only the fields to change. Answers the schedule with its units. Same errors, and 404.
DELETE /wc-sibooking/v1/maintenance/schedules/{id} #
Deletes the schedule and the state of its units. Open service tickets stay. Answers {"deleted": true, "id": 321}.
GET /wc-sibooking/v1/maintenance/due #
The units that need attention, across all schedules. Needs sibooking_ or the technician ability. Answers an array of unit states.
| Parameter | Notes |
|---|---|
states | Array of due_soon, due, overdue, snoozed, ok. Default due_soon, due, overdue. Send as states[]= |
limit | 1-500, default 200 |
POST /wc-sibooking/v1/maintenance/schedule-units/{id}/done #
Records that a unit was serviced. Needs sibooking_. Body: done_at (Y-m-d, default now) and note. Answers the unit state. Errors: 400 simaintenance_future (a date in the future), simaintenance_date; 404 simaintenance_.
POST and DELETE /wc-sibooking/v1/maintenance/schedule-units/{id}/snooze #
POST puts the service off. Body: reason (required) and either until (Y-m-d, after today) or rentals (a number of rentals). DELETE ends the snooze. Both need sibooking_ and answer the unit state. Errors: 400 simaintenance_snooze (neither until nor rentals, or a date that is not after today), simaintenance_; 404.
POST /wc-sibooking/v1/maintenance/schedule-units/{id}/ticket #
Opens the service ticket for a unit now, with the schedule’s checklist, priority and technician. Needs sibooking_. No body. Answers 201 with the ticket (kind service, source schedule). Errors: 409 simaintenance_ (the unit is already on an open ticket); 404 simaintenance_.
curl -X POST -u "ck_your_key:cs_your_secret" \
-H "Content-Type: application/json" \
-d '{"name": "Yearly service", "product_id": 456, "interval": "12mo", "due_soon": {"days": 14}, "on_due": "ticket", "priority": "normal"}' \
"$STORE/wc-sibooking/v1/maintenance/schedules"
curl -X POST -u "ck_your_key:cs_your_secret" \
-H "Content-Type: application/json" \
-d '{"done_at": "2026-11-10", "note": "Serviced in the workshop"}' \
"$STORE/wc-sibooking/v1/maintenance/schedule-units/789/done"
A unit state from GET /maintenance/due:
{
"id": 789,
"schedule_id": 321,
"schedule_name": "Yearly service",
"product_id": 456,
"serial_id": 71161,
"serial": "PW-04",
"state": "overdue",
"state_text": "Overdue (since October 2, 2026)",
"trigger": "interval",
"next_due": "2026-10-02",
"triggers": [
{ "trigger": "interval", "every": "30d", "used": 70, "left": -40, "state": "overdue", "dueDate": "2026-10-02" }
],
"last_done_at": "2026-09-02",
"snooze_until": null,
"open_ticket_id": null,
"...": "..."
}
Checklists and inspections #
A checklist is a Rentals & Bookings serial custom field set that is marked as a checklist here. Its yes/no and choice fields can fail; a failed answer opens a ticket or is only recorded, as the field’s rule says. An inspection is one recorded run of a checklist for one unit. At a check-out or check-in the answers come in through the move’s readings; you can also record one by hand.
GET /wc-sibooking/v1/maintenance/checklists #
Every serial custom field set, each marked whether it is a checklist now. Needs sibooking_ or the technician ability. Each has id (the set id), name, description, active and fields: id, key, label, type, options and rule. A rule has fail (the answers that fail: yes / no, or option keys), action (ticket or record), and the kind and priority of the ticket it opens. A store with no field sets answers [].
GET /wc-sibooking/v1/maintenance/checklists/{id} #
One set. Error: 404 simaintenance_.
PATCH /wc-sibooking/v1/maintenance/checklists/{id} #
Marks a set as a checklist or not, and changes its rules. Needs sibooking_. Body: active (boolean) and rules, an object keyed by field id: {"15": {"fail": ["no"], "action": "ticket", "kind": "repair", "priority": "high"}}. Rules you leave out stay as they are. Answers the set. Error: 404 simaintenance_.
GET /wc-sibooking/v1/maintenance/inspections #
Lists inspections, newest first, with X-WP-Total and X-WP-TotalPages. Needs sibooking_ or the technician ability. Parameters: ticket_id, serial_id, booking_id, product_id, checklist_id, context (checkout, checkin, service or inspection), result (pass or fail), page, per_page (1-100, default 20).
GET /wc-sibooking/v1/maintenance/inspections/{id} #
One inspection:
| Field | Notes |
|---|---|
id, checklist | checklist is {id, name} |
context, result | result is pass or fail |
product_id, serial_id, serial, booking_id, order_id, send_id, return_id, user_id, ticket_id | Where it was done, and the ticket it opened or joined (0 for none) |
items | One per answered field: field_id, key, label, type, value, failed, skipped, note, action |
failed | The labels of the failed fields |
created_gmt |
Error: 404 simaintenance_.
POST /wc-sibooking/v1/maintenance/inspections #
Records an inspection by hand. Needs sibooking_, or the technician ability on the ticket named in ticket_id.
| Parameter | Notes |
|---|---|
serial_id | Required. The unit |
values | Required. An object of serial custom field key and answer, such as {"lens_clean": "yes", "battery": "ok"}. The keys are fields of the checklists this unit has |
context | inspection (default) or service |
ticket_id | Record it on this ticket |
note | Optional |
Answers 201 with an array of inspections (one per checklist the values belong to), each with a ticket field: null, or the ticket it opened (created: true) or joined. Errors: 400 unknown_reading_field (a key that is not a field); 422 simaintenance_ (none of the values belongs to a checklist of this unit: they are kept as readings only); 403 simaintenance_.
Costs, parts and vendors #
Cost lines are the parts, labour, vendor invoices and other costs of a ticket. kind is part, labour, vendor or other.
GET /wc-sibooking/v1/maintenance/tickets/{id}/costs #
The lines and the totals. Needs sibooking_, or the technician ability on the ticket.
{
"ticket_id": 123,
"lines": [
{
"id": 4289, "ticket_id": 123, "kind": "part", "description": "Trigger gun", "text": "Trigger gun × 3",
"part_id": 199, "vendor_id": 241, "serial_id": 0, "qty": 3, "unit_cost": "18.50",
"minutes": 0, "rate": "0.00", "amount": "55.50", "billable": true, "running": false,
"user_id": 12, "started": null, "ended": null, "attachment_id": 0, "created": "2026-11-11T01:25:43"
}
],
"totals": { "part": "55.50", "labour": "20.00", "vendor": "0.00", "other": "0.00", "total": "75.50", "billable": "55.50", "minutes": 31 }
}
POST /wc-sibooking/v1/maintenance/tickets/{id}/costs #
Adds a line. Needs sibooking_, or the technician ability on the ticket. Answers 201 with the line. A closed ticket takes new lines only from sibooking_.
| Parameter | Notes |
|---|---|
kind | Required: part, labour, vendor or other |
part_id, description | part: a part from the parts list, or text. The part’s name, cost and vendor fill in. A counted part’s stock goes down by the quantity |
qty, unit_cost | part. qty default 1; unit_cost default: the part’s cost |
minutes or hours, rate | labour. rate default: the store’s labour rate. amount is worked out |
vendor_id, amount | vendor: the invoice amount. vendor_id default: the ticket’s vendor. Send description when there is no vendor |
amount, description | other: both required |
serial_id | Optional: the unit of the ticket the line is for |
billable | Bill the line to the customer. Only users with the costs ability can set it. Default: on when the ticket’s may_charge is on |
invoice | vendor only, as a multipart file: the vendor’s invoice (PDF or photo, up to 10 MB). Send the other fields as form fields in that case |
Errors:
| Error | When |
|---|---|
400 simaintenance_ | kind is missing or not one of the four |
400 simaintenance_part | part_id is not on the parts list |
400 simaintenance_ | No part, vendor or description to name the line |
400 simaintenance_ | qty is not above 0 |
400 simaintenance_ | A cost or amount is not a number of 0 or more |
400 simaintenance_ | Labour without minutes |
400 simaintenance_ | rate is not a number of 0 or more |
400 simaintenance_vendor | vendor_id is not a vendor |
400 simaintenance_closed | The ticket is closed |
400 simaintenance_, simaintenance_ | The invoice is not a PDF or photo, or over 10 MB |
PATCH /wc-sibooking/v1/maintenance/costs/{id} #
Changes a line (PUT works too). Send any of description, qty, unit_cost, minutes, rate, amount, billable. The kind cannot change, and hours is not read here: send minutes. The costs ability changes any line and alone sets billable. A technician changes only the lines they added, while they are on the ticket. Answers the line. Errors: 404 simaintenance_; the simaintenance_cost_* errors above.
DELETE /wc-sibooking/v1/maintenance/costs/{id} #
Removes a line (a part line gives its stock back). Same access as the change. Answers {"deleted": true, "id": 4290}.
POST /wc-sibooking/v1/maintenance/tickets/{id}/timer #
Starts or stops the labour timer. Needs sibooking_, or the technician ability on the ticket. One timer can run per user and ticket.
| Parameter | Notes |
|---|---|
op | start (default) or stop |
cost_id | Required for stop: the id the start answered |
Both answer the labour line: start with running: true and started, stop with running: false, ended and the minutes and amount worked out (rounded to the minute). Errors: 400 simaintenance_timer (no such running timer, or it is another user’s); 400 simaintenance_closed (starting on a closed ticket).
POST /wc-sibooking/v1/maintenance/tickets/{id}/vendor #
Sets the vendor a ticket is with. Needs sibooking_, or the technician ability on the ticket. Body, all optional: vendor_id (0 = no vendor; left out keeps the current one), vendor_ref, sent (Y-m-d), vendor_due (Y-m-d), quote. Answers the ticket with its vendor object. Errors: 400 simaintenance_vendor (not a vendor), simaintenance_ (not a number).
curl -X POST -u "ck_your_key:cs_your_secret" \
-H "Content-Type: application/json" \
-d '{"kind": "labour", "minutes": 30, "rate": "40.00", "description": "Bench repair"}' \
"$STORE/wc-sibooking/v1/maintenance/tickets/123/costs"
curl -X POST -u "ck_your_key:cs_your_secret" \
-H "Content-Type: application/json" \
-d '{"op": "start"}' \
"$STORE/wc-sibooking/v1/maintenance/tickets/123/timer"
curl -X POST -u "ck_your_key:cs_your_secret" \
-H "Content-Type: application/json" \
-d '{"vendor_id": 241, "vendor_ref": "RMA-1001", "sent": "2026-11-11", "vendor_due": "2026-11-18", "quote": "75.00"}' \
"$STORE/wc-sibooking/v1/maintenance/tickets/123/vendor"
curl -X POST -u "ck_your_key:cs_your_secret" \
-F "kind=vendor" -F "vendor_id=241" -F "amount=75.00" -F "description=Housing repair" \
-F "invoice=@/path/to/invoice.pdf" \
"$STORE/wc-sibooking/v1/maintenance/tickets/123/costs"
GET /wc-sibooking/v1/maintenance/parts #
The parts list. Needs sibooking_ (the technician ability alone is not enough). Parameters: search, active (boolean, default true: hidden parts are left out), vendor_id, page, per_page (1-100, default 50). Answers an array with X-WP-Total and X-WP-TotalPages. A part: id, name, sku, unit_cost, vendor_id, vendor_name, stock_qty (null = not counted), notes, active.
GET /wc-sibooking/v1/maintenance/parts/{id} #
One part. Error: 404 simaintenance_.
POST /wc-sibooking/v1/maintenance/parts and PATCH /wc-sibooking/v1/maintenance/parts/{id} #
Adds a part (201) or changes one (200; PUT works too). Needs sibooking_. Body: name (required on add), sku, unit_cost, vendor_id, stock_qty, notes, active. Errors: 400 simaintenance_, simaintenance_; 404. Names and SKUs are not checked for duplicates.
DELETE /wc-sibooking/v1/maintenance/parts/{id} #
Answers {"id": 637, "result": "deleted"}, or "result": "hidden" when cost lines use the part: it is then only hidden from the list (active false).
GET /wc-sibooking/v1/maintenance/vendors and GET /wc-sibooking/v1/maintenance/vendors/{id} #
The vendors, with search, active (default true), page and per_page (default 50), and one vendor. Needs sibooking_. A vendor: id, name, contact, email, phone, notes, active.
POST, PATCH and DELETE on /wc-sibooking/v1/maintenance/vendors #
POST /maintenance/vendors adds (201), PATCH /maintenance/ changes (200; PUT works too) and DELETE /maintenance/ removes a vendor. Needs sibooking_. Body: name (required on add), contact, email, phone, notes, active. DELETE answers "result": "deleted", or "hidden" when tickets or cost lines use the vendor. Errors: 400 simaintenance_, simaintenance_; 404. Names are not checked for duplicates.
Damage charges #
When a customer damages a unit, staff can charge them from the ticket. The ticket must come from a rental order (order_id), and damage charges must be on in the Maintenance settings. A charge is collected one of four ways (route): deposit (from the held security deposit), card (the saved card), link (an email with a pay link) or counter (paid at the counter). With no route the charge waits as to_review. Nothing is charged until a person or an integration asks for it with one of these calls.
A charge status is to_review, charging, pay_link_sent, failed or needs_action (open), or paid, waived, refunded, part_refunded or cancelled (settled).
POST /wc-sibooking/v1/maintenance/tickets/{id}/charge #
Opens a charge. Needs sibooking_ and access to the ticket. Answers 201 with the charge.
| Parameter | Notes |
|---|---|
amount | Required. A number above 0 (the order’s currency) |
reason | Shown to the customer. Default: a line naming the unit |
note_staff | A note for staff |
route | deposit, card, link or counter. Empty = To review. Must be one of the ways open for this order and amount |
counter_method, counter_ref | With counter: how it was paid (default cash) and a reference |
confirm_again | true to open a second charge on a ticket that already has one |
Errors:
| Error | When |
|---|---|
400 simaintenance_ | Damage charges are off in the settings |
400 simaintenance_ | The ticket has no rental order, or the order is cancelled, refunded or failed |
400 simaintenance_ | amount is not above 0 |
400 simaintenance_ | The route is unknown or not open for this charge |
409 simaintenance_ | The ticket already has a charge: send confirm_again to open another. data.charges lists the numbers |
409 simaintenance_ | The same amount was opened less than a minute ago |
POST /wc-sibooking/v1/maintenance/tickets/{id}/no-charge #
Records that the customer is not charged. A held deposit is released. Needs sibooking_. Body: note. Answers {"ticket_id": 123, "charge_decided": true, "may_charge": false}.
GET /wc-sibooking/v1/maintenance/charges #
Lists charges. Needs sibooking_ or sibooking_. Answers an array with X-WP-Total and X-WP-TotalPages. Parameters: status (array of the codes above, sent as status[]=paid), ticket_id, order_id, from, to (dates), page, per_page (1-100, default 50).
GET /wc-sibooking/v1/maintenance/charges/{id} #
One charge:
| Field | Notes |
|---|---|
id, number, ticket_id, order_id, kind, status | order_id is the rental order; charge_order_id is the order made to collect it |
amount, tax, total, refunded, currency | Decimal strings |
reason, route, paid_via, paid_at | |
charge_order_id, pay_url | pay_url is the checkout payment link while the order waits for payment, otherwise null |
attempts, next_attempt_at, last_error | Card attempts |
created_at | |
routes | Only while to_review: the ways it can be collected now |
Error: 404 simaintenance_.
The charge actions #
All are POST, need sibooking_, and answer the charge as it is after the action. A charge in the wrong state answers 409 simaintenance_, and one that is being collected 409 simaintenance_busy. An unknown charge id answers 404 simaintenance_.
| Endpoint | Body | What it does |
|---|---|---|
POST /maintenance/ | route (required), counter_method, counter_ref | Collects a charge that is to_review by that route. card charges the saved card |
POST /maintenance/ | method (default cash), ref | Records that the customer paid at the counter |
POST /maintenance/ | none | Sends the pay link again |
POST /maintenance/ | none | Tries a failed card charge again |
POST /maintenance/ | reason (required) | Waives the charge. Error 400 simaintenance_ |
POST /maintenance/ | amount (default: all that is left), reason | Refunds the charge through the payment gateway. Error 400 simaintenance_ for an amount above what is left |
collect with card, retry and refund move real money. Try them on a test order with a test payment method first.
curl -X POST -u "ck_your_key:cs_your_secret" \
-H "Content-Type: application/json" \
-d '{"amount": "25.00", "reason": "Cracked lance", "route": "link"}' \
"$STORE/wc-sibooking/v1/maintenance/tickets/123/charge"
curl -u "ck_your_key:cs_your_secret" \
"$STORE/wc-sibooking/v1/maintenance/charges?status[]=to_review&status[]=failed"
Reports #
GET /wc-sibooking/v1/maintenance/reports/{type} #
The data of the Reports screen. type is cost, downtime, utilisation, compliance or problems. Needs sibooking_; the cost report also needs sibooking_. An unknown type answers 404 simaintenance_report.
| Parameter | Notes |
|---|---|
from, to | Y-m-d. Default: the first day of this month to today. A range over 366 days is cut to the last 366 days |
product_id | One product |
location | A location (Multi Location Inventory) |
kind | repair, service or inspection |
Every report answers report (the type), filters (the dates and filters as used), rows and totals. Money in reports is a plain number.
| Report | Row fields | Totals |
|---|---|---|
cost | One row per product: product_id, product, part, labour, vendor, other, total, billable, tickets, revenue, pct, and serials (the same per unit) | The same sums |
downtime | product_id, product, serial_id, serial, days, tickets, failures, mttr, rentals, between | days, tickets, failures, rentals, mttr |
utilisation | product_id, product, stock, stock_days, blocked, blocked_pct, rented, rented_pct, shortage | Sums for all products |
compliance | schedule_id, schedule, product_id, product, done, on_time, late, pct, overdue | done, on_time, late, overdue, pct |
problems | product_id, product, problem, tickets, share | tickets; and top lists the most common problems with tickets and share |
curl -u "ck_your_key:cs_your_secret" \
"$STORE/wc-sibooking/v1/maintenance/reports/compliance?from=2026-10-01&to=2026-11-11"
{
"report": "compliance",
"filters": { "from": "2026-10-01", "to": "2026-11-11", "product_id": 0, "location": "", "kind": "" },
"rows": [
{ "schedule_id": 321, "schedule": "Yearly service", "product_id": 456, "product": "Pressure Washer",
"done": 1, "on_time": 1, "late": 0, "pct": 100, "overdue": 0 }
],
"totals": { "done": 1, "on_time": 1, "late": 0, "overdue": 0, "pct": 100 }
}
Needs service on a return #
The Rentals & Bookings return endpoints (POST /wc-sibooking/ and POST /wc-sibooking/, see Sending and returning rentals, and serial codes) take an extra maintenance field while Maintenance & Inspections is active. It is the “Needs service” box of the Return screen: it opens a ticket for the units that come back. It works at the top level of the request or inside each item of a batch (items[]). The user needs sibooking_, otherwise the return is refused with 403 simaintenance_.
| Field | Notes |
|---|---|
true | The whole field can be true: every unit of the return goes to maintenance with the store’s defaults |
serials | Array of serial codes. Default: every serial returned. A code that is not part of this return is refused (400 simaintenance_, with the codes in data.serials) |
quantity | Units, for a product without serial numbers. Default: every unit returned. More than returned: 400 simaintenance_ |
problem | Up to 64 characters |
note | Up to 5,000 characters |
block | Keep the units out of stock until fixed. Default: the store’s Blocking setting. A blocking unit comes back as “In maintenance” |
may_charge | The customer may be charged for the damage. Default false |
priority | low, normal, high or urgent. Default high |
photo_ids | Up to 10 ids from POST /maintenance/uploads |
curl -X POST -u "ck_your_key:cs_your_secret" \
-H "Content-Type: application/json" \
-d '{"booking_id": 456, "serials": ["PW-04"], "maintenance": {"serials": ["PW-04"], "problem": "Damaged", "note": "Cracked lance", "block": true, "may_charge": true, "priority": "high", "photo_ids": [918]}}' \
"$STORE/wc-sibooking/v1/return"
The move’s answer carries what Maintenance did, as extra keys:
| Key | On | Notes |
|---|---|---|
maintenance_tickets | A return that asked for Needs service | One entry per ticket: ticket_id, number, booking_id, created (false when the unit was added to an open ticket), serials, quantity, and error when it failed. The key is present, possibly empty, whenever the request carried maintenance |
maintenance_ | A send or a return that answered a checklist | The inspections, each as in GET /maintenance/ plus a ticket field |
maintenance_warnings | A send of a unit that has a service due | One entry per unit: serial, state, schedules, message. The send still goes through, unless the store’s check-out guard is set to Block when overdue: then an overdue unit is refused with 409 simaintenance_ (data.serials names the units) |
Hooks #
The endpoints use the same services as the screens, so the plugin’s actions fire for API changes too: simaintenance_, simaintenance_, simaintenance_, simaintenance_, simaintenance_, simaintenance_, simaintenance_, simaintenance_, simaintenance_, simaintenance_, simaintenance_, simaintenance_, simaintenance_, simaintenance_ and simaintenance_. The settings and emails are in Maintenance settings, emails and developers.
