Receive Shipment
POST/api/inbound-shipments/receive
Receive goods against a purchase order shipment. Creates a receipt record and triggers inventory movements.
Authentication: Requires Bearer token.
Async behavior (SKU-8063):
- By default, this endpoint dispatches the receive to a background job chain and returns 202 Accepted with
data.tracked_job_log_id. The frontend should open the global job tray (notifyJobStarted) and watch lastCompletedJob to refresh. - Pass
?async=0to force the legacy synchronous response (200 with the receipt resource). - The async path is only taken when the payload is ad-hoc eligible: requires
purchase_order_id, and rejects any payload that includesunexpected_items,inbound_shipment_id, or negativereceipt_lines[].quantity. Ineligible payloads silently fall back to the sync path. - 409 Conflict is returned when a ProcessPurchaseOrderReceiptJob is already in flight (PENDING or PROCESSING) for the same
purchase_order_id— the caller should tell the user to track progress in the job tray instead of retrying.
Fields:
- purchase_order_id (conditional): Required if purchase_order_shipment_id is not provided. Required for the async path.
- purchase_order_shipment_id (optional): Specific shipment ID to receive. If omitted, receives for the entire PO
- received_at (required): Date/time of receipt
- warehouse_id (optional): Override destination warehouse
- shipment_date (optional): Used if a new shipment needs to be created automatically
- shipping_method_id (optional): Shipping method for auto-created shipment
- tracking (optional): Tracking number for auto-created shipment, max 255 characters
- inbound_shipment_id (optional, exists:inbound_shipments,id): Route the whole receive against this specific inbound shipment. Restricts delegation to that shipment and over-receives it past its planned capacity if the received quantity exceeds what was expected. Used by the PO-detail receive drawer when the receiver explicitly picks a target shipment. Presence forces sync fallback.
- force_new_shipment (optional, boolean): If true, skip auto-routing/delegation to existing planned shipments and create a brand-new ad-hoc inbound shipment for this receipt. Mutually exclusive in intent with inbound_shipment_id
- receipt_lines (optional): Array of specific line quantities to receive. If omitted, receives all unreceived lines
- receipt_lines[].purchase_order_shipment_line_id (conditional): Shipment line ID. Required without purchase_order_line_reference or purchase_order_line_id
- receipt_lines[].purchase_order_line_id (conditional): PO line ID. Alternative to shipment_line_id
- receipt_lines[].purchase_order_line_reference (conditional): PO line reference code. Alternative to IDs
- receipt_lines[].quantity (required): Quantity received. Negative quantities force sync fallback.
- unexpected_items (optional): Items received that were not on the original PO. Presence forces sync fallback.
- unexpected_items[].product_id (conditional): Product ID. Required without product_sku
- unexpected_items[].product_sku (conditional): Product SKU. Required without product_id
- unexpected_items[].quantity (required): Quantity of unexpected item
- unexpected_items[].action (optional): Action for unexpected item (e.g., add_to_inventory)
- unexpected_items[].amount (optional): Unit cost for unexpected item
- unexpected_items[].description (optional): Description for unexpected item
Request
Responses
- 200
Successful response