/v1/supplier/work_order/ for receiving jobs, responding to them, and keeping buyers informed while the work progresses. Scheduling visits and completing work happen through service calls.
All examples assume:
Reading your queue
The pattern that scales is push, then fetch by id:offset, limit default 10 max 25, sort_by, order), and any other query parameter acts as a field filter. Everything is tenant-scoped to your facility.
The list and count resolve which work orders match in OpenWrench’s search index, then load the full records from the database. The count endpoint runs the same query as the list, so the two always agree. Behavior to know:
- Full-text search.
search=matches words (with prefix and stem matching) across the title, description, location name, notes, service call check-in and check-out notes, and problem type name. It also matches reference numbers such as the work order number, PO number, and asset serial number. Wrap the value in double quotes to require the exact phrase. - Asset filters include sub-assets.
assetId=andassetIds=match work orders whose main asset or any sub-asset is the given id. - Sorting.
sort_bysupportscreatedAt,locationName,woPriority(by the priority’s expected resolution time), andlastServiceCallServiceScheduledAt. Any other value, or nosort_by, sorts bycreatedAtdescending. - Unindexed filters are ignored.
updatedAtStartDate,updatedAtEndDate,buyerFacilityId, andwalkthroughIdare not in the search index and no longer narrow the results. Filter on astatusChangedAtwindow or other indexed columns instead. - Freshness. Search index and replica updates lag writes by a moment. Your own just-written change, or a work order assigned seconds ago, can be briefly absent from list results and counts.
- Pagination depth.
offset + limitcannot exceed the search result window of 10,000. Narrow the filter rather than paging that deep. - Data masking. If you are a third-party supplier (not a buyer’s internal service team), buyer-private fields are blanked on work orders, locations, and invoices before the response returns. Missing fields are usually masking, not bugs. See Reference data for details.
Accept or decline
Accept withPOST /v1/supplier/work_order/work_orders/status_update/confirm, which sets the status to ConfirmedByServiceProvider. A work order already in a completed or closed display status cannot be accepted (400).
POST .../status_update/decline. Only contacts of the work order’s assigned supplier facility may decline. The work order leaves your queue through the supplier-change flow: its status returns to PendingApproval, or a private-network supplier is auto-picked, depending on the buyer’s configuration. The note’s text is recorded as the decline reason and reflected in what the buyer sees, so make it specific.
Both calls take { "id": ..., "note": { ... } } and return the updated work order.
Keep the buyer informed
Three lightweight signals while the job is in flight: Parts tracking. Three status endpoints, same{ id, note } body shape as above:
Estimated completion date.
PATCH /v1/supplier/work_order/work_orders/{id}/estimated_completion_date reads only estimatedCompletionDate (ISO 8601) from the body:
PATCH /v1/supplier/work_order/work_orders/{id}/append_supplier_attachments appends file references to supplierAttachments, preserving what is already there. Upload the file first (see Files and users), then:
Notes
Append to the shared buyer–supplier thread withPATCH /v1/supplier/work_order/work_orders/append_notes ({ "id": ..., "note": { "text", "noteAddedBy", "noteAddedAt" } }), and read a work order’s thread with GET /v1/supplier/work_order/work_order_notes/{woId}. Reading updates read receipts for your contact, and a denied read returns an empty list rather than an error.
To @mention people on the note, add taggedUsers beside the note: a list of contact email addresses. OpenWrench folds each email into note.elements as a user element, the same shape the apps write for an @mention, so you don’t need to build the elements structure yourself. Tagged contacts are added to the work order’s subscriber list if they aren’t subscribed already.
taggedUsers:
- Emails are trimmed and lowercased before matching. A note can mention at most 25 users.
- Duplicate emails in the list, and users already tagged in
note.elements, are skipped rather than mentioned twice. - An entry that is not a valid email address, or a list of more than 25 emails, is rejected with a
400of typeinvalidInputDataException. Nothing is persisted. - An empty list is ignored. Sending
taggedUserswithout anoteobject is rejected with400.
PATCH /v1/supplier/work_order/work_orders/append_notes/bulk with { "id": ..., "notes": [ ... ] }. Each note must carry a photo URL and no other content: text must be empty and video, audio, otherFile, and elements must be absent. A request takes 1–25 notes, duplicate photo URLs are rejected with 400, and the batch keeps its order under one server-set noteAddedAt. Subscribers receive a single grouped notification instead of one notification per photo.
Labels
Work order labels are lightweight tags (a name plus an optional color) used to slice the queue. Through the API you can read the label catalog and replace the labels applied to a work order. Creating or editing the labels themselves stays in the OpenWrench app. Which catalog you see depends on your key: a key belonging to a buyer’s internal service team sees that buyer company’s catalog, and a third-party supplier’s key sees its own facility’s catalog. Browse the catalog withGET /v1/supplier/work_order/work_order_labels, or fetch one with GET /v1/supplier/work_order/work_order_labels/{id}. The list is paginated 10 per page by default and accepts search and label filters on the label text. Pass no_pagination=true to pull the whole catalog in one call.
Replace a work order’s labels with PUT /v1/supplier/work_order/work_orders/{woId}/labels. The body is { "ids": [...] } and it is a full replacement: labels not listed are removed, and an empty array clears them all. The response lists the label mappings now active on the work order.
- Every id must be a live label from your own catalog; a missing or non-array
ids, a non-integer id, and unknown or cross-tenant ids are all rejected with400. - The write requires work order write permission: a key that can only see the work order (a bidder, or a facility with read-only visibility) gets
400. On an unassigned work order, only a facility with read-write visibility may label it. - An unknown, deleted, or foreign work order id answers the same
400as a denied write, not a404.
Create a supplier-initiated work order
Suppliers can open work orders themselves (a tech spots a broken door while on site for something else).POST /v1/supplier/work_order/work_orders requires title and locationId; the location determines the buyer facility and company.
problemTypeId falls back to the first leaf problem type of the location’s buyer company, and woPriorityId to a default priority for that company. An assetId, if given, must exist, and its area is inherited when areaId is not set. The field is needApproval (no “s”) on this create body. An id in the body is ignored: this call always creates a new work order.
The server sets the initial status. For a third-party supplier key, any status or isSupplierInitiated in the body is ignored. The server creates the work order as SupplierInitiatedPendingApproval with isSupplierInitiated: true. The buyer’s approval configuration then decides where it lands: it stays in SupplierInitiatedPendingApproval until a buyer approves it, or, when the buyer auto-approves supplier-initiated work orders, it is confirmed to your facility straight away as ConfirmedByServiceProvider. Keys that belong to a buyer’s internal service team, and paying suppliers creating a work order at a location of a client they manage, keep the status they send. When these keys omit status, the initial status is derived from the buyer company’s configuration; an internal team lands in AssignedToInternalTech.
Problem types
GET /v1/supplier/work_order/problem_types lists problem types across your related buyer companies (not rate limited). Use it to classify supplier-initiated work orders correctly per buyer.
Typical integration loop
- Register a webhook endpoint for
workorder.createandworkorder.status_update. On each delivery, fetch the work order by id. Do the one-time initial load from the list endpoint, and keep it out of the steady-state loop except as an infrequent, narrowly filtered safety-net poll. confirmordeclinewithin your SLA.- Schedule the visit via service calls; post parts statuses and an ECD as things develop.
- Complete via check-out, then bill via quotes and invoicing.