> For the complete documentation index, see [llms.txt](https://docs.flowretail.com/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.flowretail.com/docs/developers/api-documentation/service/search-for-service-orders.md).

# Search for service-orders

Search for service orders is case insensitive and you can use partial values, e.g. name 'Anna' will return both 'Anna' and 'Johanna'. Use the query to search for customer, service number or title from only one field. When this is used, the customer and service search fields are ignored. The array fields work like filters. This search is scoped to the store in the path. A storeUids in the body narrows within that scope rather than widening it: naming a store the path store does not cover matches nothing. To search across every service order of the tenant, use the tenant-level service order search instead. What the results leave out: secrets and checklistAnswers are always empty arrays, and formValues leaves out the values captured for sensitive fields. Read the one service order to see them: the checklist answers at any store of the tenant, the secrets and the sensitive values at the store that owns it or the store it was taken in at. Sensitive values take no part in the matching either, so a sensitive serial can be neither read out of a result nor probed for here. This list is the store's own work: it holds the service orders the store owns, and not the ones it took in and has since sent on. Those are found on the tenant-level service order search, which reaches both. To see what this store took in, use the tenant-level service order search with createdFromStoreUids naming this store — everything it registered, wherever it sits now — and add storeUids naming another store to leave only what it sent there. A saved list holding those filters keeps it as a list of its own, separate from the work the store is handling.

Required permissions: SERVICE\_ORDER

```json
{"openapi":"3.0.2","info":{"title":"Flow Retail API version 2","version":"2.0.0"},"tags":[{"name":"Service","description":"Service"}],"servers":[{"description":"Flow Retail Production","url":"https://api.flowretail.com/v2"},{"description":"Flow Retail Stage","url":"https://api.stage.flowretail.com/v2"}],"security":[{"accessToken":[]},{"authToken":[]},{"integrationToken":[]}],"components":{"securitySchemes":{"accessToken":{"description":"Access token recevied after user login with a deviceToken","scheme":"bearer","type":"http"},"authToken":{"description":"Token received from the auth service","scheme":"bearer","type":"http"},"integrationToken":{"scheme":"bearer","type":"http"}},"responses":{"ServiceOrderListResponse":{"description":"Example response","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ServiceOrderResponseSchema"}},"paging":{"$ref":"#/components/schemas/Paging"}},"required":["items","paging"]}}}}},"schemas":{"ServiceOrderResponseSchema":{"title":"ServiceOrderResponseSchema","description":"A service order as staff read it, with everything on the case: what came in, who is on it, what it will cost, the intake form values, the secrets by label, the job types the work consists of and the answers given on their checklists.\nHow much of that is returned depends on where the service order is read from. This full representation is what the single service order endpoint returns, secret labels and sensitive form values included, at the store that owns the service order and at the store it was taken in at. Read at any other store of the tenant, two things are held back: secrets is an empty array, and formValues leaves out the values captured for sensitive fields. In the results of a service order search or of the store's service order list, three things are held back: secrets and checklistAnswers are always empty arrays, and formValues leaves out the values captured for sensitive fields. Read the one service order to see them: the checklist answers at any store of the tenant, the secrets and the sensitive values at the store that owns it or the store it was taken in at. It is a staff representation throughout, and the two customer-facing surfaces do not use it at all: the service portal has PortalServiceOrderResponseSchema and the customer data export has CustomerExportServiceOrderSchema, each assembled from customer-visible data of its own.","type":"object","required":["serviceOrderUid","tenantUid","storeUid","orderProductLineUid","orderUid","customerUid","customerName","createdFromStoreUid","assignedUserUid","assignedUserDisplayName","serviceTypeUid","serviceTypeName","serviceStatusUid","serviceStatusName","serviceState","title","serviceNumber","externalServiceNumber","externalSalesOrderNumber","description","priority","estimatedPrice","maxPrice","readyAtEstimate","createdAt","createdBy","lastModifiedAt","lastModifiedBy","totals","items","assets","rmaOrderItemUid","rmaOrderUid","formValues","intakeFormUid","secrets","serviceJobTypes","checklistAnswers","quotedPrice","quoteState","termsText","termsUrl","termsAccepted","coverage","productUid","insuranceCompanyCustomerUid","deductible","claimNumber"],"properties":{"serviceOrderUid":{"$ref":"#/components/schemas/UID"},"tenantUid":{"$ref":"#/components/schemas/UID"},"storeUid":{"description":"The store that owns the service order — the store the work sits with and where the customer collects it. It changes only through the move mechanism — the move endpoint, or the receipt of a shipment item at another store — which writes a MOVED event when it does.","type":"string","pattern":"^[A-Za-z0-9-_]+"},"orderProductLineUid":{"description":"The line of the sales order the unit was bought on, which is what ties the case to the purchase behind it. An empty string when the case names no sale.\nIt is set when the service order is registered and changed or cleared afterwards through the update. A case that names a line is what makes the sales order list it under the relation SOLD_ITEM.","allOf":[{"$ref":"#/components/schemas/OptionalUID"}]},"orderUid":{"description":"The sales order the linked line belongs to. An empty string when the case names no sale.\nIt is derived from orderProductLineUid and never sent by a client: there is no order field on the create or the update, and clearing the line clears this with it, so the two always name the same sale.","allOf":[{"$ref":"#/components/schemas/OptionalUID"}]},"customerUid":{"$ref":"#/components/schemas/OptionalUID"},"customerName":{"type":"string"},"createdFromStoreUid":{"description":"The store the service order was taken in at. It is set when the service order is registered and never changes afterwards, so it keeps recording where the unit was handed in however far the case travels. storeUid is the store that owns the service order now — where the work sits and where the customer collects it — so the two differ for the rest of the case once a service order has been moved between stores.","type":"string","pattern":"^[A-Za-z0-9-_]+"},"assignedUserUid":{"description":"The user who is to do the work on this service order. An empty string means no personal assignee: the service order is held by the store that owns it, and its notifications go to that store's service staff rather than to one person, so nothing is left waiting on somebody who is not looking at it.\nAssigning and unassigning happen on the service order's assign endpoint, which writes an ASSIGNED event either way. A move to another store also ends the assignment: the service order arrives at the receiving store unassigned, recorded on the MOVED event.","type":"string","pattern":"^[A-Za-z0-9-_]*"},"assignedUserDisplayName":{"type":"string"},"serviceTypeUid":{"$ref":"#/components/schemas/UID"},"serviceTypeName":{"type":"string"},"serviceStatusUid":{"$ref":"#/components/schemas/UID"},"serviceStatusName":{"type":"string"},"serviceState":{"$ref":"#/components/schemas/ServiceStateENUM"},"title":{"type":"string"},"serviceNumber":{"type":"string"},"externalServiceNumber":{"type":"string","description":"The number an outside workshop or supplier handling the work gives the case in its own system, such as the supplier's case number. It is never serviceNumber, and never the number of a sale: the sales order the unit was bought on is externalSalesOrderNumber."},"externalSalesOrderNumber":{"type":"string","description":"The order number of the sales order the unit in for service was bought on, in the tenant's external order system such as Omnium. It is the sale's number, never serviceNumber and never externalServiceNumber, and it is text alone: the sale itself is looked up in the external system. An empty string when the service order names no external sale."},"description":{"type":"string"},"locationLabel":{"type":"string","deprecated":true,"description":"Deprecated. Superseded by the intake form field of system kind LOCATION_LABEL: where the device is stored while it is in the workshop is captured as a form value, and is read from formValues. Until removal it is served as a derived read-only alias of the value captured for that field, and it is an empty string when no value is captured for it. It will be removed after the announced deprecation window; see the deprecation log for the date."},"priority":{"description":"How urgent the work is. An intake form field of system kind PRIORITY writes here rather than into the form values. NONE is no priority.","allOf":[{"$ref":"#/components/schemas/PriorityENUM"}]},"requiresPriceEstimate":{"type":"boolean","deprecated":true,"description":"Deprecated. Asking the customer what the work will cost before it is started is the quote: quotedPrice is the offer that was made and quoteState is how the customer answered it, both written through the quote endpoints, which record the offer and the answer rather than a flag saying one is owed. During the deprecation window it is served from the stored value on service orders registered before the change, and is false on every service order registered after it; it is no longer in the required set. It will be removed after the announced deprecation window; see the deprecation log for the date."},"estimatedPrice":{"type":"integer","description":"What the work is estimated to cost. It is captured at intake when the intake form places a field of system kind ESTIMATED_PRICE, which writes here rather than into the form values. It is 0 when no estimate has been captured."},"maxPrice":{"type":"integer","description":"The ceiling the customer allows the work to be done up to without being asked again. It is captured at intake when the intake form places a field of system kind MAX_PRICE, which writes here rather than into the form values. It is 0 when no ceiling has been captured."},"readyAtEstimate":{"type":"string","format":"date-time","nullable":true,"description":"When the service order is estimated to be finished. null when no date has been given.\nThe value is read on the clock in the tenant's timezone. A value that reads 23:59:59 there, whatever its milliseconds, means ready by the end of that day with no time picked, and is shown as the day and \"end of day\". Any other value is a picked time and is shown as the day and that time. Clients send a picked time in whole minutes, so its seconds read :00, and a picked 00:00 or 23:59 is never mistaken for the end of the day.\nA writer with no picked time sends 23:59:59 on the chosen day in the tenant's timezone, which is the value the service type's per-store turnaround response prefills.\nThe tenant's timezone is the tenant's zone name — timezone on the tenant, in tz/zoneinfo format such as Europe/Oslo, which the service portal page carries as timeZone — and never a fixed offset, so a day the clocks change on reads right. The zone is Europe/Oslo when the tenant has none set. No store carries a zone of its own.\nThe texts core writes follow the same rule: the .readyDate variable in SMS and e-mail texts, the service papers that print the expected ready time, the intake slip and the note of a FIELD_CHANGE entry for readyAtEstimate give the day and the time, or the day and \"end of day\", in the language the text is written in."},"readyAtNeeded":{"type":"string","format":"date-time","nullable":true,"deprecated":true,"description":"Deprecated. The service module follows one date, readyAtEstimate; a deadline the workshop cannot control is not tracked. During the deprecation window it is served from the stored value on service orders registered before the change, and is null on every service order registered after it; it is no longer in the required set. It will be removed after the announced deprecation window; see the deprecation log for the date."},"publicPageHash":{"type":"string","deprecated":true,"description":"Deprecated. Staff surfaces never need the customer's link: sending it, sending it again and replacing it all happen server-side, through the send endpoint and the portal token endpoint, and signing at the counter has its own signing session that reaches the terms of that one service order and nothing else. Handing the customer's portal credential to every staff client is what made it leak, and there is no longer a reason to.\nIt is served as an empty string for the whole deprecation window, and is no longer in the required set: the field stays in the response so a client that requires a string still parses, and it carries nothing. There is no value to read here — a service order's portal link reaches the customer by being sent, and by nothing else. It will be removed after the announced deprecation window; see the deprecation log for the date."},"warranty":{"type":"boolean","deprecated":true,"description":"Deprecated. Superseded by coverage, which classifies who pays for the work and under what right: warranty true is the coverage WARRANTY_CLAIM. Until removal it is served as a derived read-only alias — computed from the coverage on every read, true when the coverage is WARRANTY_CLAIM and false otherwise. It is read-only in the strict sense: the service order's write side carries no warranty at all, and the coverage is set through coverage alone. A warranty property sent on a create or an update is not a value the request carries — it changes nothing and is not refused — so a client that reads a service order and writes the body back unaltered sets no coverage by doing it. It will be removed after the announced deprecation window; see the deprecation log for the date."},"createdAt":{"type":"string","format":"date-time"},"createdBy":{"type":"string"},"lastModifiedAt":{"type":"string","format":"date-time"},"lastModifiedBy":{"type":"string"},"totals":{"$ref":"#/components/schemas/ServiceOrderTotalsSchema"},"items":{"type":"array","items":{"$ref":"#/components/schemas/ServiceOrderItemResponseSchema"}},"assets":{"type":"array","items":{"$ref":"#/components/schemas/ServiceOrderAssetResponse"}},"rmaOrderItemUid":{"$ref":"#/components/schemas/OptionalUID"},"rmaOrderUid":{"$ref":"#/components/schemas/OptionalUID"},"formValues":{"type":"array","description":"The values captured on the intake form the service order was created from, each with the field information as it was at capture time. Empty when no values were captured. An answer stays listed when a later edit of the form hides its placement or takes the field off the form, so a client that renders the form judges visibleWhen itself. Read at a store that neither owns the service order nor took it in, the values captured for sensitive fields are left out.\nA SECRET field never has a form value: what was captured for it is a secret, listed under secrets. A sensitive value that was removed because the service order reached a terminal state is still listed, with redacted true and an empty value — the question stays on the record, the answer does not.","items":{"$ref":"#/components/schemas/ServiceOrderFormValueResponseSchema"}},"intakeFormUid":{"description":"The intake form the service order was created from. It names the form rather than copying it: archiving the form afterwards leaves this uid as it is, and an edit of the form applies to the service orders created from it as well. Form values are checked against this form as it reads at the moment of the write, and an update is checked only for what it changes (formValues on the update), so a question an edit adds or makes required is asked of an existing service order only when an update clears it or sends an answer that turns it from hidden to shown.\nAn empty string when the service order was created without an intake form.","type":"string","pattern":"^[A-Za-z0-9-_]*"},"secrets":{"type":"array","description":"The secrets kept on the service order, such as a device passcode, by label. Empty when the service order has no secrets.\nThe values are never returned here — read one through the secrets reveal endpoint. Every secret is deleted when the service order reaches a terminal state, so this list is empty on a finished service order. It is empty too when the service order is read at a store that neither owns it nor took it in.","items":{"$ref":"#/components/schemas/ServiceOrderSecretResponseSchema"}},"serviceJobTypes":{"type":"array","description":"The job types the work on this service order consists of, usually one, with their names embedded so the service order can be shown without looking them up. Empty when no job type has been set.\nEach job type carries the checklist run before handover and the products suggested when the work is priced — read those through the job types endpoint.","items":{"$ref":"#/components/schemas/ServiceJobTypeRefSchema"}},"checklistAnswers":{"type":"array","description":"The answers given on the checklists of the job types the service order carries, one entry per answered item, for the items on those checklists as they read now. An item with no answer has no entry: a cleared answer is simply absent. Answers are given one at a time during the work through put-serviceorders-checklist-answers, and the results post-serviceorders-checklist sends are stored as answers too.\nAn answer belongs to the item's text, so an item renamed on the job type reads as unanswered. Answers on a job type taken off the service order are kept but not listed, and are listed again, with who gave them and when, if the job type is put back.\nIt is staff data and internal: it is never on the service portal page, the service papers, the customer data export or a webhook payload, so staff names never reach a customer. Every response that carries one service order carries it, at any store of the tenant — the single read, the read by number, and every write that returns the service order, put-serviceorders-checklist-answers included; in a list of service orders — a search or the store's service order list — it is an empty array.","items":{"$ref":"#/components/schemas/ServiceOrderChecklistAnswerSchema"}},"quotedPrice":{"type":"integer","nullable":true,"description":"The amount of the latest quote on the service order, in the same unit as estimatedPrice and maxPrice. Where that offer stands is quoteState's job rather than this field's: null here means nothing has ever been offered.\nIt is set only through the service order's quote endpoint, never through an ordinary update, so that offering a price always leaves a QUOTE_SENT event with the amount snapshotted. The customer's answer does not clear it: the amount stays as it is after a decision, approved or declined, until a new quote replaces it. estimatedPrice and maxPrice are separate figures and are not touched by quoting."},"quoteState":{"description":"Where the latest quote stands: NONE until a price has been offered, SENT while an offer is waiting for an answer, and APPROVED or DECLINED once the customer has given one, wherever they gave it.\nIt moves only through the quote endpoints, and it is what the answer is judged against — a decision is refused unless it is SENT, so after an answer a new quote has to be sent before another one can be recorded. It is the same state the service portal shows the customer.","allOf":[{"$ref":"#/components/schemas/ServiceOrderQuoteStateENUM"}]},"termsText":{"type":"string","description":"The terms and conditions that apply to this service order, in the terms format that termsText in the service settings describes: the tenant's terms followed by the additional terms of the service order's service type, the two separated by a blank line, each as it read when the service order was created. Editing the tenant's terms or the type's additional terms afterwards never changes it — a service order keeps the wording that was in force when it was taken in, so the printed confirmation says the same thing years later.\nChanging serviceTypeUid while no standing acceptance exists on the service order replaces the type's part with the new type's additional terms as in force at the change; once an acceptance exists, the text is frozen. An empty string when neither the tenant nor the type had any terms when the service order was created — service orders migrated from the old service system and orders created before any terms were saved among them — then, unless termsUrl is set, nothing is shown to the customer, no acceptance can be recorded, and termsAccepted is true."},"termsUrl":{"type":"string","description":"Where the tenant publishes their terms, as the URL that was in force when the service order was created — for tenants who keep the wording on their own website. Shown to the customer alongside termsText and printed on the service confirmation and the intake slip. An empty string when the tenant had no URL then. It counts as terms: a service order with a URL and no text has terms to accept."},"termsAccepted":{"type":"boolean","description":"Whether the terms that apply to this service order have been accepted. It is derived, never written: true when a standing acceptance exists on the service order, whichever way it was given — in the service portal, signed on a counter device, or given in the store and recorded by staff — and true when the service order has no terms at all, termsText and termsUrl both empty, because then nothing is asked. An acceptance that has been voided satisfies nothing, so voiding the one that stood puts this back to false.\nIt says whether the terms have been accepted, not whether acceptance is required: the tenant setting termsAcceptanceRequired decides whether a status change may move an unaccepted service order into IN_PROGRESS. Read the acceptance itself, with the terms as they read when accepted and the drawn signature where there is one, through the service order's terms acceptances endpoint."},"coverage":{"description":"Who pays for the work on this service order, and under what right. It is chosen at intake and can change while the case runs: a diagnosis may reclassify it — water damage voiding a warranty makes the case payable — which is an ordinary logged field edit and leaves a FIELD_CHANGE event on the timeline.\nIt replaces the deprecated warranty flag: the coverage WARRANTY_CLAIM is what warranty true used to mean.","allOf":[{"$ref":"#/components/schemas/ServiceOrderCoverageENUM"}]},"productUid":{"description":"The product the unit in for service is — the model of the machine on the bench, so the case can be found by what came in and the serial can be read against the right product. It is captured at intake when the intake form places a field of system kind PRODUCT, which writes here rather than into the form values.\nThis is not one of the products on the service order's items: those are the parts and the work that go on the bill. An empty string when the unit was not identified as a catalogue product.","type":"string","pattern":"^[A-Za-z0-9-_]*"},"insuranceCompanyCustomerUid":{"description":"The insurance company the claim is made to, as a customer record of its own. It is recorded for information: the sale is billed to the service order's customer whatever the coverage (see post-serviceorders-orders).\nSet it when the coverage is INSURANCE_CLAIM; an empty string otherwise. The number the insurer gave the claim is claimNumber.","type":"string","pattern":"^[A-Za-z0-9-_]*"},"deductible":{"type":"integer","description":"The deductible on an insurance claim, VAT included, in the same unit as estimatedPrice and maxPrice, recorded for information and printed on the service papers; it does not change how the case is billed. It is 0 when there is none, and it is above 0 only on the coverage INSURANCE_CLAIM."},"claimNumber":{"type":"string","description":"The number the insurer gave the claim, which the insurer matches the bill and the damage report to. It is entered beside the insurer and the deductible and is not an intake form field. An empty string when none was entered, and it is non-empty only on the coverage INSURANCE_CLAIM."}}},"UID":{"title":"UID","type":"string","pattern":"^[A-Za-z0-9-_]+"},"OptionalUID":{"title":"OptionalUID","type":"string","pattern":"^[A-Za-z0-9-_]*"},"ServiceStateENUM":{"title":"ServiceStateENUM","description":"Where a service order stands, as the platform understands it. Every status a tenant defines maps to exactly one state, and it is the state Flow reasons about: the workspace filters, the wording the portal shows the customer and the turnaround figures all follow the state rather than the name the status was given.\nAWAITING_PRODUCT: the service order is registered, but the device has not arrived yet.\nNOT_STARTED: the device is here and the work is queued.\nIN_TRANSIT: the service order is in a box on its way between locations.\nIN_PROGRESS: the work is being done.\nWAITING_CUSTOMER: waiting for an answer from the customer — never for the device, which is what AWAITING_PRODUCT is for.\nWAITING_SUPPLIER: waiting for parts or for an answer from a supplier.\nREADY_FOR_PICKUP: the outcome is ready to be handed over.\nCOMPLETE: the customer has the device back. This is the handover, never the payment.\nCANCELLED: the service order ended without a completed repair.\nCOMPLETE and CANCELLED are the terminal states.\nThe states are owned by the platform: tenants never define or rename them, and only decide which state each of their own statuses maps to. A status that exists today keeps the state it has until the tenant remaps it — nothing is remapped for them.\nExtensible — new states may be added, so clients must not fail on a value they do not know.","type":"string","enum":["AWAITING_PRODUCT","NOT_STARTED","IN_TRANSIT","IN_PROGRESS","WAITING_CUSTOMER","WAITING_SUPPLIER","READY_FOR_PICKUP","COMPLETE","CANCELLED"]},"PriorityENUM":{"title":"PriorityENUM","description":"HIGHEST, HIGH and LOW rank the work; NONE is no priority, which a service order carries when none was given.","type":"string","enum":["HIGHEST","HIGH","LOW","NONE"]},"ServiceOrderTotalsSchema":{"title":"ServiceOrderTotalsSchema","description":"What the case comes to, split by whether the line was taken from tracked stock. Every figure is derived from the service order items on the case; there is no separate work registration behind any of them. All figures are in minor units of the tenant's currency: 150 is 1,50.","type":"object","required":["goodsTotal","grandTotal","otherTotal"],"properties":{"goodsTotal":{"type":"integer","description":"The lines whose product is of type STOCK — tracked in stock, what was taken from a warehouse for the work."},"grandTotal":{"type":"integer","description":"goodsTotal and otherTotal added together — what the case comes to."},"otherTotal":{"type":"integer","description":"Everything else billed on the case: labour, and any goods the tenant does not track in stock. The split is drawn on whether the product is tracked in stock, never on whether a person would call the line work — a SIM card the tenant does not keep stock of is counted here and not in goodsTotal, and an hour of labour is counted here because the product it is billed on is not stocked either. Neither figure is a statement about parts against labour, and nothing on a service order item records which of the two a line is."},"partsTotal":{"type":"integer","deprecated":true,"description":"Deprecated. Superseded by goodsTotal, and served as goodsTotal's value until removal. The meaning has changed with the name: it previously covered every line on the case, including the lines now counted in otherTotal. It will be removed after the announced deprecation window; see the deprecation log for the date."},"workTotal":{"type":"integer","deprecated":true,"description":"Deprecated. Superseded by otherTotal, and served as otherTotal's value until removal. The meaning has changed with the name: it was previously computed from the hours registered against the case, and hours registration is retired — work is an ordinary service order item like any other line. It will be removed after the announced deprecation window; see the deprecation log for the date."}}},"ServiceOrderItemResponseSchema":{"title":"ServiceOrderItemResponseSchema","type":"object","required":["serviceOrderItemUid","serviceOrderUid","warehouseUid","warehouseName","tenantUserUid","productUid","salesOrderUid","quantity","name","sku","coverImage","priceOverride","price","costPrice","originalPrice","discountReasonCode","discountReference","totalPrice","totalCostPrice","serialNumber","removedSerialNumber","note","orderItemReferenceValue","tenantUserDisplayName","createdAt","createdBy","lastModifiedAt","lastModifiedBy"],"properties":{"serviceOrderItemUid":{"$ref":"#/components/schemas/UID"},"serviceOrderUid":{"$ref":"#/components/schemas/UID"},"warehouseUid":{"type":"string","pattern":"^[A-Za-z0-9_-]*$","description":"The warehouse the line is booked against, fixed when the line was added. On a stock-tracked line it is where the units were taken out of, as the server resolved it — what the request named, else the store's serviceDefaultWarehouseUid service setting, else the store's own defaultWarehouseUid when the store owns that warehouse. A line for a product that is not stock-tracked carries one only when the request named it, and no stock moved. Empty when the line was added without one and needed none, or when the warehouse it carried has since been deleted. It cannot be changed afterwards, so it is read-only wherever an existing line is shown."},"warehouseName":{"type":"string","description":"The name of the warehouse the line is booked against, as it stands now — served beside warehouseUid so a line can be labelled without a second call, the way the sales order line carries it. Empty exactly when warehouseUid is empty. A store reading a case it does not own sees lines booked against the owning store's warehouses, which its own warehouse lists do not name, so the name travels with the line rather than being resolved by the reader."},"tenantUserUid":{"$ref":"#/components/schemas/OptionalUID"},"productUid":{"$ref":"#/components/schemas/UID"},"salesOrderUid":{"$ref":"#/components/schemas/OptionalUID"},"quantity":{"type":"integer","description":"In hundredths (100 = 1 unit)."},"name":{"type":"string"},"sku":{"type":"string"},"coverImage":{"description":"The cover image of the line's product as it stands now, carried on the line so a part can be drawn without a second read of the product. All three of its fields are empty strings when the product has no image: the object is always present and is never null, which is how the sales order line carries it too. It follows the product, so changing the product's cover image changes what every line for that product serves.","allOf":[{"$ref":"#/components/schemas/CoverImageSchema"}]},"priceOverride":{"type":"boolean","description":"Whether the line's product allows its price to be set to anything other than the one the catalogue resolves. It is read off the product as it stands now rather than recorded on the line, so it changes when the product does. It is the same flag the product carries, and on a service line it fixes the price outright rather than asking for the change to be recorded as a discount: a service line has no discount amount of its own, a reduction on a case being price below originalPrice, so there is nothing for it to be recorded as. False therefore fixes the line's price, and what a write then accepts is stated on price — the price the server resolves on the create, and on the update the price the line already carries, or its originalPrice where that is not 0. A client shows no price control on such a line rather than offering one the server will refuse. Where the case is billed, a reduction is given on the aggregate sales order line the part is summed into, the part being no line of its own there."},"price":{"type":"integer","description":"What one unit of the line is charged at now. It is originalPrice until somebody changes it, so the two together are the discount or the mark-up the line carries."},"costPrice":{"type":"integer"},"originalPrice":{"type":"integer","description":"What the line was priced at when it was added: the figure the create was sent, or the one the server resolved for it where the create sent none. It is written once, at the create, and no later change touches it — changing price moves price alone — so the two fields together say whether a line has been discounted or marked up since it was added, and by how much. A line that carries 0 here while it charges something holds no opening price at all, and the update never restores a price from that 0."},"discountReasonCode":{"type":"string","description":"The tenant's discount reason for this line's price, as its code — one of the tenant's reasons of type DISCOUNT, as the reasons list returns them for reasonType DISCOUNT. Empty when none was given. It is an annotation and never a calculation: what the line is charged at is price alone, and nothing is derived from the reason."},"discountReference":{"type":"string","description":"What the discount reason points at — the authorization, the agreement, the case it was granted under. Empty when none was given, and empty whenever discountReasonCode is empty. A line whose reason carries requiresReference always has one, that reason being refused on the line without it, so this is never empty while such a reason stands."},"totalPrice":{"type":"integer","description":"The price times the quantity divided by 100, the quantity being in hundredths."},"totalCostPrice":{"type":"integer"},"serialNumber":{"type":"string","description":"The serial number of the part that went INTO the device — the new part this line is for. An empty string when the part carries no serial number."},"removedSerialNumber":{"type":"string","description":"The serial number of the part that was taken OUT of the device and replaced by this one. An empty string when nothing was removed, or when the removed part carried no serial number.\nThe two serials are the two ends of the same swap: serialNumber is what went in, removedSerialNumber is what came out. Recording both is what lets the part that left the device be followed afterwards — back to the supplier on a claim, or found again if it turns up."},"note":{"type":"string"},"orderItemReferenceValue":{"type":"string","description":"The reference recorded against the line to satisfy what its product asks for — the phone number, the e-mail address, the agreement or the authorization the part is supplied under. An empty string when nothing was recorded, which is every line for a product that asks for nothing and every line added before a reference was demanded of it. Whether a product asks for a reference, and what shape the answer must take, is read off that product's own requirements.orderItemReference and never off the line."},"tenantUserDisplayName":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"createdBy":{"type":"string"},"lastModifiedAt":{"type":"string","format":"date-time"},"lastModifiedBy":{"type":"string"}}},"CoverImageSchema":{"title":"CoverImageSchema","type":"object","properties":{"productMediaUid":{"$ref":"#/components/schemas/OptionalUID"},"mainUrl":{"type":"string"},"thumbnailUrl":{"type":"string"}},"required":["productMediaUid","mainUrl","thumbnailUrl"]},"ServiceOrderAssetResponse":{"title":"ServiceOrderAssetResponse","type":"object","required":["assetUid","name","description","isPublic","customerVisible","publicUrl","mimeType","size","createdAt","createdBy","tenantUserUid","tenantUserDisplayName"],"properties":{"assetUid":{"$ref":"#/components/schemas/UID"},"name":{"type":"string"},"description":{"type":"string"},"isPublic":{"type":"boolean","description":"Whether the file is served from the CDN without a signature. For private assets use the download endpoint to get signed access. This is about how the file is fetched, not about who is meant to see it — customerVisible is what decides that."},"customerVisible":{"type":"boolean","description":"Whether the file is shown to the customer: it is listed among the documents on their service portal page. False keeps it inside the workshop — the photo of the damage taken for the technician, the supplier's note.\nIt is independent of isPublic, which only says whether the file is fetched from the CDN without a signature. A file can be CDN-public and still internal, and a customer-visible file reaches the customer through its own document link on the portal page. A file fetched from the CDN without a signature (isPublic) or kept at an address of its own, a file outside the SERVICE category and a file attached to more than one service order are never listed on the portal, whatever this flag says."},"publicUrl":{"type":"string"},"mimeType":{"type":"string"},"size":{"type":"string","description":"The size of the file in bytes, written as a decimal string — the same shape the asset endpoints serve it in."},"createdAt":{"type":"string","format":"date-time","description":"When the file record was created. It does not move when the file's contents are uploaded afterwards, nor when the file is attached to a service order later."},"createdBy":{"type":"string","description":"The caller the file record was created under, as it was recorded at the time: the name that user carries in this tenant, which on a shared screen is the person whose PIN unlocked it. A file created under an integration token carries that account's own name."},"tenantUserUid":{"type":"string","pattern":"^[A-Za-z0-9-_]*","description":"The person the file was added by: the caller, when the caller is a person — on a shared screen, the person whose PIN unlocked it. Empty when no person was resolved — an upload under an integration token, a file outside the SERVICE category, a file that carries no person. It is a person, never an integration account; createdBy is the caller's name as recorded at the time, a separate fact."},"tenantUserDisplayName":{"type":"string","description":"The display name of that person, read from the user as it stands today, the way a timeline entry names its author. Empty when tenantUserUid is empty."}}},"ServiceOrderFormValueResponseSchema":{"title":"ServiceOrderFormValueResponseSchema","description":"A value captured for one field on the service order's intake form, with the field's render information snapshotted at capture time so the value can be shown without looking the field up. Editing the field library afterwards does not change what is shown here.\nA capture for a MULTI_SELECT field is returned in values with value an empty string; every other field type is returned in value with values empty.\nA SECRET field never appears here: what was captured for one is a service order secret, listed under the service order's secrets and read through the secrets reveal endpoint.\nA sensitive value that was removed when the service order reached a terminal state still appears, with redacted true and an empty value: the answer's label stays, so the record still says which question was asked, and only what was answered is gone.","type":"object","required":["serviceFormFieldUid","fieldKey","label","fieldType","systemKind","sensitive","value","values","redacted"],"properties":{"serviceFormFieldUid":{"$ref":"#/components/schemas/UID"},"fieldKey":{"type":"string","description":"The stable slug of the field. It never changes."},"label":{"type":"string","description":"The label of the field as it was when the value was captured — for a platform field, in the language the capturing user read it in."},"fieldType":{"$ref":"#/components/schemas/ServiceFormFieldTypeENUM"},"systemKind":{"nullable":true,"description":"The well-known Flow concept this field represents. A system kind marks a platform field; null marks one of the tenant's own custom fields.","allOf":[{"$ref":"#/components/schemas/ServiceFormFieldSystemKindENUM"}]},"sensitive":{"type":"boolean","description":"Whether the value is sensitive. Sensitive values are left out of search results, webhooks and exports, and are removed when the service order reaches a terminal state — after which the entry stays, with redacted true."},"value":{"type":"string","description":"The captured value as text. Always an empty string for a capture on a MULTI_SELECT field, whose chosen options are in values. An empty string when redacted is true: the value has been removed and is not recoverable."},"values":{"type":"array","description":"The chosen options as text, for a capture on a MULTI_SELECT field. Empty for every other field type, and empty when redacted is true: what was chosen has been removed and is not recoverable.","items":{"type":"string"}},"redacted":{"type":"boolean","description":"True when a sensitive value was removed because the service order reached a terminal state. The answer's label remains, so the record still says which question was asked, and only what was answered is gone. False on every entry that still holds its value. The entry stays even when the placement it answers is later hidden by a condition — the record that the question was answered is kept — and, when the entry is marked sensitive, it is served on the single service order only, never in search results."}}},"ServiceFormFieldTypeENUM":{"title":"ServiceFormFieldTypeENUM","description":"The data type of a service order form field. It decides how the field is rendered at intake and how the captured value is validated.\nTEXT: single-line text. TEXTAREA: multi-line text. NUMBER: a number. BOOLEAN: true or false. DATE: an ISO 8601 date. SELECT: one of the values listed in the field's selectOptions. MULTI_SELECT: several of the values listed in the field's selectOptions. SECRET: a short sensitive text such as a device passcode.\nSECRET always implies sensitive, and what is captured for a SECRET field is never kept as a form value: it is stored as a service order secret, which holds the value encrypted, is listed by its label alone under the service order's secrets, and can only be read through the secrets reveal endpoint. Secrets are deleted when the service order reaches a terminal state.\nWhat is captured for a MULTI_SELECT field is a list rather than a single answer, and is sent and returned in the form value's values rather than in its value.\nThe field type is immutable after the field has been created — create a new field instead of changing it.","enum":["TEXT","TEXTAREA","NUMBER","BOOLEAN","DATE","SELECT","MULTI_SELECT","SECRET"],"type":"string"},"ServiceFormFieldSystemKindENUM":{"title":"ServiceFormFieldSystemKindENUM","description":"Marks a service order form field as a platform field: a well-known Flow concept, so clients and integrations can recognise the field without matching on its label.\nSERIAL_NUMBER: the serial number of the device. IMEI: the IMEI of a mobile device. PASSCODE: the passcode or unlock code of the device — it is of the field type SECRET and is therefore always sensitive. ACCESSORIES: the accessories handed in with the device, written as free text. LOCATION_LABEL: where the device is physically stored while it is in the workshop. ISSUE_REPRODUCED: whether the reported issue could be reproduced. INTERNAL_NOTE: a note that is never shown to the customer. ESTIMATED_PRICE: what the work is estimated to cost. MAX_PRICE: the ceiling the customer allows the work to be done up to without being asked again. PRODUCT: the product the unit in for service is. PRIORITY: how urgent the work is, one of the four values of PriorityENUM.\nA platform field is already in every tenant's field library, ready to be used. It belongs to the platform: the platform labels it — the label comes back localized to the reader's language, the way the platform localizes everywhere else — and the tenant can neither create, relabel nor archive one, nor change its validation or its sensitivity. Its whole definition — type, sensitivity and what it is checked against — is fixed by the platform and does not change, so a condition, a filter or an integration built against a platform field keeps working. No platform field carries selectOptions: what a tenant would put in such a list is the tenant's own, so a platform field is free text, a number, a boolean, a secret or, for PRIORITY, one of the four PriorityENUM values its kind names, and selectOptions is always empty on one. In every other respect a platform field is an ordinary field: it stands in the field list with a uid of its own, and it is placed on a form exactly like any other field, except that PRIORITY is never marked required.\nESTIMATED_PRICE and MAX_PRICE are backed fields: what is captured for them is written to the service order's own estimatedPrice and maxPrice rather than into the form value store, because that is where billing and the quote rules compute on it. The form still decides everything about the capture — whether the field appears at all, where in the intake it sits, and whether it must be filled in — and the value simply lands where it is used. Both are of field type NUMBER, and neither is ever sensitive.\nPRODUCT is backed in the same way: what is captured for it is written to the service order's own productUid rather than into the form value store, because that is what the case is identified by. It is of field type TEXT and is never sensitive. A PRODUCT capture is the uid of one of the tenant's products, and a uid naming none is refused with a 404, the same answer the service order's own productUid gives — the two are one road, so they refuse alike. A client renders it by its system kind — a product search — rather than as a text box.\nPRIORITY is backed in the same way: what is captured for it is written to the service order's own priority rather than into the form value store, because that is the priority the case carries wherever it is shown and filtered. It is of field type TEXT and is never sensitive. A PRIORITY capture is one of the names of PriorityENUM — HIGHEST, HIGH, LOW or NONE — and any other value is refused with a 400; clearing it stores NONE. A client renders it by its system kind — a picker of the four values — rather than as a text box, and its selectOptions stays empty. It is never a required field: the service order's priority always holds a value, so required would mean nothing, and a form placement that marks it required is refused with a 400. As with every backed field, a PRIORITY capture wins over priority sent in the same request, and a PRIORITY placement the write hides — hidden on the create, or closed by an update's own answers — clears it to NONE in the same write.\nA field without a system kind is a field the tenant created itself, and everything about it is the tenant's to set. The schema is nullable: null is the value systemKind carries on such a custom field.\nExtensible — new system kinds may be added, so clients must not fail on a value they do not know. A kind is seeded into every tenant's field library, so a client that lists the library meets every kind the platform has, including ones added after it was built.","enum":["SERIAL_NUMBER","IMEI","PASSCODE","ACCESSORIES","LOCATION_LABEL","ISSUE_REPRODUCED","INTERNAL_NOTE","ESTIMATED_PRICE","MAX_PRICE","PRODUCT","PRIORITY",null],"nullable":true,"type":"string"},"ServiceOrderSecretResponseSchema":{"title":"ServiceOrderSecretResponseSchema","description":"An encrypted secret kept on a service order, such as a device passcode. A service order can hold any number of secrets.\nThe value is never returned here: a secret is listed by its label alone and can only be read through the secrets reveal endpoint, which writes a SECRET_VIEWED event on the service order.\nA secret is never edited. It is created, revealed and deleted, and nothing else — a value that has to change is a new secret and the old one deleted, which is why the record carries when it was created and by whom and nothing about a later change.\nSecrets are never included in search results, webhooks or exports. A secret can be deleted on its own as soon as it is no longer needed, and every secret still on the service order is deleted in the same transaction as the service order reaching a terminal state. Reopening the service order afterwards does not bring them back.","type":"object","required":["secretUid","serviceOrderUid","label","serviceFormFieldUid","createdAt","createdBy"],"properties":{"secretUid":{"$ref":"#/components/schemas/UID"},"serviceOrderUid":{"$ref":"#/components/schemas/UID"},"label":{"type":"string","description":"What the secret is, so it can be shown in a list without revealing the value. Snapshotted when the secret is created — editing the label of the form field afterwards does not change it, and a platform field's label snapshots in the language the capturing user read it in."},"serviceFormFieldUid":{"description":"The SECRET field on the intake form this secret was captured for. An empty string on a secret that was added on its own, without a form field.","type":"string","pattern":"^[A-Za-z0-9-_]*"},"createdAt":{"type":"string","format":"date-time"},"createdBy":{"type":"string"}}},"ServiceJobTypeRefSchema":{"title":"ServiceJobTypeRefSchema","description":"A job type on a service order, with its name embedded so the service order can be shown without looking the job type up. Read the checklist and the suggested products through the job types endpoint.","type":"object","required":["serviceJobTypeUid","name"],"properties":{"serviceJobTypeUid":{"$ref":"#/components/schemas/UID"},"name":{"type":"string","description":"The name of the job type as it reads now. Renaming the job type changes what is returned here."}}},"ServiceOrderChecklistAnswerSchema":{"title":"ServiceOrderChecklistAnswerSchema","description":"One answer on a job type's checklist on a service order: the item, yes or no, who gave the answer and when. It is internal staff data and never reaches a customer.\nAttribution is double, as on a timeline entry. tenantUserUid is the person who gave the answer: the caller, which on a shared screen is the person whose PIN unlocked it; it is empty for an answer given under an integration token, which is no person, and empty when that person has since been deleted. tenantUserDisplayName is that person's name as it read when the answer was given: it stays when the person is deleted, and is empty under an integration token. screenAccountTenantUserUid is the screen account the screen was signed in with, set exactly as on a timeline entry: under an unlock token it is read from the token; on a personal login, or under any other access token, it is the person themselves; it is empty under an integration token, and empty when the screen account has since been deleted.","type":"object","required":["serviceJobTypeUid","item","checked","tenantUserUid","tenantUserDisplayName","screenAccountTenantUserUid","answeredAt"],"properties":{"serviceJobTypeUid":{"$ref":"#/components/schemas/UID"},"item":{"type":"string","description":"The checklist item the answer is for, as it reads on the job type."},"checked":{"type":"boolean","description":"The answer: true is yes, false is no."},"tenantUserUid":{"$ref":"#/components/schemas/OptionalUID"},"tenantUserDisplayName":{"type":"string"},"screenAccountTenantUserUid":{"$ref":"#/components/schemas/OptionalUID"},"answeredAt":{"type":"string","format":"date-time","description":"When the answer was given. Sending the same answer again does not move it; a different answer does."}}},"ServiceOrderQuoteStateENUM":{"title":"ServiceOrderQuoteStateENUM","description":"Where the latest quote on a service order stands.\nNONE: nothing has been offered. SENT: an offer is outstanding, waiting for the customer's answer. APPROVED: the customer accepted the latest offer. DECLINED: the customer turned it down.\nIt is maintained solely by the quote endpoints: sending a quote sets SENT, recording a decision sets the answer that was given, and a new quote puts it back to SENT and asks again.","type":"string","enum":["NONE","SENT","APPROVED","DECLINED"]},"ServiceOrderCoverageENUM":{"title":"ServiceOrderCoverageENUM","description":"Who pays for the work on a service order, and under what right. Every service order carries a coverage: it is chosen at intake, and it can be changed while the case runs — a diagnosis may reclassify it, as when water damage voids a warranty and the case becomes payable.\nPAYABLE: the customer pays. CONSUMER_CLAIM: a claim under statutory consumer rights — the seller's cost. WARRANTY_CLAIM: a claim under a warranty — the seller's or the manufacturer's cost. INSURANCE_CLAIM: a claim to an insurer — the service order names the insurer and may carry the insurer's claim number and the deductible, recorded for information.\nPricing, quoting and invoicing work the same way whatever the coverage is: the sale is billed to the service order's customer on every coverage (see post-serviceorders-orders). A covered repair can still carry billable work.\nExtensible — new coverages may be added, so clients must not fail on a value they do not know.","type":"string","enum":["PAYABLE","CONSUMER_CLAIM","WARRANTY_CLAIM","INSURANCE_CLAIM"]},"Paging":{"description":"totalCount The total number of items in the result set.\n\npageSize The number of items per page.\n\npageNumber The current page in the result set.","properties":{"pageNumber":{"type":"integer"},"pageSize":{"type":"integer"},"totalCount":{"type":"integer"}},"required":["totalCount","pageSize","pageNumber"],"title":"Paging","type":"object"},"ServiceOrderSearchRequestSchema":{"title":"ServiceOrderSearchRequestSchema","type":"object","properties":{"customerName":{"type":"string"},"customerMobile":{"type":"string","description":"Filter by the start of the customer's mobile number. Whitespace in it is ignored, and the number is matched the way query matches a whole number against the mobile number, without the five-digit minimum. A customerMobile of whitespace alone is no filter, and one that is not a whole number once its whitespace is taken out, or is zeros alone, matches no case. It is ignored when query carries a word."},"customerEmail":{"type":"string"},"title":{"type":"string"},"serviceNumber":{"type":"string"},"query":{"type":"string","description":"Search on the customer, the service number and the title in one. The query is split on whitespace into words, and every word must match at least one of the service number, the title, or the customer's first name, last name or e-mail, partially and case-insensitively — so a customer's full name in either order, or a name word together with a title word, finds the case. A word that is a whole number — digits, with an optional leading + — of at least five digits also matches the start of the customer's mobile number, typed as the national number with or without its leading 0, or with the tenant's country code after a +, after 00 or after nothing: in a tenant whose country's phonePrefix is +47, 91234567, 4791234567, 004791234567 and +4791234567 all find the cases of the customer whose mobile is +4791234567, and in a +46 tenant 0701234567 finds +46701234567. Its leading zeros are taken off a number of at least eight digits only; a shorter number that begins with 0 is matched as typed. A number written with a + and its country code finds a mobile of any country. A whole number of fewer than five digits never matches the mobile number, and neither does one of zeros alone.\nA query that is a whole number once its whitespace is taken out is read as that one number, so a number typed in groups, +47 912 34 567 or 912 34 567, is read whole; beside a word the groups are not joined, and in ola 912 34 567 each group is a word of its own. A query that is one whole number alone matches only the service number and, under the rule above, the start of the customer's mobile number. A query of whitespace alone is no query. It does not match externalSalesOrderNumber or externalServiceNumber, which are filters of their own. When query carries a word, customerName, customerEmail, customerMobile, serviceNumber and title are ignored."},"fromCreatedDate":{"type":"string","format":"date","description":"GTE date, e.g. 2006-05-04"},"toCreatedDate":{"type":"string","format":"date","description":"LTE date, e.g. 2006-05-04"},"assignedUserUids":{"type":"array","description":"Filter by who the service order is held by. The entries are user uids, and an empty string entry means held by the store and assigned to nobody — the same thing an empty assignedUserUid says on the service order itself.\nA service order matches when it is held by any one of the listed entries, so \"mine and the ones up for grabs\" is one list with two entries: the user's own uid and an empty string. The list is OR within itself and AND with the other filters, exactly as every other list filter here is.","items":{"$ref":"#/components/schemas/OptionalUID"}},"createdFromStoreUids":{"type":"array","description":"Filter by the store a service order was taken in at. It never changes, so it still names the counter a case was registered at long after the case has moved on. This is not storeUids, which filters on the store that owns it today; the two differ for the rest of a case's life once it has been moved. Wherever the request runs without a store in the path, this is how a store lists everything it took in, wherever those cases sit now — the ones it still owns and the ones it has sent on alike. Narrow it with storeUids to say where they sit: naming the store itself leaves what it still owns, and naming another store leaves what it sent there.","items":{"$ref":"#/components/schemas/UID"}},"priorities":{"type":"array","items":{"$ref":"#/components/schemas/PriorityENUM"}},"serviceStates":{"type":"array","items":{"$ref":"#/components/schemas/ServiceStateENUM"}},"open":{"type":"boolean","description":"Set to true to get only the service orders that are still open: the ones that have not finished, whatever state they are on. Which states end a service order is ServiceStateENUM's own business — COMPLETE and CANCELLED as it stands — and a service order that is reopened is open again.\nThe filter only ever applies when it is true. Leaving it out, or sending false, does not filter on this at all: it never means \"only the finished ones\", which is what serviceStates and the finished-date filters are for.\nIt narrows like every other filter, so sending it beside serviceStates asks for both at once: a request that names only the states which end a service order in serviceStates, and sends open true, matches nothing. Ask with it rather than by listing the states a client believes to be open — ServiceStateENUM is extensible, and a state added later falls on the right side of this filter from the moment it exists, here, in the service order counts endpoint and in every saved list holding these filters."},"serviceTypeUids":{"type":"array","items":{"$ref":"#/components/schemas/UID"}},"storeUids":{"type":"array","description":"Filter by the store that owns the service order — the store the work sits with and where the customer collects it. This is not createdFromStoreUids, which filters on the store that took the service order in; the two differ whenever a service order has been moved between stores.\nHow it composes with the store in the path: on the store-scoped search the path store scopes the result, and storeUids narrows within it — naming a store the path store does not cover matches nothing. Wherever the same request shape runs without a store in the path — on the tenant-level search, the counts endpoint and the filters a saved list holds — the reach is every service order of the tenant, and storeUids is the only filter on the owning store there is: it narrows within the tenant. Naming a store the caller holds nothing at is not refused: it matches the service orders that store owns.\nstoreUids narrows on the store that owns a service order alone. A case a store took in and has since sent on is outside a storeUids naming that store, because another store owns it now; createdFromStoreUids is the filter that names it.","items":{"$ref":"#/components/schemas/UID"}},"serviceStatusUids":{"type":"array","description":"Filter by the status the service order is on now.","items":{"$ref":"#/components/schemas/UID"}},"fromReadyAtNeeded":{"type":"string","format":"date-time","deprecated":true,"description":"Deprecated. The service module follows one date, readyAtEstimate — filter on fromReadyAtEstimate instead. It is ignored when sent. It will be removed after the announced deprecation window; see the deprecation log for the date."},"toReadyAtNeeded":{"type":"string","format":"date-time","deprecated":true,"description":"Deprecated. The service module follows one date, readyAtEstimate — filter on toReadyAtEstimate instead. It is ignored when sent. It will be removed after the announced deprecation window; see the deprecation log for the date."},"fromReadyAtEstimate":{"type":"string","format":"date-time","description":"GTE date-time on readyAtEstimate, the point in time the service order is estimated to be finished. The bound is inclusive: a whole-day \"from\" bound is that day's first millisecond, 00:00:00.000 in the tenant's timezone. Service orders with no readyAtEstimate are left out when this is used."},"toReadyAtEstimate":{"type":"string","format":"date-time","description":"LTE date-time on readyAtEstimate, the point in time the service order is estimated to be finished. The bound is inclusive: a whole-day \"to\" bound is that day's last millisecond, 23:59:59.999 in the tenant's timezone, so a value saved at 23:59:59.999 is inside it, as is the end of that day with no time picked. Service orders with no readyAtEstimate are left out when this is used."},"overdue":{"type":"boolean","description":"Set to true to get only the service orders that are running late. A service order is late when its readyAtEstimate is in the past and it is not a finished service order; a service order with no readyAtEstimate is never late.\nThe filter only ever applies when it is true. Leaving it out, or sending false, does not filter on lateness at all: it never means \"only the ones on time\"."},"serial":{"type":"string","description":"Filter by serial number or IMEI. Matches the serial number and IMEI values captured on the service order's intake form as well as the serial numbers on its items — both the parts that were installed and the parts that were removed. Case insensitive, and partial values match.\nValues captured for a field marked sensitive never take part in the matching. A sensitive serial can therefore be neither read out of a result nor probed for by guessing at it here: search is no way around the sensitivity of a field."},"serviceJobTypeUids":{"type":"array","description":"Filter by the job types the work on the service order consists of. A service order matches when it carries any one of the listed job types.","items":{"$ref":"#/components/schemas/UID"}},"externalServiceNumber":{"type":"string","description":"Filter by externalServiceNumber: the number an outside workshop or supplier handling the work gives the case. Case insensitive, and partial values match."},"claimNumber":{"type":"string","description":"Filter by claimNumber: the number the insurer gave the claim on an insurance case. Case insensitive, and partial values match."},"externalSalesOrderNumber":{"type":"string","description":"Filter by externalSalesOrderNumber: the order number, in the tenant's external order system, of the sales order the unit was bought on — never the service number. Case insensitive, and partial values match. Leading and trailing whitespace is trimmed, and a value of spaces alone is no filter."},"customerNumber":{"type":"string","description":"Filter by the customer number of the customer on the service order. Case insensitive, and partial values match."},"customerUids":{"type":"array","description":"Filter to the service orders that belong to these customers. A service order matches when it is on any one of the listed customers. This is also how a customer page the tenant builds itself asks for one customer's service orders, through an integration token.","items":{"$ref":"#/components/schemas/UID"}},"productUids":{"type":"array","description":"Filter by the product the unit in for service is — the model of the machine on the bench, not the parts on the service order's items. A service order matches when the unit it is about is any one of the listed products. This is how \"every one of this model we have had in\" is asked for.","items":{"$ref":"#/components/schemas/UID"}},"coverages":{"type":"array","description":"Filter by who pays for the work and under what right. A service order matches when its coverage is any one of the listed values — which is how the claims are separated from the payable work.","items":{"$ref":"#/components/schemas/ServiceOrderCoverageENUM"}},"fromFinishedDate":{"type":"string","format":"date","description":"GTE date on the date the service order last reached a terminal state, COMPLETE or CANCELLED, e.g. 2006-05-04. Service orders that are not finished are left out when this is used, however long they have been open — and a reopened service order is not finished until it ends again.\nThis is what the workspace tiles count through: \"completed today\", \"completed the last 7 days\" and \"completed the last 30 days\" put a date on this filter and narrow serviceStates to COMPLETE, counted by the service order counts endpoint."},"toFinishedDate":{"type":"string","format":"date","description":"LTE date on the date the service order last reached a terminal state, COMPLETE or CANCELLED, e.g. 2006-05-04. Service orders that are not finished are left out when this is used, however long they have been open — and a reopened service order is not finished until it ends again.\nThis is what the workspace tiles count through: \"completed today\", \"completed the last 7 days\" and \"completed the last 30 days\" put a date on this filter and narrow serviceStates to COMPLETE, counted by the service order counts endpoint."},"formValueFilters":{"type":"array","description":"Filter on what was captured on the intake form. Each entry names a library field by its stable key and the value it must hold; several entries narrow the result, because a service order has to match every one of them.\nThe same shape reaches the tenant-level search, the store-scoped search, the service order counts endpoint and the filters a saved list holds alike, so a dashboard card can count on any field the tenant ever created: \"in queue with a support agreement\" is two counts and a division away.\nValues captured for a field marked sensitive never take part in the matching. A sensitive answer can therefore be neither read out of a result nor probed for by guessing at it here: search is no way around the sensitivity of a field.","items":{"$ref":"#/components/schemas/ServiceOrderFormValueFilterSchema"}}}},"ServiceOrderFormValueFilterSchema":{"title":"ServiceOrderFormValueFilterSchema","description":"A filter on what was captured for one intake form field. A service order matches when the value captured for the named field equals the value given here; for a MULTI_SELECT field it matches when the value given here is among the options that were chosen.\nValues captured for a field marked sensitive never take part in the matching. A sensitive answer can therefore be neither read out of a result nor probed for by guessing at it here: search is no way around the sensitivity of a field.\nA filter naming a field of system kind ESTIMATED_PRICE, MAX_PRICE, PRODUCT or PRIORITY matches nothing: what is captured for those is written to the service order's own columns rather than into the form value store. The service order's priority is filtered with priorities on the search instead.","type":"object","required":["fieldKey","value"],"properties":{"fieldKey":{"type":"string","description":"The stable slug of the library field to look at — it never changes, so a filter written against it keeps working when a label is edited. On a custom field it is generated by the server from the label at creation; a platform field carries a fixed platform key, the same for every tenant and every language."},"value":{"type":"string","description":"The captured value the field must hold, compared as text. A BOOLEAN answer compares as the strings true and false, a SELECT answer compares against the option that was chosen, and a MULTI_SELECT answer matches when this is one of the options that were chosen. An empty value matches nothing: no captured answer is empty."}}},"SortDirectionENUM":{"description":"|ENUM      | Description |\n| ---------------- | ------------ |\n| ASC | Sort in ascending order|\n| DESC | Sort in descending order|\n","enum":["ASC","DESC"],"title":"SortDirectionENUM","type":"string"}},"requestBodies":{"ServiceOrderSearchRequest":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceOrderSearchRequestSchema"}}}}},"parameters":{"pageNumberQuery":{"description":"Reference to a specific page in a result set.","in":"query","name":"pageNumber","required":false,"schema":{"type":"integer"}},"pageSizeQuery":{"description":"The number of items per page in a result set.","in":"query","name":"pageSize","required":false,"schema":{"type":"integer"}},"sortByQuery":{"description":"Defines which field the resource list is sorted by.","in":"query","name":"sortBy","required":false,"schema":{"type":"string"}},"sortDirectionQuery":{"description":"Reference to a sort direction","explode":false,"in":"query","name":"sortDirection","schema":{"$ref":"#/components/schemas/SortDirectionENUM"},"style":"form"}}},"paths":{"/tenants/{tenantUid}/stores/{storeUid}/serviceorders/search":{"post":{"summary":"Search for service-orders","tags":["Service"],"responses":{"200":{"$ref":"#/components/responses/ServiceOrderListResponse"}},"operationId":"serviceorders-search","description":"Search for service orders is case insensitive and you can use partial values,\ne.g. name 'Anna' will return both 'Anna' and 'Johanna'.\nUse the query to search for customer, service number or title from\nonly one field. When this is used, the customer and service search fields are ignored.\nThe array fields work like filters.\nThis search is scoped to the store in the path. A storeUids in the body narrows within that scope rather than widening it: naming a store the path store does not cover matches nothing. To search across every service order of the tenant, use the tenant-level service order search instead.\nWhat the results leave out: secrets and checklistAnswers are always empty arrays, and formValues leaves out the values captured for sensitive fields. Read the one service order to see them: the checklist answers at any store of the tenant, the secrets and the sensitive values at the store that owns it or the store it was taken in at. Sensitive values take no part in the matching either, so a sensitive serial can be neither read out of a result nor probed for here.\nThis list is the store's own work: it holds the service orders the store owns, and not the ones it took in and has since sent on. Those are found on the tenant-level service order search, which reaches both. To see what this store took in, use the tenant-level service order search with createdFromStoreUids naming this store — everything it registered, wherever it sits now — and add storeUids naming another store to leave only what it sent there. A saved list holding those filters keeps it as a list of its own, separate from the work the store is handling.\n\nRequired permissions: SERVICE_ORDER","requestBody":{"$ref":"#/components/requestBodies/ServiceOrderSearchRequest"},"parameters":[{"$ref":"#/components/parameters/pageNumberQuery"},{"$ref":"#/components/parameters/pageSizeQuery"},{"$ref":"#/components/parameters/sortByQuery"},{"$ref":"#/components/parameters/sortDirectionQuery"}]}}}}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.flowretail.com/docs/developers/api-documentation/service/search-for-service-orders.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
