Create Co-Manufacturing Chain
POST/api/manufacturing/chains
Create a complete multi-stage co-manufacturing chain in one atomic transaction: the finished good (created or reused), a lot-tracked work-in-progress product for every intermediate stage, one bill of materials per stage (activated), and - optionally - a set of chained draft manufacturing orders whose destinations flow from each stage's site to the next, ending at your warehouse.
Stages are ordered first to last (max 5). The first stage must include components (the recipe per output unit); every stage except the last must include wip_product (the storable intermediate it outputs). Later stages consume the prior stage's WIP product (1:1 by default; override with input_quantity).
Per stage: production_method (outsourced default, or in_house). Outsourced stages require contractor_supplier_id and accept service_fee_rate (per-unit tolling rate; falls back to the contractor's default) OR service_fee_amount (flat total - never both), plus cost_basis (toll or hybrid). In-house stages require warehouse_id (the facility they run in) and carry no contractor fee. Every stage accepts expected_yield_percent, expects_inbound_freight (a middle-mile freight bill is captured at receipt), and scheduled_start / scheduled_end.
Quantities follow yields: with create_draft_mos, each stage's planned quantity is the run quantity reduced by the expected yields of the stages before it - downstream orders plan for what will actually arrive.
Units: output_uom_id sets the unit every output and hand-off is expressed in; products minted by the chain stock in that unit. Recipe components default to their own stock unit, with optional per-line uom_id and expected_scrap_percent.
Finished good: pass either finished_product_id (existing product) or finished_product (sku + name to create). Lot tracking is enabled on the finished good and all minted WIP products automatically; component products are flipped to lot-tracked when enable_lot_tracking is true.
internal_reference and priority apply to every draft order (the reference gains a per-stage suffix). The response warnings array lists lot-traceability gaps detected while activating the chain's BOMs. The whole request is all-or-nothing: any failure rolls back every product, BOM, and order.
Replacing an existing recipe: when the finished good already has a live single-stage recipe, pass source_bom_id to split it across vendors instead of being blocked. Send that recipe's component lines as stage 1's components (adjust them freely - the original is never edited in place). On success the source recipe is archived, draft manufacturing orders that referenced it move to the chain's final stage - they still produce the same finished good, now fed by the chain - and orders already past draft keep running the old recipe untouched. Call GET /api/manufacturing/chains/supersede-preview/{bom} first to show what will change. Without source_bom_id, a finished good that already has a live recipe is rejected with 422.
supersede_mode decides what happens to that source recipe. supersede (the default) archives it and moves its draft orders onto the chain. keep leaves it live instead - activating the chain's final recipe already makes the chain the default, so the old recipe stays available for a direct single-stage run and keeps its own orders.
manufacturing:writeGrant this scope to your token under Settings → Developer → Personal Access Tokens.
Components on any stage. stages[].components is accepted for every stage, not only the first. Stage 1's list is the raw-ingredient recipe (required). A later stage always consumes the previous stage's output — added automatically, do not list it — and its components are the goods YOU supply directly to that vendor, typically packaging shipped to the co-packer that uses it. Materials the contractor owns are not modelled: they are covered by the service fee, or by their supplier price under the hybrid cost basis.
Request
Responses
- 201
- 401
- 403
- 422
- 429
Created
Response Headers
Unauthenticated — the bearer token is missing, revoked, expired, or malformed. Never retry automatically; fix the credential. See the Errors guide.
Forbidden — the token lacks a required scope, the endpoint is not available to API tokens, or the user behind the token lacks the permission. A human must adjust the token scopes or user permissions; do not retry.
Unprocessable Entity
Response Headers
Rate limited — platform limit is 1,000 requests/min; individual tokens may carry lower limits. Honor the Retry-After header before retrying. See the Rate Limits guide.