Skip to main content

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.

warning

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:

FieldWho fills it
itemKeyIdIntegrator. Required; the item must exist in the item catalogue
quantityIntegrator. Must be > 0
retailPrice or netPriceIntegrator sends one; the API derives the other from the tax rate
taxIdOptional. If 0 or omitted, the item tax is used
taxValueAPI (rate for the matching taxId)
itemGroupIdAPI (item group)
guidAPI generates it when empty. Resend it on PUT to keep the line
itemDescription, itemType, serialNumber, imeiIntegrator, optional
invoicedRead-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 → 400 ServiceOrder.InvalidDetailItemKeyId / Intervention.InvalidDetailItemKeyId.
  • itemKeyId not in the item catalogue → 404 ServiceOrder.ItemNotFound / Intervention.ItemNotFound.
  • On PUT (order or intervention), details is a full replacement: current lines are removed and recreated from the submitted list. Resend the ones you want to keep, with their guid.
  • 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 relationTypeServiceOrder (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

EndpointPurpose
GET /service-order?page=1&pageSize=20Paginated 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-documentsDocuments already issued from this order
GET /service-order/{guid}/has-invoiceAlready invoiced?
Status change

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