Create, update or delete a purchase order

distru-mutate-purchase-orderWriteQuickBooks

Creates, updates or deletes one purchase order. Reaches QuickBooks when your settings sync purchases: saving pushes an order, never a draft, when they sync its status and its total isn't negative (a zero total needs its own setting), and deleting removes its bill.

Inputs

Every tool also takes the common inputs.

FieldTypeRequiredDescription
actionenum
CREATEUPDATEDELETE
Yes
idstringNoRequired for UPDATE and DELETE. Resolve via distru-search-purchase-orders (status DRAFT for a draft).
supplierIdstringNoRequired for CREATE unless status DRAFT. Supplier company. Changes only while the purchase is a draft, the UPDATE that finishes it included; send supplierLocationId with it, or the old supplier's location stays. Resolve via distru-search-companies.
intakeLocationIdstringNoRequired for CREATE unless status DRAFT, and to add lines: new lines are received here. Changes only while the purchase is a draft, the UPDATE that finishes it included; a draft's lines move with it. Resolve via distru-search-locations.
statusenum
DRAFTPENDINGPROCESSINGDELIVERINGPARTIALLY_RECEIVEDCOMPLETED
NoCREATE defaults to PENDING. DRAFT: still being filled in; CREATE needs only the status and required custom fields. An UPDATE to another status finishes it, and the fields CREATE requires are then required. Nothing goes back to DRAFT. PENDING: placed, waiting on the supplier. PROCESSING: the supplier is preparing it. DELIVERING: on its way. These three leave stock alone. PARTIALLY_RECEIVED: part arrived; every line needs receivedQuantity, which is added to stock; not for package-tracked products. COMPLETED: everything arrived and is added to stock; package-tracked products complete only by matching a Metrc manifest. A received purchase cannot go back to PENDING, PROCESSING or DELIVERING.
orderDatetimestringNoWhen the purchase was ordered. CREATE defaults to now; a draft gets it when finished. ISO 8601 with a UTC offset, e.g. "2026-09-01T00:00:00-07:00"; the company timezone is on distru-get-me.
dueDatetimestringNoWhen payment is due. A non-draft CREATE, or finishing a draft, defaults to orderDatetime plus the company's default purchase payment term, and needs it when the company has none. ISO 8601 with a UTC offset, e.g. "2026-09-01T00:00:00-07:00"; the company timezone is on distru-get-me.
billingLocationIdstringNoA non-draft CREATE, or finishing a draft, defaults to the company's default purchase billing location, else intakeLocationId. Resolve via distru-search-locations.
supplierLocationIdstringNoThe supplier's location the purchase ships from. Resolve via distru-get-company on the supplier.
ownerIdstringNoResolve via distru-search-users.
descriptionstringNoNotes. CREATE defaults to the company's default purchase description.
metrcManifestNumberstringNoIncoming Metrc manifest to match this purchase with; completes it and receives the packages. Every accepted package on the manifest needs one line, identified by metrcPackageLabel. intakeLocationId must be on the license that received it. Not on a draft: finish it first. Resolve via distru-get-metrc-manifest.
orderItemsobject[] or nullNoRequired for CREATE unless status DRAFT. On UPDATE the complete list: stored lines left out are deleted, and [] is refused unless the purchase is a draft; send a stored line with just its id to keep it unchanged. Omitted or null leaves the lines as they are. Read current rows with distru-get-purchase-order first (includeOrderItems). Not allowed on UPDATE once the purchase is matched to a compliance transfer.
orderItems[].idstringNoUPDATE only: a line already on the purchase; only the fields sent change. Omit to add a line. Resolve via distru-get-purchase-order (includeOrderItems).
orderItems[].productIdstringNoResolve via distru-search-products. With metrcPackageLabel, omit it when the manifest package shows package.product (that product is used, a different one is rejected) or productMostRecentlyMappedToMetrcItem.
orderItems[].batchIdstringNoRequired for batch-tracked products (inventoryTrackingMethod BATCH), except on a draft until it is finished; product-tracked ones use their default batch, package-tracked ones get a package when received. Resolve via distru-search-batches (filter by productIds).
orderItems[].quantitystring or numberNoIn the product's unit type. Not with metrcPackageLabel: it comes from the manifest.
orderItems[].pricestring or numberNoCost per unit of the product's unit type, not the line total. Required for CREATE.
orderItems[].receivedQuantitystring or numberNoReceived so far, in the product's unit type. Required on every line with status PARTIALLY_RECEIVED, not allowed otherwise.
orderItems[].metrcPackageLabelstringNoWith metrcManifestNumber: the package's label (tag) on the manifest. The line quantity comes from the manifest, converted to the product's unit type.
orderChargesobject[] or nullNoOrder-level charges and discounts: a preset (chargePresetId) or a custom one (name, type, unitType, and percent or price). Taxes not supported. 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-purchase-order first (includeOrderCharges). Not allowed on UPDATE once the purchase is matched to a compliance transfer.
orderCharges[].idstringNoUPDATE only: a charge already on the purchase; only the fields sent change. Omit to add a charge. Resolve via distru-get-purchase-order (includeOrderCharges).
orderCharges[].chargePresetIdstringNoA 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. Resolve via distru-search-lookups (type CHARGE_PRESET).
orderCharges[].namestringNo
orderCharges[].typeenum
CHARGEDISCOUNT
No
orderCharges[].unitTypeenum
PERCENTPRICE
No
orderCharges[].percentstring or numberNoPercent 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[].pricestring or numberNoFlat 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.
customFieldsobject[]NoOnly the fields listed change. Required custom fields must be set, on update too, while still blank.
customFields[].customFieldIdstringYesResolve via distru-search-custom-fields (entityType PURCHASE_ORDER).
customFields[].valuestring or string[]YesTEXT: 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 purchaseOrder

FieldTypePresenceDescription
purchaseOrderobjectAlways
purchaseOrder.idstringAlways
purchaseOrder.customFieldsobject[]Always
purchaseOrder.customFields[].customFieldobjectAlways
purchaseOrder.customFields[].customField.idstringAlways
purchaseOrder.customFields[].customField.namestringAlways
purchaseOrder.customFields[].customField.fieldTypeenum
CHECKBOXDATEDROPDOWNTEXT
Always
purchaseOrder.customFields[].valuestringCan be null
purchaseOrder.purchaseNumberstringAlways
purchaseOrder.statusenum
COMPLETEDDELIVERINGDRAFTPARTIALLY_RECEIVEDPENDINGPROCESSING
Always
purchaseOrder.paymentStatusenum
NOT_PAIDOVER_PAIDPAIDPARTIALLY_PAID
Always
purchaseOrder.totalstringAlways
purchaseOrder.totalChargesstringAlways
purchaseOrder.paidstringAlways
purchaseOrder.orderDatestringCan be null
purchaseOrder.dueDatestringCan be null
purchaseOrder.createdDatestringAlways
purchaseOrder.updatedDatestringAlways
purchaseOrder.descriptionstringCan be null
purchaseOrder.urlstringAlways
purchaseOrder.supplierobjectNull or absent
purchaseOrder.supplier.idstringAlways
purchaseOrder.supplier.namestringNull or absent
purchaseOrder.ownerobjectCan be null
purchaseOrder.owner.idstringAlways
purchaseOrder.owner.profileobjectAlways
purchaseOrder.owner.profile.fullNamestringAlways
purchaseOrder.intakeLocationobjectCan be null
purchaseOrder.intakeLocation.idstringAlways
purchaseOrder.intakeLocation.namestringAlways
purchaseOrder.intakeLocation.addressstringAlways
purchaseOrder.billingLocationobjectCan be null
purchaseOrder.billingLocation.idstringAlways
purchaseOrder.billingLocation.namestringAlways
purchaseOrder.billingLocation.addressstringAlways
purchaseOrder.supplierLocationobjectCan be null
purchaseOrder.supplierLocation.idstringAlways
purchaseOrder.supplierLocation.namestringAlways
purchaseOrder.supplierLocation.addressstringAlways
purchaseOrder.qbBillIdstringCan be null
purchaseOrder.qbSyncStatusenum
DELETED_IN_QBOERRORNOT_SYNCEDPARTIALLY_SYNCEDPENDINGSYNCED
Can be null
purchaseOrder.orderItemsobject[]Always
purchaseOrder.orderItems[].idstringAlways
purchaseOrder.orderItems[].quantitystringAlways
purchaseOrder.orderItems[].receivedQuantitystringCan be null
purchaseOrder.orderItems[].pricestringAlways
purchaseOrder.orderItems[].productobjectAlways
purchaseOrder.orderItems[].product.idstringAlways
purchaseOrder.orderItems[].product.namestringAlways
purchaseOrder.orderItems[].product.unitTypeobjectAlways
purchaseOrder.orderItems[].product.unitType.idstringAlways
purchaseOrder.orderItems[].product.unitType.namestringAlways
purchaseOrder.orderItems[].batchobjectCan be null
purchaseOrder.orderItems[].batch.idstringAlways
purchaseOrder.orderItems[].batch.namestringAlways
purchaseOrder.orderItems[].locationobjectCan be null
purchaseOrder.orderItems[].location.idstringAlways
purchaseOrder.orderItems[].location.namestringAlways
purchaseOrder.orderItems[].packageobjectCan be null
purchaseOrder.orderItems[].package.idstringAlways
purchaseOrder.orderItems[].package.metrcLabelstringAlways
purchaseOrder.orderChargesobject[]Always
purchaseOrder.orderCharges[].idstringAlways
purchaseOrder.orderCharges[].namestringAlways
purchaseOrder.orderCharges[].typestringAlways
purchaseOrder.orderCharges[].unitTypestringAlways
purchaseOrder.orderCharges[].percentstringCan be null
purchaseOrder.orderCharges[].pricestringAlways
purchaseOrder.orderCharges[].isTaxbooleanAlways
purchaseOrder.complianceManifestNumberstringCan be nullManifest number of the matched compliance transfer; null when unmatched.

Result with id

FieldTypePresence
idstringAlways
What the AI reads

Creates, updates or deletes one purchase order: a purchase of inventory from a supplier, with line items, order-level charges and custom fields. Stock changes only once it is PARTIALLY_RECEIVED or COMPLETED (UPDATE status COMPLETED receives everything). For a purchase still being filled in, CREATE status DRAFT; an UPDATE to another status finishes it. Payments: distru-create-purchase-payment. When the company syncs purchases to QuickBooks, a CREATE or UPDATE that leaves the purchase in one of the company's QuickBooks sync statuses (by default only COMPLETED) creates or updates its QuickBooks bill, and the vendor when missing. To import an incoming Metrc manifest, CREATE with metrcManifestNumber and one line per accepted package (metrcPackageLabel), read from distru-get-metrc-manifest (includeDeliveries); the purchase is created COMPLETED and receives the packages. Otherwise CREATE, or the UPDATE that finishes a draft, adds the preset charges whose auto-apply tags match the products and aren't on it yet. On UPDATE, setting metrcManifestNumber matches the purchase with an incoming Metrc manifest and completes it: a stored line sent with its id and a metrcPackageLabel keeps its price, and its product unless the package is already in Distru as another product; once matched to a compliance transfer, only header fields change. DELETE removes the purchase for good (purchases have no canceled status; drafts included) with its lines, charges, tasks, every payment (voided ones included) and the AI purchase intake that created it, and deletes its QuickBooks bill and bill payments. Stock it received is taken back out first, so DELETE is refused when that stock was already sold, transferred, adjusted or assembled; purchases synced to Metrc are refused too. CREATE and UPDATE return the purchase as distru-get-purchase-order does with includeOrderItems and includeOrderCharges; DELETE returns its id. Sparse update: on UPDATE only the fields passed change; orderItems and orderCharges, when passed, replace the whole list.