Keep the copy of every order in Mirakl Connect current. Observe an order on the sales channel, and push its complete state in with upsertOrders. Mirakl Connect, the seller, and the return and action flows then all work from an accurate picture.
An order lives on the sales channel, but the seller manages it from inside Mirakl Connect, which drives the fulfillment actions, the returns, and the refunds from there too.
The connector is the middleware: it watches the channel and reports each order, and every change to it. Everything downstream depends on that report being accurate and current, from the status the seller sees to the actions Mirakl Connect is allowed to request.
Use upsertOrders whenever an order is created or changes on the channel: a new order, a status change, a new adjustment, or updated shipping information.
Never use it to report the outcome of an action Mirakl Connect requested. An action arrives as an OrderActionEvent, and updateActionStatus reports its outcome. Once the action is done, use upsertOrders to push the state it produced.
How your connector detects a change depends on the channel, and Mirakl Connect prescribes nothing here. A channel exposes one of two mechanisms, and some channels expose both:
- The channel notifies your connector, asynchronously, when an order is created or changes. Your connector reacts to each notification it receives.
- Your connector polls the channel's API, synchronously, on a schedule it owns, or it reads a feed the channel publishes. Keep a cursor, such as the date of the last change you read, so that each poll picks up only what moved since.
You report the current state of the order, not the individual change, so all you need is the order as it now stands.
upsertOrders does not support PATCH, so every call restates the order in full. An order carries its origin, its lines, and a lifecycle status. Each line carries its price, tax excluded, its taxes, its product, its quantity, its status, and its full append-only list of adjustments. Set the line's product id to the seller's own product reference on the channel. The seller reads that value to identify what was ordered.
Add the order's sub_channel_code when the store carries sub-channels. Mirakl Connect needs it to tell apart two orders that share a channel_order_id, and it rejects a creation with a 400 on orders[i].channel_order_id once another order already holds a code under that id. Read Naming the sub-channel of an order.
{
"origin": {
"channel_id": "0024",
"channel_store_id": "2005"
},
"orders": [
{
"channel_order_id": "0024_COMMERCIAL_ID-A",
"created_at": "2026-07-10T09:12:00Z",
"channel_updated_at": "2026-07-10T14:03:22Z",
"status": "AWAITING_SHIPMENT",
"fulfillment": { "type": "FULFILLED_BY_SELLER" },
"shipping_info": {
"email": "buyer@example.com",
"carrier": "DHL Express",
"method": "standard",
"address": {
"first_name": "Alex",
"last_name": "Martin",
"street": "12 rue des Fleurs",
"city": "Lyon",
"zip_code": "69001",
"country_iso_code": "FRA"
}
},
"order_lines": [
{
"channel_order_line_id": "0024_COMMERCIAL_ID-A-1",
"created_at": "2026-07-10T09:12:00Z",
"updated_at": "2026-07-10T09:12:00Z",
"quantity": 2,
"can_cancel": true,
"can_refund": true,
"price": { "amount": 49.98, "currency": "EUR" },
"total_shipping_price": { "amount": 4.90, "currency": "EUR" },
"product": { "id": "SELLER_ID_1", "title": "Wireless mouse" },
"taxes": [
{ "code": "VAT", "rate": 0.20, "amount": { "amount": 9.99, "currency": "EUR" } }
],
"status": "AWAITING_SHIPMENT",
"adjustments": []
}
]
}
]
}Set channel_updated_at to the last time the order was modified on the channel. Connect uses it to version the updates: it silently ignores an upsert whose channel_updated_at is older than the value it already stores. This is what keeps a delayed or replayed message from overwriting a newer state.
POST /v1/orders is synchronous and all or nothing:
| Response | Meaning | What to do |
|---|---|---|
204 | Connect accepted every order in the request. | Nothing. |
400 | At least one order is invalid, so Connect rejects the whole request and applies no order. | Fix the invalid order, and send the batch again. |
404 | Connect does not know the channel or the store in origin. | Check the identifiers. Usually, the store was not onboarded or synchronized first. |
Because one invalid order rejects the entire batch, validate before you send. Keep a batch small enough to isolate a bad order quickly, and send up to 100 orders in each request.
Two habits keep the state correct over many updates:
- Order the updates for each
channel_order_id, and let the newest win. Key that ordering on the pair ofchannel_order_idandsub_channel_codewhen the store carries sub-channels. Fold each observed change into the order's current state, and stamp it with the time of the channel. If two updates race, keep the one stamped later. The anti-replay guard of Connect backs this up, but to order your own writes avoids work you send and Connect drops. - Adjustments are append-only. Each order line carries its complete history of past adjustments on every upsert. To send only the newest adjustment erases the rest.
An order is placed with one line that awaits its shipment, as in step 2 above. The seller later ships it, so the order and the line move to SHIPPED on the channel. The connector rebuilds the whole order, with the same lines and adjustments, the new status, and a newer channel_updated_at, and it upserts the order again:
{
"origin": { "channel_id": "0024", "channel_store_id": "2005" },
"orders": [
{
"channel_order_id": "0024_COMMERCIAL_ID-A",
"created_at": "2026-07-10T09:12:00Z",
"channel_updated_at": "2026-07-11T08:40:10Z",
"status": "SHIPPED",
"fulfillment": { "type": "FULFILLED_BY_SELLER" },
"shipping_info": {
"carrier": "DHL Express",
"method": "standard",
"address": {
"first_name": "Alex", "last_name": "Martin",
"street": "12 rue des Fleurs", "city": "Lyon",
"zip_code": "69001", "country_iso_code": "FRA"
}
},
"order_lines": [
{
"channel_order_line_id": "0024_COMMERCIAL_ID-A-1",
"created_at": "2026-07-10T09:12:00Z",
"updated_at": "2026-07-11T08:40:10Z",
"quantity": 2,
"can_cancel": false,
"can_refund": true,
"price": { "amount": 49.98, "currency": "EUR" },
"total_shipping_price": { "amount": 4.90, "currency": "EUR" },
"product": { "id": "SELLER_ID_1", "title": "Wireless mouse" },
"status": "SHIPPED",
"adjustments": []
}
]
}
]
}Connect accepts it with a 204, because channel_updated_at moved forward.
- To send only what changed. There is no merge. A line or an adjustment you leave out of the payload is deleted, not preserved. Always send the complete order.
- To send a delta of the adjustments. Send the full adjustment history of the line every time. The list is append-only, and a partial list rewrites it.
- To omit or reuse
channel_updated_at. Without a timestamp that moves forward, Connect cannot tell a newer state from a replay. A stale upsert can then be dropped, and if you reuse an old value, Connect silently ignores it. - To read a
204as "applied on the channel". A204means that Connect accepted the order into its own copy. It says nothing about the channel, because the channel is the source you report from, not the target. - To send the channel's own product identifier on a line. The seller cannot tell which of their items was ordered. Send the seller's product reference on the channel, which is the SKU is most cases.
- To upsert an order for an unknown store or channel. A
404means that Connect does not know the store or the channel. Synchronize the onboarding first, then retry.
- Handle order action events: how to perform the accept, ship, cancel, and refund actions Mirakl Connect requests, and report the outcome with
updateActionStatus. - Returns: how to synchronize the returns with
upsertReturnsand record the refunds. - Orders: the order process between Mirakl Connect and the channel, and the events and APIs the connector implements.