Inbound deliveries and expected stock
An inbound notice is a plan. The warehouse operator separately confirms arrival, inspection and the physical receipt. An owner's ERP cannot prove work in the partner's warehouse. In an own warehouse both roles belong to the same organization, but remain separate actions and scopes.
| Method and path | Scope | Purpose |
|---|---|---|
| GET /v1/inbounds | inbound:read | Current authorized notices and quantities |
| GET /v1/inbounds/options | inbound:read | Authorized stock articles, warehouses, operators and destinations |
| GET /v1/inbounds/commands/{idempotencyKey} | inbound:read | Recover a command receipt |
| POST /v1/inbounds/commands | inbound:announce | Owner planning and expected allocations |
| POST /v1/inbounds/commands/preview | inbound:announce + inbound:read | Check owner command without saving |
| POST /v1/inbounds/receiving-commands | inbound:receive | Operator confirmations and physical receipts |
| POST /v1/inbounds/receiving-commands/preview | inbound:receive + inbound:read | Check operator command without saving |
#Identity and read contract
List with limit=1..100 (default 50), then send after unchanged from next. Omit after on the first request. Lists are current summaries, not frozen snapshots: details_included=false deliberately omits detailed child arrays. Pass inbound_id to read the complete notice, quantities, allocations and received claims. An empty details array in a summary is not proof that the case has no lines.
Options additionally accept role=owner|operator (default owner) and search up to 200 characters. Use the returned stock identity, unit, warehouse and operator together; do not substitute a partner organization or guess an article by SKU. Each call checks current ownership, membership and fulfillment releases again. Selecting a Shopify destination only identifies the rule's target; it does not turn on stock publishing.
#Owner commands
Every command contains a UUID idempotency_key and an operation object with kind. Client-selected case and line UUIDs identify the intended new records. Later case changes require inbound_id and its current integer expected_version.
| kind | Required business inputs |
|---|---|
| announce | inbound_id, operator_organization_id, warehouse_id, reference, destination_id or null, customer_eta or null, rule, lines |
| amend | inbound_id, expected_version, reference, customer_eta, rule |
| amend_line | inbound_id, expected_version, line_id, quantity, reason |
| cancel | inbound_id, expected_version, reason |
| set_default | destination_id, expected_version (0 for a missing default), days or null |
| allocate_expected | inbound_id, expected_version, line_id, allocation_id, order_item_id, quantity |
| release_expected | inbound_id, expected_version, allocation_id, reason |
Each announced line has id, stock_item_id, unit: "piece" and positive decimal-string quantity. Duplicate stock articles or line identities in one notice are rejected. Expected allocations reference an order item authorized for this API connection; an unrelated shop order does not become readable or writable through a guessed ID.
#ETA and advance-availability rules
An ETA is { "date": "2026-11-12", "time_zone": "Europe/Berlin" }. customer_eta is an expectation. Only the operator's separately confirmed ETA can contribute expected availability. Editing the customer's ETA removes the previous operator confirmation.
rule has one of three explicit forms:
{ "mode": "inherit" }follows the current default for this owner's destination.{ "mode": "disabled" }contributes no expected availability.{ "mode": "override", "days": 3 }starts three local calendar days before confirmed arrival. Zero means the arrival day; it does not mean disabled.
A missing default or ETA contributes nothing. Overdue unconfirmed supply offers no new quantity. The scheduled reconciliation also handles day changes without a person editing the notice; it shares the bounded delivery scheduler and is not a real-time guarantee. Existing promises remain visible for review instead of being silently forgotten. These expected quantities are never pickable physical stock and do not automatically alter a shop's available quantity.
#Operator commands
| kind | Required business inputs in addition to inbound_id and expected_version |
|---|---|
| confirm | confirmed_eta or null |
| arrive | occurred_at with timezone offset |
| receive | line_id, quantity, location_id, condition_id, received_at, batch or null, accept_overdelivery |
| reject | line_id, quantity, reason |
| close | accept_shortage |
| convert_expected | claim_id, expected_balance_version, target_location_id, released_condition_id, reason |
Only the actual operator organization can perform physical actions. A receipt books stock once, preserves condition and reduces the outstanding expected quantity atomically. If expected demand was already allocated, the received goods remain exclusively held until the authorized conversion creates a real reservation. Conversion transfers the claim; it does not create another stock receipt or subtract the same binding twice.
#Preview, replay and recovery
The preview uses the real command validation and rolls the transaction back. Its saved=false, already_applied, before, after and before_fingerprint describe the checked state; it is not a saved physical receipt. Execute still needs the current version. A committed result contains event_id, operation kind, inbound_id, version and an optional physical stock_event_id.
After a timeout, keep the original input, version and key. Read the receipt or retry exactly. A reused key with changed input conflicts. A receipt reader returning null does not authorize duplicating an uncertain booking. Read rights are independent of write rights; grant the appropriate read scope if the integration must recover and reconcile. Test keys return no live warehouse data and cannot perform physical or planning writes against live cases. Use the isolated simulator for complete write scenarios.
#Unit contract
The public API uses piece consistently in notices, options, return sources, custody and preview quantities. The transport explicitly translates this spelling to the existing native piece unit before validating and storing the same command. Quantities and idempotency keys are unchanged; no package, mass or material-unit conversion occurs. Replays and previews use the identical translation. Historical records using another base unit fail with HTTP 422 unit_unsupported; rows are never silently dropped or rounded. Native workspace and AI tools retain their existing unit labels. Preview fingerprints remain the original server state proof, not a client-computed display hash.
#Goods after access withdrawal
GET /v1/inbounds/custody reads only physical holdings still handled by the caller's own warehouse after partnership access is withdrawn. Parameters: optional entity_id, after and limit (1–50, default 20). The operator may send handoff_recovery to the receiving endpoint with the case ID, version, explicitly confirmed quarantine condition and reason. Existing order reservations stay on their original warehouse/dispatch recovery path. A quarantine handoff neither sells nor ships goods.
#Global list selection
GET /v1/inbounds applies search, role=all|owner|operator, status=announced|confirmed|arrived|closed|cancelled|recovery, 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; % 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/inbounds.md