Step 4 — Open the service order
The service order is the workshop sheet: it links equipment, customer, fault, planning and billable lines (parts and services to charge).
Create
POST /gateway/service-order
Content-Type: application/json
Authorization: Bearer {token}
{
"series": 2026,
"status": "RECEB",
"priority": "URG",
"assistanceTypeKeyId": "REP",
"equipmentId": 123,
"entityKeyId": "C0001",
"designation": "Will not power on - suspected PSU",
"breakdownDescription": "Customer reports the device has not powered on since 10/08.",
"deliveryForecast": "2026-08-20T18:00:00Z",
"formatEquipment": false,
"backupEquipment": true,
"details": [
{
"itemKeyId": "SCREEN-7420",
"itemDescription": "Replacement LCD panel",
"quantity": 1,
"retailPrice": 180.00,
"serialNumber": "SN-LCD-0099"
},
{
"itemKeyId": "MO-HORA",
"itemDescription": "Labour per hour",
"quantity": 2,
"netPrice": 20.00
}
]
}
Response: 201 Created with the assigned number.
Required (API validation): status, priority, assistanceTypeKeyId — all three must exist in the catalogues (Steps 1.2 and 1.3) — and series ≥ 1. If SAT configuration has isEmployeeFillObligatory, responsibleUserId (> 0) is also required.
Recommended: equipmentId, entityKeyId, designation, breakdownDescription.
Step 4.1 — Billable lines (details)
details is what gives the document content: each line is a part or service to charge and is what appears on the invoicing preview. Comment lines added by the preview (“Intervention No. 46”, “Hours used”) are grouping headers only, with no value.
If the order has no details and linked interventions have no valued hours or km, preview returns 400 ServiceOrderInvoice.NothingToInvoice (or InterventionInvoice.NothingToInvoice for a standalone intervention). A document that reaches issue with comment lines only is rejected with Invoice.Details.OnlyComments.
The details object is the same on the service order and on the intervention. Per line, send three things — the API fills the rest:
| Field | Who fills it |
|---|---|
itemKeyId | Integrator. Required; the item must exist in the item catalogue |
quantity | Integrator. Must be > 0 |
retailPrice or netPrice | Integrator sends one; the API derives the other from the tax rate |
taxId | Optional. If 0 or omitted, the item tax is used |
taxValue | API (rate for the matching taxId) |
itemGroupId | API (item group) |
guid | API generates it when empty. Resend it on PUT to keep the line |
itemDescription, itemType, serialNumber, imei | Integrator, optional |
invoiced | Read-only: the line is already referenced by an issued document |
Rules and errors:
- Lines with
quantity≤ 0 are silently discarded — no error, they are simply not stored. - Quantity > 0 without
itemKeyId→ 400ServiceOrder.InvalidDetailItemKeyId/Intervention.InvalidDetailItemKeyId. itemKeyIdnot in the item catalogue → 404ServiceOrder.ItemNotFound/Intervention.ItemNotFound.- On PUT (order or intervention),
detailsis a full replacement: current lines are removed and recreated from the submitted list. Resend the ones you want to keep, with theirguid. - On a service order, removing an already invoiced line returns 409
ServiceOrder.CannotRemoveInvoicedDetail.
Traceability on invoicing: each billable line becomes a preview line with originBodyGuid equal to the line guid and the matching relationType — ServiceOrder (4) for lines on the order itself and ServiceOrderIntervention (5) for intervention lines. Hours and km use the intervention GUID as origin, with ServiceOrderInterventionHours (9) and ServiceOrderInterventionKms (8). On a quote, all become ServiceOrderQuote (24).
Useful queries
| Endpoint | Purpose |
|---|---|
GET /service-order?page=1&pageSize=20 | Paginated list |
GET /service-order/{guid} | Detail by GUID |
GET /service-order/{series}/{number} | Detail by series+number (what the customer reads on the ticket) |
GET /service-order/next-number/{series} | Next number in the series |
GET /service-order/{guid}/issued-documents | Documents already issued from this order |
GET /service-order/{guid}/has-invoice | Already invoiced? |
Change status with PUT /service-order/{guid} (status + stateChangeReason when the state requires a reason). State history is recorded automatically.
After creating the order, register interventions. When the work is done, close the order as below.
Close
Close has a preview endpoint — always use it before closing to know what will happen (open interventions, pending quotes).
Preview close (no changes):
GET /gateway/service-order/ORDER-GUID/close-preview
Authorization: Bearer {token}
Close:
POST /gateway/service-order/ORDER-GUID/close
Content-Type: application/json
Authorization: Bearer {token}
{
"reason": "Repair completed and tested",
"concludeOpenInterventions": true
}
concludeOpenInterventions: true is required when open interventions exist — without it, close returns 409 Conflict.
Reopen
POST /service-order/{guid}/reopen (optional body with reason). The change is stored in the state history.
Next
Invoicing (two steps: preview + generic issue).