> 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/update-service-order-item.md).

# Update service-order item

Update a service-order item. This is a write on the case, so it belongs to the store that owns the service order: at any other store it is refused with a 403, where the case can be read but not worked on.

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":{"ServiceOrderResponse":{"description":"Example response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceOrderResponseSchema"}}}}},"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"]},"ServiceOrderItemUpdateRequestSchema":{"title":"ServiceOrderItemUpdateRequestSchema","description":"The fields of a line on a service order that can be changed after it is added.\nEvery field is optional, and what a request leaves out is kept as the line holds it at the moment the write runs — not as the client last read it. So a request that changes one field changes that field alone, and two people editing different fields of one line do not revert each other.\nA line that has been put on a sales order can no longer be changed at all: every update is refused until that order is cancelled, and that refusal is given before the price or the discount reason is judged.","type":"object","properties":{"price":{"type":"integer","description":"What one unit of the line is charged at.\nA price that is sent is taken exactly as it is given, 0 included — a part handed over free is priced by sending 0 — unless the product forbids it. A product whose priceOverride is false fixes the line's price: the create accepts only the price the server would have resolved had none been sent, so a client leaves price out on such a line rather than working the figure out itself, and the update accepts only the price the line already carries, or the one it was added at, its originalPrice, where that is not 0. Anything else is refused with a 400 naming the product. An originalPrice of 0 is not an opening price to restore, so the update never puts a line back to it; a line whose price is 0 keeps taking 0, that being the price it already carries. A product whose price is fixed and which has no price at all — no price list reaching this store and no recommended retail price — is refused the same way, there being no price it would accept; a product the catalogue prices at 0 has a price like any other, and a line for it is added by sending 0. The line's priceOverride says which kind of product it is, so a client shows no price control where the price is fixed.\nLeft out on the create, the server prices the line the way an ordinary sales order line is priced for this customer: the store's sales price for the product, as the catalogue resolves it at that moment. Do not resolve a price client-side and send it — a figure the client works out is a figure the server takes as given and will not correct. A price that resolves to 0 is a price like any other and the line is created at 0. Only a product with no price at all — no price list reaching this store and no recommended retail price — is refused, with a 400 naming the product, rather than created at 0: a part is never quietly booked as free.\nLeft out on the update, the price the line already carries is kept. An update never re-prices a line: a part keeps what it was charged at when it was added, however the catalogue moves afterwards, and a new figure is only ever one that was sent here."},"discountReasonCode":{"type":"string","description":"The tenant's discount reason for this line's price, as its code. It must be one of the tenant's reasons of type DISCOUNT — the codes the reasons list returns for reasonType DISCOUNT — and a code naming no such reason is refused with a 400.\nLeft out on the create, the line carries no reason. Left out on the update, what the line already holds is kept, and an empty string clears it; a line left with no reason may carry no reference either, so a request that clears the reason while leaving a non-empty reference standing is refused with a 400. Only a code that is sent is looked up: a code the line already holds is never re-checked, so a reason deleted since it was recorded leaves the annotation standing and demands nothing.\nIt is an annotation, never a calculation. Core derives no amount from it and checks none: what the line is charged at is price alone, and a reason may be recorded on a line that carries no reduction at all. The product's allowDiscount plays no part in it either — the reason is an annotation on the service line, not a discount for the sales module to judge."},"discountReference":{"type":"string","description":"What the discount reason points at — the authorization, the agreement, the case it was granted under.\nLeft out on the create, the line carries no reference. Left out on the update, what the line already holds is kept, and an empty string clears it.\nEverything is judged on the line as it stands once the request has been applied, never on the request alone, so a request that sends one of the two fields is judged against the other as the line already holds it. A reference that is not empty is refused with a 400 when the line then carries no discount reason, and an empty one is refused with a 400 when the reason the line then carries has requiresReference — so clearing the reference alone is refused on a reason that demands one, and the way to drop such a reason is to clear both fields in one request, which is always accepted."},"quantity":{"type":"integer","description":"How many units the line is for, in hundredths (100 = 1 unit).\nLeft out, the quantity is kept and no stock moves at all, so correcting a note or a serial number never touches the warehouse. A quantity that is sent moves stock by the difference where the line is booked against a warehouse for a stock-tracked product: units added are taken out of that warehouse, units removed are put back. A line carrying a serial number is one unit and nothing else — 100 here, and any other quantity is refused — so serial-numbered parts are added and removed rather than counted up. A quantity below 1 is refused. The create demands it."},"serialNumber":{"type":"string","description":"The serial number of the part that went INTO the device — the new part this line is for."},"removedSerialNumber":{"type":"string","description":"The serial number of the part that was taken OUT of the device and replaced by this one. Send an empty string when nothing was removed, or when the removed part carried no serial number. The two serials are the two ends of the same swap, and recording both is what lets the part that left the device be followed afterwards."},"note":{"type":"string"},"orderItemReferenceValue":{"type":"string","description":"The reference the line's product asks to have recorded against it: the phone number, the e-mail address, the agreement or the authorization the part is supplied under. Whether a product asks for one, and what shape the answer must take, is read off that product's own requirements.orderItemReference, which asks for nothing when it is empty.\nCore holds the line to that requirement: when the reference is judged, one that is missing, empty, or not of the shape the requirement names is refused with a 400. A product that asks for nothing accepts anything here, the empty string included.\nLeft out on the create, the line carries no reference, and a product that asks for one refuses the line. Left out on the update, what the line already holds is kept and nothing about the reference is judged, so correcting a note or a serial number never trips this rule. An empty string clears it, and a product that asks for a reference refuses that. On an update alone there is one exception: the reference the line already carries is always accepted, empty or not — a resend that changes nothing is never a refusal — which keeps a line editable both when no reference was ever demanded of it and when the shape its product asks for has changed since the reference was recorded. A create has nothing it already carries, so the exception never reaches it.\nIt stays on the service order line and does not reach the sales order the case is converted to.\nIt is the same answer a sales order line holds among its properties under the key ORDERITEM_REFERENCE, kept here as a field of its own because a service order line has no properties. It is named for the value rather than for the demand because a sales order line's own orderItemReference field carries the product's demand and not the answer to it."}}}},"requestBodies":{"ServiceOrderItemUpdateRequest":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceOrderItemUpdateRequestSchema"}}}}}},"paths":{"/tenants/{tenantUid}/stores/{storeUid}/serviceorders/{serviceOrderUid}/items/{serviceOrderItemUid}":{"put":{"summary":"Update service-order item","operationId":"put-serviceorder-item","description":"Update a service-order item.\nThis is a write on the case, so it belongs to the store that owns the service order: at any other store it is refused with a 403, where the case can be read but not worked on.\n\nRequired permissions: SERVICE_ORDER","responses":{"200":{"$ref":"#/components/responses/ServiceOrderResponse"}},"tags":["Service"],"requestBody":{"$ref":"#/components/requestBodies/ServiceOrderItemUpdateRequest"}}}}}
```


---

# 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/update-service-order-item.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.
