Physical kits and warehouse manufacturing
Manufacturing consumes actual eligible component stock and records actual finished goods. It uses the same services as the warehouse workspace, MCP and Meyki. A virtual set has no physical header stock. Receiving a purchased finished kit does not consume local components.
| Method and path | Required scopes | Purpose |
|---|---|---|
| GET /v1/manufacturing | inventory:read + products:read | Current authorized manufacturing records |
| GET /v1/manufacturing/options | inventory:read + products:read | Published physical recipes, free sources and explicit destinations/conditions |
| GET /v1/manufacturing/history | inventory:read + products:read | All actual dismantling and recovered/lost component records |
| POST /v1/manufacturing/commands | inventory:assemble + products:read | Record a physically confirmed operation |
| POST /v1/manufacturing/commands/preview | inventory:assemble + inventory:read + products:read | Validate the actual booking path without saving |
| GET /v1/manufacturing/commands/{idempotencyKey} | inventory:read + products:read | Recover the original receipt of this API connection |
All product quantities in this domain are exact whole-piece strings, from "1" through "999999999". Zero is allowed only where explicitly documented. Component records use unit: "piece". No material-unit or recipe-factor conversion is inferred.
#Select actual identities
List manufacturing with limit=1..50 (default 20), then send after from next. Select manufacturing_id for one record. An operator uses its own offered manufacturing identity; a goods owner receives a separate neutral public identity. Do not exchange a public owner reference for the partner's warehouse identity.
Options accept owner_organization_id, definition_id, warehouse_id, search, after, source_after and limit=1..100 (default 50). Select a definition and warehouse to obtain sources. Each source carries its current version, exact quantity and allowed_part_ids. Follow definition next and source_next independently. An empty source page does not authorize substituting reserved stock or an unknown condition.
For an existing record, outputs[].balances identifies actual original output lots and positions that can be considered for dismantling. removable_quantity is a current choice aid; the writer rechecks every binding. outputs[].condition_name is the original output classification, while a balance's current condition can differ.
The workspace includes the first 20 disassemblies. Follow disassembly_next through /manufacturing/history?manufacturing_id=...&after=... with limit=1..100. Its own next advances all records. Each record reports actual time, expected/recovered/lost component quantities and conditions. Operator positions and reasons are not exposed to a foreign goods owner.
#Shared command envelope
Every command contains exactly idempotency_key and operation. Every operation includes kind, a human-readable reason (1–500 characters) and physically_confirmed: true. The physical action must actually have occurred; an ERP status or AI statement alone is not evidence of real output.
| kind | Additional fields |
|---|---|
| assemble | manufacturing_id, owner_organization_id, definition_id, expected_definition_revision, warehouse_id, output_stock_item_id or null, quantity, components, reference, output |
| consume | Same start fields as assemble, without output |
| output | manufacturing_id, expected_version, quantity, output or null, close_remaining_as_scrap |
| disassemble | output_id, source_balance_id, expected_balance_version, quantity, recovered_components, confirm_component_shortage, occurred_at |
| recovery_output | manufacturing_id, expected_version, positive quantity, output |
A start accepts at most 250 selected source entries across the published recipe's at most 100 slots. Each entry is {definition_part_id, stock_item_id, balance_id, expected_version, quantity}. Select each balance once per slot; repeated slots may share one balance using the same version. Their aggregate quantity is checked and consumed once. Every slot must receive exactly its frozen factor multiplied by the intended finished quantity. Positions containing any reservation or exclusive hold are conservatively unavailable for this operation.
output is {location_id, condition_id, received_at, batch}. The timestamp includes a timezone offset and batch is a string up to 200 characters or null. output_stock_item_id: null resolves or prepares the unique correct physical product identity for the selected owner and warehouse; it never chooses a different SKU.
assemble is an atomic physical-kit operation. consume works for physical kits and production bills of materials: it freezes actual consumption while creating no finished stock. New starts require the currently published definition, still-active native recipe and unchanged active physical variant mapping. Previously consumed work retains its original quantities and physical products after later catalog changes.
#Partial output and loss
output can record a positive partial quantity. It cannot exceed quantity - produced - scrapped from the original consumed record. A positive quantity requires an explicit output destination and known condition. Quarantine or blocked output is physically recorded and remains unavailable for sale. The published output eligibility policy governs later allocation; it does not automatically classify the receipt as released.
Set close_remaining_as_scrap: true only when the remaining consumed work actually became scrap. To record only remaining scrap, send quantity: "0" and output: null. Consumed input is never restored by this operation. A record allows up to 1000 output receipts. Finished goods are subsequently reserved and processed through the ordinary dispatch path; this service does not synthesize order workflow completion, refunds or carrier shipments.
Each recovered_components entry identifies one original definition_part_id and contains stock_item_id or null, actual whole-piece quantity, location_id, condition_id, and batch. Report every original slot exactly once. Positive recovered quantities require a known condition and actual location; zero requires all four target fields to be null. Recovery cannot exceed the proved original composition. Explicitly set confirm_component_shortage: true when anything is missing; lost amounts are recorded rather than received.
Dismantling requires the actual original manufacturing output lot. A purchased kit or newly received returned kit does not automatically prove its contents. Missing provenance produces operation_state_conflict; the current recipe cannot fill that gap. Proven quarantined goods can be physically dismantled without first declaring them sellable.
#Revoked access and recovery
Only the actual operator organization can book in its warehouse. An owner's ERP may read currently authorized partner evidence; it cannot impersonate the partner actor. Current key, connection, environment and creator rights are checked again on each authorized entrance. Test keys never read live manufacturing or perform real physical writes.
After partner access withdrawal, ordinary new manufacturing stops. recovery_output is restricted to the actual operator's already consumed historical work and its proved remaining output. It keeps the original owner/SKU and requires an explicitly known quarantine condition. It does not create a customer decision, permit sale, consume more inputs or restore raw goods. The actual output record carries recovery: true; the domain event uses operation: "recovery_output" with type production.output_recorded.
#Preview, retry and events
A preview executes the same validated booking path and rolls all changes back. saved: false, a fingerprint and expected effects are not a receipt. Generated identities of the discarded attempt are excluded. Preserve current versions, the exact final request and one idempotency key for execution.
After an uncertain response, find the original receipt. data: null is unknown, not proof of failure. Retry only the same key and exact body. A different API connection cannot adopt that key. A receipt records its original action; read current quantities separately before another action. No automatic undo is offered.
If the live API has since been disabled by the organization's entitlement or connection state, use the existing authorized workspace, AI read tools or data export to reconcile prior evidence. A denied key or subscription does not mean the earlier booking failed. Do not create another key or another physical booking to resolve uncertainty.
Opt-in events are kit.assembled, kit.disassembled, production.material_consumed, production.output_recorded and production.scrap_recorded. They carry exact strings and an explicit quantity_basis (finished_units, planned_finished_units, disassembled_units or scrapped_finished_units), unit: "piece", and owner-bound public manufacturing/receipt references. Current product and partnership visibility is checked before delivery. These events do not themselves publish shop inventory.
#Global list selection
GET /v1/manufacturing applies search, role=all|owner|operator, state=in_progress|completed|closed_with_scrap and mode=physical_kit|production_bom, sort=id|created_at|reference and direction=asc|desc to every currently authorized record before counting and cursor pagination. Search matches references without case sensitivity; manufacturing also matches the permitted article-name snapshot; % and _ are literal characters. total is the exact current filtered count, independent of the page size or cursor. It does not count hidden partner records.
Omitting the new fields retains the previous id ascending order. Date/reference sorts break ties by the same public identifier and direction. Continue with unchanged filters/sort and after=next. Changing a filter or sort starts again without after. An inaccessible, deleted or no-longer-matching date/reference anchor returns 409 resource_revision_conflict; restart the selection. These are current lists, not immutable stock snapshots: changes between calls can affect membership and order. The UI, MCP readers and integration profiles use this same contract.
Machine-readable version of this page: https://www.meykt.com/developers/manufacturing.md