POST
Record that an exchange's returned goods arrived

Authorizations

Authorization
string
header
required

A secret API key. Publishable keys cannot reach this API. A key may carry an expiry, and an expired key is refused exactly like an unknown one, with a 401 that names no reason; check the key's expires_at in the dashboard rather than inferring it from a response. When a merchant rolls a key's secret they choose a grace window of up to 3 days, and for its duration BOTH the new secret and the one it replaced authenticate, so an integration moves over on its own deploy schedule instead of at the instant the button is pressed. Move before the window closes: after it, the old secret is refused. Nothing else about this contract moves with a roll. The key keeps its id and its scopes, so the only thing an integration updates is the credential itself.

Headers

Idempotency-Key
string
required

A unique key per logical write. Replaying a request with the same key returns the first response byte for byte instead of applying the write twice.

Path Parameters

exchangeId
string
required

Body

application/json

Takes no parameters, and an empty body is expected. THIS ONE MOVES STOCK, which is the fact that separates it from the other two transitions this API publishes: every inbound line is RESTOCKED into its own order line's location, the place the goods shipped from, in the same transaction as the status flip. An inbound line whose order line no longer records a location is received with no restock for that line. THE CALLER CHOOSES NOTHING ABOUT THE MOVE. Not the destination, not the quantity (fixed when the exchange was opened), not whether it happens at all, which is why restock and location_id are still refused BY NAME: recording that goods came back is this grant's business, and putting stock into a named location is write_inventory's. IT IS ALL OR NOTHING. The restock and the status change share one transaction, so a failed restock rolls the receive back and the exchange stays approved. There is no state where the API says received and the stock never moved. A RESTOCK CAN REACH SHOPPERS. A variant that was sold out and is buyable again because of this receipt fires the store's back-in-stock notifications after the commit, so this call can send email to people who are not the merchant. NO MONEY MOVES, whatever difference_total_minor says. That figure is a snapshot taken when the exchange was opened, in the MINOR UNITS of the order's currency, and it settles on SHIP, which this API does not publish. Nothing is charged and nothing is refunded here. LEGAL ONLY FROM approved, and that guard is what makes the stock movement safe to retry. Three retry shapes, all different: replaying the SAME Idempotency-Key returns the stored 200 and the handler never runs; a FRESH key after a success answers 409 invalid_transition under the row lock and CANNOT restock a second time; a fresh key after a 5xx executes for the first time, because the transaction rolled back and the exchange is still approved. A requested, shipped or cancelled exchange is 409 as well. 409 order_line_missing IS THE ONE REFUSAL THAT IS NOT A TRANSITION ERROR: an inbound item points at an order line that no longer exists, so there is nowhere to return those goods to. Nothing was received and no stock moved. CANCELLING AFTERWARDS DOES NOT UNDO THE RESTOCK. Cancel is legal from received and flips the status while leaving that stock exactly where this call put it; move it again through the inventory api if it is not staying on the shelf. THE BODY IS READ ONLY TO REFUSE IT, against the same list the other two transitions use. received_at is refused BY NAME because the platform stamps it the first time goods are received and back-dating a receipt would put the inventory movement and its stamp on different days. refund, refund_to, amount, difference_total and difference_total_minor are refused because no money moves here, reason and note because the exchange row has no column for prose, status because the route in the url is the transition, and the provenance keys (id, store_id, order_id, created_by, canceled_at, created_at, updated_at) because the server owns them. The response is the WHOLE exchange in the shape GET /api/v1/exchanges/{exchangeId} serves.

Response

Success

data
object