Upsert an assembly
Create, update, or delete an assembly and its outputs, inputs, and costs in a single request.
Every row — the assembly and each nested output, input, and cost — carries a required action of CREATE, UPDATE, or DELETE. UPDATE and DELETE must include the row's id; CREATE omits it. DELETE on the assembly removes it along with all of its outputs, inputs, and costs. Updates are sparse: only the fields you send are changed. A nested row (output, input, or cost) you leave out entirely is left untouched — omission never deletes it; removing one always requires sending it with action DELETE. The whole request is applied atomically: if any row is rejected, none of the changes are saved.
How this moves inventory: while the assembly is PENDING, each fulfilled input (status PENDING or COMPLETED) claims specific on-hand inventory from its batch or package, and each DRAFT input reserves product-level quantity without committing a specific lot. Completing an output consumes its inputs and produces the output into inventory at its location_id — as a batch for batch-/product- tracked outputs, or as a new package for package-tracked (Metrc) outputs. Completing the whole assembly requires all of its outputs to be completed.
How this moves compliance: on a Metrc license, completing a package-tracked output (or a Metrc processing job) is pushed to Metrc as a side effect after the request commits. A 2xx therefore means the change was saved in Distru, not that Metrc has finished syncing — the created packages' Metrc identifiers may still be absent and the affected packages briefly flagged as syncing. Re-fetch the assembly with GET /public/v1/assemblies/{id} to observe the synced result. This endpoint supports Metrc and non-compliance (NONE) licenses only; BioTrack is not supported.
Only assemblies with creation_source=MANUALLY_CREATED (i.e. created via the Assembly form in Distru or via the API) can be modified or deleted by this endpoint; system-generated assemblies (SALES_ORDER, SPLIT_PACKAGE, LAB_TESTING) are rejected.
Metrc processing jobs: set metrc_processing_job.name and metrc_processing_job.type_id together to make the assembly a Metrc processing job. Both are required together, the license must be a Metrc license with processing-job capability, type_id must be the Metrc ID of an existing Metrc processing job type, and name must be non-empty and not already used by a processing job in Metrc. Once set, name and type_id are permanent — they cannot be changed on a later update; only notes and waste stay editable. metrc_processing_job.id in the response is the job's Metrc-assigned ID (set by Metrc once Distru creates the job there); it is read-only and null until then. Completing a processing job (setting status to COMPLETED) requires notes. waste is what Distru reports to Metrc when the job is finished (each quantity sent with its unit name); record it while the assembly is still PENDING — at the latest in the same request that completes it. Once the assembly is COMPLETED the waste fields are read-only.
Completed assemblies: once an assembly's status is COMPLETED, the only assembly-level fields you can still change are description, custom_data, estimated_work_hours, estimated_work_minutes, and owner_id; every other assembly field is read-only, and the assembly can be neither un-completed nor deleted. Its outputs and inputs are frozen — they cannot be edited or deleted. Costs behave differently: an existing cost on a completed output cannot be edited or deleted, but you can still add new costs to that output. Completing an assembly requires all of its outputs to be completed. For a Metrc processing job, packages (inputs) cannot be added or removed once any output is completed; to delete such an assembly, finish the job in Metrc and Distru removes it automatically about 30 minutes later.
Required permission: assemblies_permissions_create to create, assemblies_permissions_edit to update, assemblies_permissions_delete to delete.
Request body
Example request
{
"custom_data": {
"101": "Some text value",
"102": "2026-08-18T00:00:00.000-07:00",
"103": [
"Option A",
"Option B"
]
}
}Response
The updated assembly
Changes
No recorded changes to this endpoint across all 1 revision of this API.