API

Search the developer hub

Jump to a page or an endpoint.

Orders

Read an organisation's orders, and place new ones priced and scheduled from their catalogue.

An order is what a customer booked: the product, where it goes, when it is delivered and collected, and what it costs. OPS25 turns each order into the jobs drivers carry out; see jobs.

Reading orders

With an API key, GET /api/v1/orders lists the organisation's orders newest first, 25 at a time. Pass the last order's id as startingAfter to get the next page, and stop when hasMore is false. To hear about new and cancelled orders as they happen instead of polling, use webhooks.

Amounts are in cents, including GST. Dates are YYYY-MM-DD in the organisation's timezone.

Creating orders

There are two ways to place an order. Both take the same body, run the same pricing and booking rules, and return the booking reference the customer will quote on the phone.

  • From your server, POST /api/v1/orders with a read and write API key. Use this for an integration: a quoting tool, a CRM, a website form handled on your server.
  • From a browser, POST /api/public/{organisation}/orders on an allowlisted origin. This is the call the booking flow itself makes, and needs no key. A server-side call to it is refused with 403; see authentication.

Before you create one

  • Read the catalogue first. productId, areaId, the add-ons' productIds and deliveryTimePeriodId all have to come from it. Nothing here accepts free text where an id is expected.
  • Send an Idempotency-Key. Bookings are the one thing customers will not forgive you for duplicating.

acceptedTerms must be true, and acceptedNoticeIds must list every booking notice that applies to the product and has mustAccept set. The API will not accept the order otherwise. Notices come back in the catalogue under notices; one applies when its productGroupIds is empty or includes the product's group. The order's record keeps the wording of each notice accepted. Show them. Do not send ids behind a customer who never saw them.

acceptedCollectionNotice is retired: it is still accepted, and ignored.

What comes back

A 201. POST /api/v1/orders returns the whole order, the same object GET returns. The browser call returns a shorter summary: the id, reference, total, dates, status and whether it has been paid. Payment is a separate step handled by the hosted flow — see hosted payments.

Validation failures

A 422 names the offending fields, semicolon-separated:

{ "error": "deliveryDate: Enter a valid date; quantity: Too small: expected number to be >=1" }

Show these to the customer if you like — they are written for a person — but map your own copy onto the field names rather than the message text.

GET/api/v1/orders

The organisation's orders, newest first.

  • Beta — still moving. Changes are announced in the changelog before they ship.
  • Needs an API key. Call it from your server, never a browser.
  • Works with read-only and read and write keys.

Query parameters

NameRequiredDescription
limitNoBetween 1 and 100. Defaults to 25.
startingAfterNoAn order id from the previous page. Returns the orders created before it. Use it while `hasMore` is true.

Headers

NameRequiredDescription
AuthorizationYesYour API key as a bearer token: `Bearer ops25_sk_…`.

Errors

StatusWhen
401The key is missing, malformed or revoked.
429More than 600 requests from this key in a minute.
404`startingAfter` is not an order in this organisation.

GET/api/v1/orders/{id}

One order, by its id.

  • Beta — still moving. Changes are announced in the changelog before they ship.
  • Needs an API key. Call it from your server, never a browser.
  • Works with read-only and read and write keys.

Path parameters

NameDescription
idThe order id, a UUID.

Headers

NameRequiredDescription
AuthorizationYesYour API key as a bearer token: `Bearer ops25_sk_…`.

Errors

StatusWhen
401The key is missing, malformed or revoked.
429More than 600 requests from this key in a minute.
404No order in this organisation has that id.

POST/api/v1/orders

Place an order from your server. Same body, pricing and booking rules as the public booking call. Answer the organisation’s booking questions in `customFields`, by field key. List the booking notices the customer accepted in `acceptedNoticeIds`; every notice that applies to the product and must be accepted is required. The old `placement` field is still accepted and becomes the answer to a question keyed `placement`.

  • Beta — still moving. Changes are announced in the changelog before they ship.
  • Needs an API key. Call it from your server, never a browser.
  • Needs a read and write key. Read-only keys get 403.

Headers

NameRequiredDescription
AuthorizationYesYour API key as a bearer token: `Bearer ops25_sk_…`.
Content-TypeYesMust be `application/json`.
Idempotency-KeyNoRepeat a call safely. The same key returns the original order rather than creating a second one.

Body

Generated from the schema the API validates with, so it cannot describe a body the API would reject.

FieldTypeRequiredNotes
productIduuidYes
areaIduuid | ""NoDefaults to ""
localityobjectNo
locality.suburbstringYes1–120 characters
locality.postcodestringYes
linesobject[]Noup to 20 items
lines[].discountPercentintegerNo0–100. Defaults to 0
lines[].descriptionstringNo1–500 characters
lines[].lineType"hire" | "sale"No
lines[].workType"none" | "delivery" | "service"No
lines[].purchaseOrderstringNoup to 100 characters
lines[].equipmentReferencestringNoup to 120 characters
lines[].deliveryOnstringNo
lines[].collectionOnstring | nullNo
lines[].productIduuidYes
lines[].quantitynumberYes0.01–1000
lines[].deliveryDatestringYes
lines[].pickupDatestringYes
lines[].waitWhileLoadbooleanNoDefaults to false
lines[].scheduleobject | nullNo
purchaseOrderstringNoup to 100 characters
salespersonstringNoup to 120 characters
customerType"individual" | "company"Yes
customerNamestringYes2–120 characters
contactNamestringYes2–120 characters
emailemailYesup to 200 characters
phonestringYes8–30 characters
addressstringYes5–250 characters
lotNumberstringNoup to 40 characters
gateCodestringNoup to 80 characters
placementstringNoup to 80 characters
notesstringNoup to 2000 characters. Defaults to ""
customFieldsobjectNo
addOnsobject[]Noup to 50 items. Defaults to []
addOns[].productIduuidYes
addOns[].quantityintegerYes1–100
quantityintegerYes1–1000
deliveryDatestringYes
deliveryTimePeriodIdstring | nullNoDefaults to null
pickupDatestringYes
waitWhileLoadbooleanNoDefaults to false
acceptedTermstrueYes
acceptedNoticeIdsuuid[]Noup to 50 items. Defaults to []
acceptedCollectionNoticebooleanNo

Errors

StatusWhen
401The key is missing, malformed or revoked.
429More than 600 requests from this key in a minute.
402The organisation's subscription is inactive.
403The key is read-only.
422The body failed validation. The message names the offending fields.

POST/api/public/{organisation}/orders

Place a booking against an organisation, priced and scheduled from their catalogue.

  • Beta — still moving. Changes are announced in the changelog before they ship.
  • Browser only — the API requires an allowlisted Origin header.

Path parameters

NameDescription
organisationThe organisation's booking slug.

Headers

NameRequiredDescription
Content-TypeYesMust be `application/json`.
Idempotency-KeyNoRepeat a call safely. The same key against the same organisation returns the original order rather than creating a second one.
OriginYesMust be an allowlisted origin. The API rejects writes from unrecognised origins, which is why this endpoint cannot yet be called from a server.

Body

Generated from the schema the API validates with, so it cannot describe a body the API would reject.

FieldTypeRequiredNotes
productIduuidYes
areaIduuid | ""NoDefaults to ""
localityobjectNo
locality.suburbstringYes1–120 characters
locality.postcodestringYes
linesobject[]Noup to 20 items
lines[].discountPercentintegerNo0–100. Defaults to 0
lines[].descriptionstringNo1–500 characters
lines[].lineType"hire" | "sale"No
lines[].workType"none" | "delivery" | "service"No
lines[].purchaseOrderstringNoup to 100 characters
lines[].equipmentReferencestringNoup to 120 characters
lines[].deliveryOnstringNo
lines[].collectionOnstring | nullNo
lines[].productIduuidYes
lines[].quantitynumberYes0.01–1000
lines[].deliveryDatestringYes
lines[].pickupDatestringYes
lines[].waitWhileLoadbooleanNoDefaults to false
lines[].scheduleobject | nullNo
purchaseOrderstringNoup to 100 characters
salespersonstringNoup to 120 characters
customerType"individual" | "company"Yes
customerNamestringYes2–120 characters
contactNamestringYes2–120 characters
emailemailYesup to 200 characters
phonestringYes8–30 characters
addressstringYes5–250 characters
lotNumberstringNoup to 40 characters
gateCodestringNoup to 80 characters
placementstringNoup to 80 characters
notesstringNoup to 2000 characters. Defaults to ""
customFieldsobjectNo
addOnsobject[]Noup to 50 items. Defaults to []
addOns[].productIduuidYes
addOns[].quantityintegerYes1–100
quantityintegerYes1–1000
deliveryDatestringYes
deliveryTimePeriodIdstring | nullNoDefaults to null
pickupDatestringYes
waitWhileLoadbooleanNoDefaults to false
acceptedTermstrueYes
acceptedNoticeIdsuuid[]Noup to 50 items. Defaults to []
acceptedCollectionNoticebooleanNo

Errors

StatusWhen
402The organisation's subscription is inactive, so online booking is closed.
403The request came from an origin that is not allowlisted.
404No organisation has that slug.
422The body failed validation. The message names the offending fields.