Create, update or delete a sales order
distru-mutate-sales-orderWriteLeafLinkMetrcPOSQuickBooksCreates, updates or deletes one sales order. An UPDATE pushes the change to LeafLink for an order that came from it, and re-syncs the order's invoices to QuickBooks and to your POS (Dutchie, Blaze or Treez) when they sync there. On an order with a Metrc transfer template, an UPDATE with every line fulfilled updates the template in Metrc, and canceling or deleting the order deletes it.
Inputs
Every tool also takes the common inputs.
| Field | Type | Required | Description |
|---|---|---|---|
| action | enumCREATEUPDATEDELETE | Yes | |
| id | string | No | Required for UPDATE and DELETE. Resolve via distru-search-sales-orders. |
| customerId | string | No | Customer company. Optional while the status is PENDING or PROCESSING; required from READY_TO_SHIP on. Resolve via distru-search-companies. |
| status | enumPENDINGPROCESSINGREADY_TO_SHIPDELIVERINGDELIVEREDCOMPLETEDCANCELED | No | CREATE defaults to the company's default status, usually PENDING. PROCESSING holds stock only for lines with a batch or package: to reserve it, give each line one. CANCELED releases stock, deletes pending assemblies and voids every invoice of the order; moving out of CANCELED un-voids them. CANCELED, like DELETE, also deletes the order's Metrc transfer template; every UPDATE re-syncs a LeafLink order and the order's invoices to QuickBooks and the POS when they sync there. A LeafLink order can't leave CANCELED. |
| orderDatetime | string | No | CREATE defaults to now. ISO 8601 with a UTC offset, e.g. "2026-09-01T00:00:00-07:00"; the company timezone is on distru-get-me. |
| dueDatetime | string | No | Payment due. Defaults to orderDatetime plus the customer's payment term, else the company's default term, else orderDatetime. ISO 8601 with a UTC offset, e.g. "2026-09-01T00:00:00-07:00"; the company timezone is on distru-get-me. |
| deliveryDatetime | string | No | When the company's compliance setting to use the received date is on, matching a received manifest replaces it with that date. ISO 8601 with a UTC offset, e.g. "2026-09-01T00:00:00-07:00"; the company timezone is on distru-get-me. |
| locationId | string | No | Inventory location stock ships from; new rows without their own locationId use it. On UPDATE, rows already on the order keep their location: send each row by id with its new locationId (and a batch held there) to move it; a row sent without id is a new row. Required for metrcPackageLabel rows: a label is looked up on its license, the one a manifest must belong to. A packageId row needs it or its own locationId. Resolve via distru-search-locations. |
| billingLocationId | string | No | The customer's billing location. Resolve via distru-get-company (includeLocations) on the customer. |
| shippingLocationId | string | No | The customer's shipping location. Resolve via distru-get-company (includeLocations) on the customer. |
| ownerId | string | No | Sales rep. Resolve via distru-search-users. |
| internalNotes | string | No | Not shown to the customer. |
| externalNotes | string | No | Shown on the order slip and invoice. |
| metrcManifestNumber | string | No | Outgoing Metrc manifest to match. Resolve via distru-search-metrc-manifests (direction OUTGOING); read its packages with distru-get-metrc-manifest (includeDeliveries). Status defaults to the company's post-match status when omitted. |
| orderItems | object[] or null | No | Required for CREATE. One entry per stored row. On UPDATE the complete list: stored rows left out are deleted and their stock released; send a stored row with just its id to keep it unchanged. Omitted or null leaves the rows as they are. Read current rows with distru-get-sales-order first (includeOrderItems); lineGroup there is output only, never sent back. Groups: a product line fulfilled from packages is several rows sharing product, batch, location, priceBase, isSample and tier (and THC when the company sells by potency; same lineGroup in the output): one row per package (whole package, no quantity) and at most one remainder row with only quantity, allowed in PENDING and PROCESSING. Adding a package row does not reduce the remainder: resend the remainder with the quantity left, or leave it out when the packages cover the line. Dropping a package row shrinks the line unless you add its quantity back to the remainder. |
| orderItems[]. | string | No | UPDATE only: a row already on the order; only the fields sent change. Omit to add a row. Resolve via distru-get-sales-order (includeOrderItems). |
| orderItems[]. | string | No | Required unless batchId, packageId or metrcPackageLabel gives the product. Alone on a batch- or package-tracked product: an unfulfilled row that holds no stock (the remainder). A new productId on a stored row with a batch or package needs a batch or package of the new product too. Resolve via distru-search-products. |
| orderItems[]. | string | No | Fulfill from this batch. Batch-tracked products only. Resolve via distru-search-batches. |
| orderItems[]. | string | No | Sell this whole package; its quantity, product and batch come from it, so send it without batchId. Package-tracked products only. Resolve via distru-search-packages. |
| orderItems[]. | string | No | Sell this whole package by its Metrc label. With metrcManifestNumber (sent or stored): a package on that manifest, created in Distru at match when it isn't there yet (package null on distru-get-metrc-manifest; then productId is needed unless its Metrc item was mapped to a product before). Without: a package already in Distru on the license of the order's locationId. |
| orderItems[]. | string or number | No | In the product's unit type. Required to add a product-only or batch row; refused on a package or label row, which sells the whole package. |
| orderItems[]. | string or number | No | Unit price before price tiers, in the product's unit type. Required to add a row; a sample keeps it unless you send 0. Rows of one line share it. Never send a row's discounted price back as priceBase. Without the Edit Product Price permission a stored row's priceBase can't change, and a new row, or one changing product, takes the product's price (the error names it). |
| orderItems[]. | enumAUTOOVERRIDENONE | No | AUTO (default) applies the best matching tier and locks its current version, so the row then reads OVERRIDE; OVERRIDE locks priceTierId; NONE applies none. A stored row keeps its tier unless this is sent. Tiers apply only once the order has a customer, and are picked on the line's total across its rows. |
| orderItems[]. | string | No | With priceTierMode OVERRIDE only. A row already locked to this tier keeps its version. Resolve via distru-search-price-tiers. |
| orderItems[]. | string | No | Where this row's stock is held; a new row defaults to the order's locationId. Resolve via distru-search-locations. |
| orderItems[]. | boolean | No | Sample: no tax. Its price is still priceBase; send 0 only to give it free. |
| orderItems[]. | string | No | "" clears it. |
| orderCharges | object[] or null | No | Order-level charges, discounts and taxes: a preset (chargePresetId) or a custom one (name, type, unitType, and percent or price). On UPDATE the complete list: stored charges left out are deleted; [] removes them all. Omitted or null leaves the charges as they are. Read current rows with distru-get-sales-order first (includeOrderCharges). |
| orderCharges[]. | string | No | UPDATE only: a charge already on the order; only the fields sent change. Omit to add a charge. Resolve via distru-get-sales-order (includeOrderCharges). |
| orderCharges[]. | string | No | A charge preset; it sets name, type and the amount, so send it alone: unitType, percent and price are refused unless the preset allows inline edits. Can't change once the charge exists. Resolve via distru-search-lookups (type CHARGE_PRESET). |
| orderCharges[]. | string | No | |
| orderCharges[]. | enumCHARGEDISCOUNT | No | Forced to CHARGE with taxId. |
| orderCharges[]. | enumPERCENTPRICE | No | |
| orderCharges[]. | string or number | No | Percent of the order subtotal for unitType PERCENT, e.g. 10. A custom charge keeps the sign sent, whatever its type: negative for a DISCOUNT, e.g. -10. With chargePresetId, only to override a preset that allows inline edits, and positive. |
| orderCharges[]. | string or number | No | Flat amount for unitType PRICE. A custom charge keeps the sign sent, whatever its type: negative for a DISCOUNT. With chargePresetId, only to override a preset that allows inline edits, and positive. |
| orderCharges[]. | string or null | No | Makes the charge a tax. Not with chargePresetId. Resolve via distru-search-lookups (type TAX). Send null to clear it. |
| customFields | object[] | No | Only the fields listed change. Required custom fields must be set, on update too, while still blank. |
| customFields[]. | string | Yes | Resolve via distru-search-custom-fields (entityType SALES_ORDER). |
| customFields[]. | string or string[] | Yes | TEXT: the text. DROPDOWN: the option name. CHECKBOX: an array of option names. DATE: YYYY-MM-DD, company timezone. "" or [] clears the field. |
Output
This tool returns one of 2 shapes, depending on its inputs.
Presence on a nested field assumes its parent exists.
Result with salesOrder
| Field | Type | Presence | Description |
|---|---|---|---|
| salesOrder | object | Always | |
| salesOrder. | string | Always | |
| salesOrder. | object[] | Always | |
| salesOrder. | object | Always | |
| salesOrder. | string | Always | |
| salesOrder. | string | Always | |
| salesOrder. | enumCHECKBOXDATEDROPDOWNTEXT | Always | |
| salesOrder. | string | Can be null | |
| salesOrder. | string | Always | |
| salesOrder. | string | Always | |
| salesOrder. | string | Always | |
| salesOrder. | string | Always | |
| salesOrder. | string | Always | |
| salesOrder. | string | Always | |
| salesOrder. | string | Always | |
| salesOrder. | string | Can be null | |
| salesOrder. | string | Always | |
| salesOrder. | string | Always | |
| salesOrder. | string | Can be null | |
| salesOrder. | string | Can be null | |
| salesOrder. | string | Always | |
| salesOrder. | string | Can be null | |
| salesOrder. | string | Can be null | |
| salesOrder. | object | Null or absent | |
| salesOrder. | string | Always | |
| salesOrder. | string | Null or absent | |
| salesOrder. | object | Can be null | |
| salesOrder. | string | Always | |
| salesOrder. | object | Always | |
| salesOrder. | string | Always | |
| salesOrder. | object | Can be null | |
| salesOrder. | string | Always | |
| salesOrder. | string | Always | |
| salesOrder. | string | Always | |
| salesOrder. | object | Can be null | |
| salesOrder. | string | Always | |
| salesOrder. | string | Always | |
| salesOrder. | string | Always | |
| salesOrder. | object | Can be null | |
| salesOrder. | string | Always | |
| salesOrder. | string | Always | |
| salesOrder. | string | Always | |
| salesOrder. | object | Can be null | |
| salesOrder. | string | Always | |
| salesOrder. | string | Always | |
| salesOrder. | object | Can be null | |
| salesOrder. | string | Always | |
| salesOrder. | string | Always | |
| salesOrder. | object | Can be null | |
| salesOrder. | string | Always | |
| salesOrder. | string | Always | |
| salesOrder. | string | Always | |
| salesOrder. | object[] | Always | |
| salesOrder. | string | Always | |
| salesOrder. | string | Always | |
| salesOrder. | string | Can be null | |
| salesOrder. | string | Always | |
| salesOrder. | string | Always | |
| salesOrder. | boolean | Always | |
| salesOrder. | string | Can be null | |
| salesOrder. | string | Can be null | |
| salesOrder. | string | Can be null | |
| salesOrder. | object | Always | |
| salesOrder. | string | Always | |
| salesOrder. | string | Always | |
| salesOrder. | object | Always | |
| salesOrder. | string | Always | |
| salesOrder. | string | Always | |
| salesOrder. | object | Can be null | |
| salesOrder. | string | Always | |
| salesOrder. | string | Always | |
| salesOrder. | object | Can be null | |
| salesOrder. | string | Always | |
| salesOrder. | string | Always | |
| salesOrder. | object | Can be null | |
| salesOrder. | string | Always | |
| salesOrder. | string | Always | |
| salesOrder. | enumAUTONONEOVERRIDE | Null or absent | |
| salesOrder. | integer | Always | Rows with the same lineGroup are one line: same product, batch, location, priceBase, sample flag and tier (and THC when the company sells by potency), e.g. one row per package and the unfulfilled remainder. Numbered from 1 in row order on this order only. |
| salesOrder. | object | Null or absent | |
| salesOrder. | string | Always | |
| salesOrder. | string | Always | |
| salesOrder. | object | Always | |
| salesOrder. | enumAMOUNT_OFFFLAT_PRICEPERCENT_OFF | Always | |
| salesOrder. | string | Can be null | |
| salesOrder. | boolean | Always | |
| salesOrder. | object[] | Always | |
| salesOrder. | string | Always | |
| salesOrder. | string | Always | |
| salesOrder. | string | Always | |
| salesOrder. | string | Always | |
| salesOrder. | string | Can be null | |
| salesOrder. | string | Always | |
| salesOrder. | boolean | Always | |
| salesOrder. | string | Can be null | Manifest number of the matched compliance transfer; null when unmatched. |
Result with id
| Field | Type | Presence |
|---|---|---|
| id | string | Always |
What the AI reads
Creates, updates or deletes one sales order: a sale to a customer with line items, order-level charges or discounts and custom fields. Stock is held from PROCESSING on, only by lines fulfilled from a batch or package; PENDING and CANCELED hold none. READY_TO_SHIP and later need a customer and every batch- or package-tracked line fulfilled. A line with only a product holds no stock (the company's auto-fulfill setting fills it at PROCESSING): to sell from a location, give each line a batch stocked there (distru-search-batches) or a package. A package line sells the whole package: pass packageId or metrcPackageLabel, never quantity. One product line fulfilled from several packages is several rows sharing product and priceBase (lineGroup in the output); see orderItems. To match an outgoing Metrc manifest set metrcManifestNumber: the package lines must be the manifest's packages (or a subset when the company allows partial matching); packages not yet in Distru are created. Matching can't be undone here; a matched order can't go back to PENDING or to CANCELED and keeps its package lines. CREATE adds preset charges whose auto-apply tags match the products. Invoices: distru-create-invoice; an existing invoice follows line price changes and quantity decreases. DELETE removes the order for good with its lines, charges and shipments and releases its stock; refused for merged orders, orders with returns, orders matched to a transfer and orders with an invoice (delete the invoices first with distru-delete-invoice, or set status CANCELED, which voids them). CREATE and UPDATE return the order as distru-get-sales-order does with includeOrderItems, includeOrderCharges and includeOrderItemPriceTiers; DELETE returns its id. Sparse update: on UPDATE only the fields passed change; orderItems and orderCharges, when passed, replace the whole list — read the order with distru-get-sales-order first and resend every line you keep.