Orders
Create: POST /v1/orders
Header Idempotency-Key: one key per attempt (for example PO-2026-000123-1), at most 255 characters.
Limits: 1 to 100 lines per order; quantity an integer from 1 to 1000; unit_price a positive number; text fields at most 255 characters.
ship_to.name, address1, city and country are required (company, address2, province, zip and phone are optional).
ship_to.province is required when country is US, CA, AU or BR (the carrier needs the state or province there) and must be
the province code used by Shopify for that country, for example CA for California, ON for Ontario, NSW for New South Wales or SP for
Sao Paulo (case does not matter, ca is read as CA). A full name such as California, or a code of another country, is refused. For any
other country province is optional and informational only: it is accepted (up to 255 characters) but not used for the shipment.
address2 is the second address line (apartment, suite, unit).
Puerto Rico, Guam, the US Virgin Islands, American Samoa, the Northern Mariana Islands, Micronesia, the Marshall Islands, Palau and US military
addresses (AA, AE, AP) are shipped as "country": "US" with their code in province (for example "province": "PR"); their own
country codes (such as PR) are refused as country.
A missing or invalid field gives 400 invalid_request. A live key answers 404 not_found while live orders are not yet enabled for your account.
{ "partner_order_id": "PO-2026-000123",
"lines": [ { "sku": "WP-7Q2K9M-36", "quantity": 1, "unit_price": 303.75 } ],
"ship_to": { "name": "...", "company": "...", "address1": "...", "city": "...", "zip": "...", "country": "JP", "phone": "..." } }
To the United States (the same applies to CA, AU and BR), province must be present:
"ship_to": { "name": "...", "address1": "...", "address2": "Suite 400", "city": "Los Angeles", "province": "CA", "zip": "90012",
"country": "US", "phone": "..." }
Without it, or with a value that is not a province code of that country, the attempt is refused with 400 invalid_request and a message
naming ship_to.province (for example ship_to.province is not a valid province code for US); nothing is stored for the key. A destination
outside your allowed_countries is refused first, with 422 destination_not_allowed.
Response 201: { "order_id", "status", "lines": [ { "sku", "status": "accepted" | "rejected", "reason", "current_price" } ] }.
- A network retry (timeout,
5xx,409 request_in_progress) must reuse the same key: you get the first result, never a second order. An attempt can stayrequest_in_progressfor minutes, in rare cases for a day or more while we check it by hand; its lines already count forduplicate_lineand against your balance. If it is finally not created, the same key returnsstatus: "rejected"with reasonnot_created, nothing is charged, and you can send the lines again with a new key. - Same key with a different valid body gives
409 idempotency_conflict(a body that is also invalid gives400 invalid_requestfirst). Results with any other4xxerror are not stored: fix the cause and send a new attempt with a new key. - Each attempt with at least one accepted line creates its own
order_id. A line is all-or-nothing on quantity. Askualready accepted for the samepartner_order_idis rejected withduplicate_line, even if that line was later cancelled: to order it again, use a newpartner_order_id. - Rejection reasons:
out_of_stock,unknown_sku,price_changed,duplicate_line,not_created. If every line is rejected the response is still201withstatus: "rejected"and nothing is charged. To retry rejected lines, send a new attempt with a new key and only those lines.
Stock check
The order checks stock live at the moment you send it, not against the feed. A line can therefore come back out_of_stock even if the feed still
showed it, and a line can still be cancelled for stock up to its confirmation (see below).
Stock is checked live for each line: a line that is out of stock comes back out_of_stock while the other lines are accepted. In a rare case the
stock changes in the instant between that check and the creation of the order. Then:
- an order with a single line comes back with that line
out_of_stock(or, more rarely,not_created); - an order with several lines can be refused as a whole without saying which line ran out, and every line comes back
not_created. Nothing is charged and the lines do not count asduplicate_line: send the order again with a new key, and the live check then usually reports the line that ran out asout_of_stockwhile the others are accepted (or leave that line out, if you already know which one it is).
The flat shipping fee, when your mode has one, is charged in full once per order when the order is created with at least one accepted line; if every line is rejected, nothing is charged. If later every line of a created order is cancelled before anything ships, the fee is not returned automatically: it is credited back to your balance after a manual check by our team (see Deposit).
Price applied
Each line is charged at the current price, checked live when you send the order (it can differ from the feed, where a price change arrives through a refresh scheduled every 15 minutes). A unit_price below it (for example a sale has just ended) is rejected with price_changed
and current_price; a unit_price at or above it is accepted and charged at the current price.
Destination
ship_to.country (ISO 3166-1 alpha-2) must be one of the allowed_countries of your profile. Otherwise the whole attempt is refused with
422 destination_not_allowed: no order, nothing reserved, nothing stored for the key, so you can send it again with a new key once the
destination is right. Countries of the European Union and a few neighbouring ones are never allowed; for GB the zip is required and Northern
Ireland postcodes (BT...) are refused. An account with no allowed_countries yet refuses every order with this error.
Status and tracking
GET /v1/orders/{order_id} returns one order; GET /v1/orders?updated_since=<ISO-8601> returns { "orders": [ ... ], "next_cursor": "..." | null }
with every order changed at or after that time, at most 200 per page. While next_cursor is not null, repeat the call with
cursor=<next_cursor> instead of updated_since. For the next poll pass as updated_since the updated_at of the last order you received.
Orders may repeat across pages and polls: upsert them by order_id. A change becomes visible in the list after about 2 minutes; the single
order always shows the current state. Poll at most every 15 minutes. updated_since is required unless you pass a cursor.
Order status: rejected, or received, in_progress, partially_shipped, shipped; cancelled.
Line status: accepted, ordered (the supplier has the piece, usually within minutes), confirmed, shipped; or cancelled with a reason
(out_of_stock when the supplier has no stock, cancelled when cancelled by the supplier or by us). A line normally moves forward through these steps,
but its status is recomputed from our systems on every read, so always rely on the latest state you receive; a confirmed line can still become
cancelled. Lines rejected at creation show rejected with their reason.
In live, shipped, partially_shipped and the parcels in shipments[] exist through the API only when your shipping mode is own_awb; in live with included
and flat_fee the API does not move a line beyond confirmed and shipments is an empty list (see Shipping). The sandbox always
simulates parcels and shipped.
{ "order_id": "...", "partner_order_id": "PO-2026-000123", "status": "in_progress",
"created_at": "2026-10-19T10:00:00.000Z", "updated_at": "2026-10-19T10:20:00.000Z",
"lines": [ { "sku": "WP-7Q2K9M-36", "quantity": 1, "status": "confirmed", "reason": null } ],
"shipments": [ { "shipment_id": "17", "status": "awaiting_awb", "lines": [ { "sku": "WP-7Q2K9M-36", "quantity": 1 } ],
"weight_kg": 1.2, "dimensions_cm": { "length": 30, "width": 20, "height": 10 }, "ready_date": "2026-10-21",
"carrier": "CARRIER", "tracking_number": null, "shipped_at": null } ] }
- An order is
rejectedif no line was accepted or the attempt was not created;cancelledif the whole order is cancelled before any line shipped;shippedwhen every line not cancelled is shipped;partially_shippedonly while some lines are shipped and others are neither shipped nor cancelled;in_progressonce any line has moved beyondaccepted;receivedotherwise. - A key only sees the orders of its own account (others give
404). An attempt still being processed answers409 request_in_progress. - Shipments are described in Shipping.
Cancellation
Accepted orders are passed to our suppliers within minutes and cannot be cancelled through the API. To request a cancellation write to your Wanan integration contact: we will do our best with the supplier, and any line we manage to cancel is released to your balance.