View Categories

REST API: Maintenance & Inspections

29 min read

Table of Contents

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 #

NamespaceWhat lives thereNeeds
/wp-json/wc-sibooking/v1/maintenance/Tickets, statuses, uploads, schedules, due units, checklists, inspections, costs, timer, vendor, parts, vendors, damage charges, reportsMaintenance & Inspections 1.0.0 or newer, with Rentals & Bookings Regular
  • wc-sibooking/v1 is a wc- 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 as multipart/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 as 2026-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 with simaintenance_ and are listed with each endpoint. A missing or invalid parameter answers 400 with rest_missing_callback_param or 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_forbidden.

AbilityWho has itOpens
sibooking_maintenance_viewShop managers and administrators, and any role given itReading every ticket, statuses, schedules, due units, checklists, inspections, parts, vendors and the reports (not the cost report)
sibooking_maintenance_manageShop managers and administratorsOpening, editing, assigning and writing off tickets; pending uploads; changing schedules, checklist rules, parts and vendors; recording an inspection
sibooking_maintenance_workAdministrators, 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_maintenance_costsShop managers and administratorsEvery cost line (read, change, delete), “billable”, the costs totals on a ticket and the cost report
sibooking_maintenance_chargeShop managers and administratorsDamage charges: opening, collecting, waiving, refunding. Reading the charge list also works with the costs ability
manage_woocommerceShop managers and administratorsCounts 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_maintenance_view, or the technician ability (then it lists only the user’s own tickets).

ParameterNotes
tabopen (default), mine, overdue, waiting, services (open service tickets from a schedule), done or all
statusA status code from GET /maintenance/statuses
product_idA product id
serialA 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_idA user id; -1 = unassigned
priority, kindValues above
order_id, booking_idThe rental order or booking the ticket came from
searchTicket number, title, product, serial or customer
orderbynumber, priority, expected_back or updated
orderasc or desc
page, per_pagePage 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.

FieldNotes
id, numberTicket id and its number (MT-123)
kind, source, priority, title, problem, descriptionAs set
status, status_label, categoryThe status code, its label and its category: open, waiting or closed
product_id, product_name, sku, locationThe product, and the location when Multi Location Inventory is used
hold_mode, hold_start, expected_back, overdueThe block: block or none, when it starts, the expected date (or null) and whether that date has passed
opened_at, closed_at, outcomeoutcome 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_checkinWhere it came from (0 for none). customer is {id, name} or null
may_charge, charge_decidedThe customer may be charged, and whether staff have decided (charge or no charge)
vendornull, or {id, name, ref, due, sent, quote, late} when the ticket is with a vendor
linesThe units: id, serial_id, serial, quantity, hold ({start, end, quantity, location} or null), hold_state, covers_now
costs{total, billable}. Only with sibooking_maintenance_costs
timelineEvents: id, type, text, actor (staff, system), actor_name, created (GMT), payload

Errors: 404 simaintenance_not_found.

POST /wc-sibooking/v1/maintenance/tickets #

Opens a ticket. Needs sibooking_maintenance_manage. Answers 201 with the ticket, and conflicts ({short, bookings}) listing the bookings the block overlaps.

ParameterNotes
product_idRequired. A product or variation id
serial_idsArray of serial ids of that product
serialsArray of serial codes of that product, instead of or besides serial_ids
quantityUnits, for a product without serial numbers. Default 1, at most the stock
kindDefault repair
priorityDefault normal
titleDefault: the problem, or “Maintenance”
problem, description, noteFree text. problem is one of the store’s problem list or your own text
hold_modeblock or none. Default: the store’s Blocking setting
hold_startStore time Y-m-d H:i. Default now
expected_backY-m-d or Y-m-d H:i. Default: the store’s usual repair time, if set
assignee_idA user id
locationA location the product has (Multi Location Inventory)
order_id, booking_idLink the ticket to a rental order or booking
may_chargetrue when the customer may be charged for the damage

Errors:

ErrorWhen
400 simaintenance_productproduct_id is not a product
400 simaintenance_serialA serial is not a unit of the product
400 simaintenance_retiredThe unit is retired
409 simaintenance_duplicateThe unit is already on an open ticket. data.ticket_id names it
400 simaintenance_quantityMore units than the product has in stock
400 simaintenance_locationThe location does not have this product
400 simaintenance_expectedexpected_back is not a date

PATCH /wc-sibooking/v1/maintenance/tickets/{id} #

Changes a ticket (PUT works too). Needs sibooking_maintenance_manage. 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_not_found; 400 simaintenance_title (empty title), simaintenance_expected, simaintenance_location.

GET /wc-sibooking/v1/maintenance/statuses #

The statuses. Needs sibooking_maintenance_view 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_maintenance_manage, or the technician ability on a ticket assigned to the user. Answers the ticket (and conflicts when it is still blocking).

ParameterNotes
statusRequired. 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
noteAdded to the timeline as a comment
outcomefixed (default), no_fault or replaced. Used when closing as done

Errors: 400 simaintenance_status (unknown status); 400 simaintenance_use_write_off (written_off is only reached through the write-off endpoint); 404 simaintenance_not_found.

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_maintenance_manage. 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_maintenance_manage.

ParameterNotes
reasonRequired: damaged, lost, stolen, sold or end_of_life
reduce_stockDefault true: lower the product’s stock count by the units written off. false leaves the stock alone
value, noteOptional

Answers the ticket with stock_before, stock_after and short (details when the lower stock leaves bookings short, otherwise null). Error: 409 simaintenance_written_off (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_maintenance_manage, 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_not_found.

POST /wc-sibooking/v1/maintenance/uploads #

Uploads a photo before its ticket exists, for example at a return. Needs sibooking_maintenance_manage. 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_maintenance_view 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_not_found.

FieldNotes
id, name, product_id, active
scopeproduct (every unit) or serial (one unit, in serial_id)
intervalnull, or a number and a unit: 365d, 12w, 6mo, 1y
rentals, rental_days, hoursOther triggers, or null. hours reads the meter field meter_field_id
due_soon_percent, due_soonWhen “due soon” starts: a percent of the interval, or {days, rentals, rentalDays, hours}
on_dueticket_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_onWhat the opened ticket gets; starts_on is Y-m-d
description, planA readable summary, and the schedule as the rules engine reads it
unitsThe unit states (below)

A unit state:

FieldNotes
id, schedule_id, schedule_name, product_id, serial_id, serialserial_id and serial are null for a product without serial numbers
state, state_textok, due_soon, due, overdue or snoozed, and a readable line
unsnoozedThe state without a snooze
trigger, next_due, next_due_estimated, triggersWhat 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_meterThe last service
snooze_until, snooze_rentals, snooze_reasonAn active snooze
open_ticket_id, not_reopenedThe 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_maintenance_manage. 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:

ErrorWhen
400 simaintenance_productproduct_id is not a product
400 simaintenance_serialscope is serial and serial_id is not a unit of the product
400 simaintenance_intervalinterval is not a number of days, weeks, months or years
400 simaintenance_numberrentals, rental_days or hours is not above 0
400 simaintenance_quantity_scheduleA rentals, rental days or hours trigger on a product without serial numbers
400 simaintenance_meterhours without a meter field in meter_field_id
400 simaintenance_no_triggerNo 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_maintenance_view or the technician ability. Answers an array of unit states.

ParameterNotes
statesArray of due_soon, due, overdue, snoozed, ok. Default due_soon, due, overdue. Send as states[]=due&states[]=overdue
limit1-500, default 200

POST /wc-sibooking/v1/maintenance/schedule-units/{id}/done #

Records that a unit was serviced. Needs sibooking_maintenance_manage. 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_not_found.

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_maintenance_manage and answer the unit state. Errors: 400 simaintenance_snooze (neither until nor rentals, or a date that is not after today), simaintenance_snooze_reason; 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_maintenance_manage. No body. Answers 201 with the ticket (kind service, source schedule). Errors: 409 simaintenance_duplicate (the unit is already on an open ticket); 404 simaintenance_not_found.

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_maintenance_view 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_not_found.

PATCH /wc-sibooking/v1/maintenance/checklists/{id} #

Marks a set as a checklist or not, and changes its rules. Needs sibooking_maintenance_manage. 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_not_found.

GET /wc-sibooking/v1/maintenance/inspections #

Lists inspections, newest first, with X-WP-Total and X-WP-TotalPages. Needs sibooking_maintenance_view 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:

FieldNotes
id, checklistchecklist is {id, name}
context, resultresult is pass or fail
product_id, serial_id, serial, booking_id, order_id, send_id, return_id, user_id, ticket_idWhere it was done, and the ticket it opened or joined (0 for none)
itemsOne per answered field: field_id, key, label, type, value, failed, skipped, note, action
failedThe labels of the failed fields
created_gmt

Error: 404 simaintenance_not_found.

POST /wc-sibooking/v1/maintenance/inspections #

Records an inspection by hand. Needs sibooking_maintenance_manage, or the technician ability on the ticket named in ticket_id.

ParameterNotes
serial_idRequired. The unit
valuesRequired. 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
contextinspection (default) or service
ticket_idRecord it on this ticket
noteOptional

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_no_checklist (none of the values belongs to a checklist of this unit: they are kept as readings only); 403 simaintenance_forbidden.

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_maintenance_costs, 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_maintenance_costs, or the technician ability on the ticket. Answers 201 with the line. A closed ticket takes new lines only from sibooking_maintenance_costs.

ParameterNotes
kindRequired: part, labour, vendor or other
part_id, descriptionpart: 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_costpart. qty default 1; unit_cost default: the part’s cost
minutes or hours, ratelabour. rate default: the store’s labour rate. amount is worked out
vendor_id, amountvendor: the invoice amount. vendor_id default: the ticket’s vendor. Send description when there is no vendor
amount, descriptionother: both required
serial_idOptional: the unit of the ticket the line is for
billableBill the line to the customer. Only users with the costs ability can set it. Default: on when the ticket’s may_charge is on
invoicevendor 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:

ErrorWhen
400 simaintenance_cost_kindkind is missing or not one of the four
400 simaintenance_partpart_id is not on the parts list
400 simaintenance_cost_descNo part, vendor or description to name the line
400 simaintenance_cost_qtyqty is not above 0
400 simaintenance_cost_amountA cost or amount is not a number of 0 or more
400 simaintenance_cost_minutesLabour without minutes
400 simaintenance_cost_raterate is not a number of 0 or more
400 simaintenance_vendorvendor_id is not a vendor
400 simaintenance_closedThe ticket is closed
400 simaintenance_file_type, simaintenance_file_sizeThe 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_not_found; 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_maintenance_costs, or the technician ability on the ticket. One timer can run per user and ticket.

ParameterNotes
opstart (default) or stop
cost_idRequired 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_maintenance_manage, 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_vendor_quote (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_maintenance_view (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_not_found.

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_maintenance_manage. Body: name (required on add), sku, unit_cost, vendor_id, stock_qty, notes, active. Errors: 400 simaintenance_part_name, simaintenance_part_cost; 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_maintenance_view. 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/vendors/{id} changes (200; PUT works too) and DELETE /maintenance/vendors/{id} removes a vendor. Needs sibooking_maintenance_manage. 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_vendor_name, simaintenance_vendor_email; 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_maintenance_charge and access to the ticket. Answers 201 with the charge.

ParameterNotes
amountRequired. A number above 0 (the order’s currency)
reasonShown to the customer. Default: a line naming the unit
note_staffA note for staff
routedeposit, card, link or counter. Empty = To review. Must be one of the ways open for this order and amount
counter_method, counter_refWith counter: how it was paid (default cash) and a reference
confirm_againtrue to open a second charge on a ticket that already has one

Errors:

ErrorWhen
400 simaintenance_damage_offDamage charges are off in the settings
400 simaintenance_damage_orderThe ticket has no rental order, or the order is cancelled, refunded or failed
400 simaintenance_damage_amountamount is not above 0
400 simaintenance_damage_routeThe route is unknown or not open for this charge
409 simaintenance_damage_againThe ticket already has a charge: send confirm_again to open another. data.charges lists the numbers
409 simaintenance_damage_twiceThe 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_maintenance_charge. Body: note. Answers {"ticket_id": 123, "charge_decided": true, "may_charge": false}.

GET /wc-sibooking/v1/maintenance/charges #

Lists charges. Needs sibooking_maintenance_charge or sibooking_maintenance_costs. 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:

FieldNotes
id, number, ticket_id, order_id, kind, statusorder_id is the rental order; charge_order_id is the order made to collect it
amount, tax, total, refunded, currencyDecimal strings
reason, route, paid_via, paid_at
charge_order_id, pay_urlpay_url is the checkout payment link while the order waits for payment, otherwise null
attempts, next_attempt_at, last_errorCard attempts
created_at
routesOnly while to_review: the ways it can be collected now

Error: 404 simaintenance_not_found.

The charge actions #

All are POST, need sibooking_maintenance_charge, and answer the charge as it is after the action. A charge in the wrong state answers 409 simaintenance_damage_state, and one that is being collected 409 simaintenance_busy. An unknown charge id answers 404 simaintenance_not_found.

EndpointBodyWhat it does
POST /maintenance/charges/{id}/collectroute (required), counter_method, counter_refCollects a charge that is to_review by that route. card charges the saved card
POST /maintenance/charges/{id}/countermethod (default cash), refRecords that the customer paid at the counter
POST /maintenance/charges/{id}/resendnoneSends the pay link again
POST /maintenance/charges/{id}/retrynoneTries a failed card charge again
POST /maintenance/charges/{id}/waivereason (required)Waives the charge. Error 400 simaintenance_damage_reason
POST /maintenance/charges/{id}/refundamount (default: all that is left), reasonRefunds the charge through the payment gateway. Error 400 simaintenance_damage_amount 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_maintenance_view; the cost report also needs sibooking_maintenance_costs. An unknown type answers 404 simaintenance_report.

ParameterNotes
from, toY-m-d. Default: the first day of this month to today. A range over 366 days is cut to the last 366 days
product_idOne product
locationA location (Multi Location Inventory)
kindrepair, 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.

ReportRow fieldsTotals
costOne row per product: product_id, product, part, labour, vendor, other, total, billable, tickets, revenue, pct, and serials (the same per unit)The same sums
downtimeproduct_id, product, serial_id, serial, days, tickets, failures, mttr, rentals, betweendays, tickets, failures, rentals, mttr
utilisationproduct_id, product, stock, stock_days, blocked, blocked_pct, rented, rented_pct, shortageSums for all products
complianceschedule_id, schedule, product_id, product, done, on_time, late, pct, overduedone, on_time, late, overdue, pct
problemsproduct_id, product, problem, tickets, sharetickets; 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/v1/return and POST /wc-sibooking/v1/return/scan, 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_maintenance_manage, otherwise the return is refused with 403 simaintenance_forbidden.

FieldNotes
trueThe whole field can be true: every unit of the return goes to maintenance with the store’s defaults
serialsArray of serial codes. Default: every serial returned. A code that is not part of this return is refused (400 simaintenance_not_returned, with the codes in data.serials)
quantityUnits, for a product without serial numbers. Default: every unit returned. More than returned: 400 simaintenance_quantity
problemUp to 64 characters
noteUp to 5,000 characters
blockKeep the units out of stock until fixed. Default: the store’s Blocking setting. A blocking unit comes back as “In maintenance”
may_chargeThe customer may be charged for the damage. Default false
prioritylow, normal, high or urgent. Default high
photo_idsUp 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:

KeyOnNotes
maintenance_ticketsA return that asked for Needs serviceOne 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_inspectionsA send or a return that answered a checklistThe inspections, each as in GET /maintenance/inspections/{id} plus a ticket field
maintenance_warningsA send of a unit that has a service dueOne 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_service_overdue (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_ticket_created, simaintenance_ticket_status_changed, simaintenance_ticket_closed, simaintenance_ticket_assigned, simaintenance_ticket_written_off, simaintenance_cost_added, simaintenance_schedule_saved, simaintenance_service_done, simaintenance_service_ticket_opened, simaintenance_inspection_recorded, simaintenance_inspection_failed, simaintenance_damage_charge_created, simaintenance_damage_charge_paid, simaintenance_damage_charge_waived and simaintenance_damage_charge_refunded. The settings and emails are in Maintenance settings, emails and developers.