Assembly

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.

post/public/v1/assemblies

Request body

action'CREATE' | 'UPDATE' | 'DELETE' required

CREATE, UPDATE, or DELETE. Required. DELETE removes the assembly and all of its outputs, inputs, and costs.

custom_dataobject

A map of custom field IDs to their values for this assembly. Use GET /public/v1/custom-fields?parent_object=assembly to retrieve the available fields, their IDs, and their types. The value format depends on the field's type: a text field takes a string, a date field takes a full ISO8601 datetime, and a checkbox field takes an array of its selected options. On update this replaces the whole custom-data map, so send every field you want to keep.

descriptionstring

A free-text description for this assembly. Editable at any status.

estimated_start_datetimestring

When this assembly is planned to start, as an ISO 8601 datetime (e.g. 2026-08-19T00:00:00Z). Optional; omit to leave it unset.

estimated_work_hoursinteger

The whole-hours portion of the estimated work time; must be 0 or greater. Combine with estimated_work_minutes for the full estimate (e.g. 1 hour 30 minutes is estimated_work_hours 1, estimated_work_minutes 30). Editable at any status.

estimated_work_minutesinteger

The minutes portion of the estimated work time; must be 0 or greater. Pairs with estimated_work_hours (see above). Editable at any status.

idstring

The assembly to update or delete. Required for UPDATE and DELETE; omit for CREATE.

owner_idstring

The ID of the user that owns this assembly. Optional. Editable at any status.

status'PENDING' | 'COMPLETED'

The assembly's lifecycle state, PENDING or COMPLETED (SCREAMING_CASE). Required when creating. PENDING claims/reserves ingredient inventory but consumes nothing; COMPLETED consumes the inputs and produces the outputs into inventory, and requires every output to be COMPLETED. Creating directly as COMPLETED performs that consumption immediately. Once COMPLETED an assembly cannot be moved back to PENDING and only a few fields remain editable (see the endpoint description).

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.