This page covers the life of a return, from the request of a buyer to the closing of the return. It shows you how to:
- keep the copy of the return in Mirakl Connect current, with upsertReturns,
- carry out the return actions Mirakl Connect requests, which are to accept or decline a return, record its tracking, acknowledge its reception, and close it out,
- attach the documents of the return, such as its return label.
A buyer sends part or all of an order back, and the return runs its own lifecycle, from requested, to accepted or declined, to received, to closed. The return lives on the channel, and the seller works with it inside Mirakl Connect.
So your connector does two things. It reports the state of the return, and it performs the return actions Mirakl Connect requests. The seller sees only the returns your connector reports. Mirakl Connect holds a return action open until your connector reports its outcome.
The refund that compensates the buyer is not part of the return. It is an adjustment on the order line, and Refunds and cancellations documents it.
- Call upsertReturns whenever a return is created or changes on the channel.
- Handle an OrderActionEvent whenever one arrives with a
typeon the return side, which isACCEPT_RETURN,UPDATE_RETURN_TRACKING_INFORMATION,ACKNOWLEDGE_RETURN_RECEPTION, orCLOSE_RETURN.
A return is opened against an order Mirakl Connect already knows, so synchronize the order first. A store and a channel scope the return, exactly as they scope the order it belongs to.
When not to use this. For the order itself, and for the refund that follows a return, read Orders. For the actions on the order side, which are ACCEPT, CREATE_SHIPMENT, CANCEL, REFUND, and UPLOAD_DOCUMENT, read Handle order action events. For how a store reaches Mirakl Connect, read Stores.
Three properties shape everything below.
- A return references resources Mirakl Connect already knows. The
channel_order_idmust name an order you synchronized before with upsertOrders. Thechannel_order_line_idof each return line must name an order line from that synchronization. A return for an order Mirakl Connect has not seen fails. - A return names the order's sub-channel when the store carries sub-channels. Send the order's
sub_channel_codeon the return. Without it, achannel_order_idthat several orders share resolves to none of them, and the return fails with the message that thesub_channel_codeis required. Read Naming the sub-channel of an order. upsertReturnsis partially successful. A request that is syntactically valid returns200, with a result for each return. A400or a404is reserved for a problem with the whole request, such as a malformed body, or an unknown channel or store.
A return is the request of a buyer to send part or all of an order back. Its channel_return_id identifies it, and it always carries the channel_order_id of the order it belongs to.
It also carries:
- an optional
rma_id, the Return Merchandise Authorization id, - a lifecycle
status, - the
tracking, which holds a tracking number, a carrier name, and a tracking URL, and alabel_urlfor the return shipping label, - a
method, the return shipping method on the channel, - a return
address, - a
rejection_reason, when the return is declined, - one or more return lines.
A return line references the order line that is returned, by its channel_order_line_id, and it names a quantity and a reason:
WRONG_ITEM: the buyer received the wrong item.MISSING_ITEM: an item was missing from the order.DEFECTIVE_ITEM: the item was defective.DAMAGED_ITEM: the item arrived damaged.UNWANTED_ITEM: the buyer no longer wants the item.OTHER: any other reason.
The Data model describes the full definition, field by field, of the return and the return line.
The status of a return is a reported snapshot. The connector observes where the return stands on the channel, and reports it to Mirakl Connect. The contract defines the six possible statuses, but it does not prescribe a fixed set of transitions.
REQUEST_INITIATED: a buyer requested a return, and it waits for a decision.REQUEST_DECLINED: the request was declined, and arejection_reasonsays why.OPENED: the return was accepted, and it is in progress.RECEIVED: the returned goods arrived.CLOSED: the return is complete.CHANNEL_SPECIFIC: a channel status with no standard equivalent in Mirakl Connect.
When a return is declined, its rejection_reason explains why:
RETURN_WINDOW_CLOSED: the return window has closed.NOT_ELIGIBLE_FOR_RETURN: the item is not eligible for a return.FINAL_SALES: the item was a final sale.OTHER: any other reason.
Send the order with upsertOrders before its returns. The return names that order and its lines, and Mirakl Connect must already hold them. Read Sync orders into Connect.
Send the returns whole, because there is no PATCH. Each call carries the origin, which is the channel and the store, and up to 100 returns. Mirakl Connect versions the returns by channel_updated_at, so it silently ignores an update whose timestamp is older than the value it stores.
{
"origin": { "channel_id": "0024", "channel_store_id": "2005" },
"returns": [
{
"channel_return_id": "RET-0024-001",
"channel_order_id": "0024_COMMERCIAL_ID-A",
"rma_id": "CR117B72FEF5E8391187",
"status": "REQUEST_INITIATED",
"created_at": "2026-07-15T10:00:00Z",
"channel_updated_at": "2026-07-15T10:00:00Z",
"return_lines": [
{
"channel_order_line_id": "0024_COMMERCIAL_ID-A-1",
"quantity": 1,
"reason": "DEFECTIVE_ITEM"
}
]
}
]
}Read both lists of the response. return_success names the returns Mirakl Connect applied, and return_errors names the ones that failed, each with the detail of what went wrong, field by field.
{
"return_success": [
{ "channel_order_id": "0024_COMMERCIAL_ID-A", "channel_return_id": "RET-0024-001" }
],
"return_errors": [
{
"channel_order_id": "0024_COMMERCIAL_ID-B",
"channel_return_id": "RET-0024-002",
"details": [
{ "code": "DATA_NOT_FOUND", "message": "Unknown order line", "field": "returns[0].return_lines[0].channel_order_line_id" }
]
}
]
}Leave the return_success entries alone. Drive only the return_errors entries again, after you fix what the field points at, most often the order or the order line the return references.
A 200 is not a receipt that Mirakl Connect applied every return. Inspect return_success and return_errors on every response.
Some changes to a return start in Mirakl Connect, not on the channel. A seller decides to accept or decline a return, record its tracking, acknowledge that the goods arrived, or close the return out. Mirakl Connect requests each of them as an OrderActionEvent, with a type that names the action and an action_id to track it.
The return actions follow the same loop as the order actions:
- Deduplicate on the envelope
id. - Persist the
action_id. - Perform the action on the channel.
- Report the outcome with updateActionStatus, either
SUCCESS, orFAILEDwith one or more boundedActionErrorcodes and a message a human can read. - Re-sync the return with upsertReturns, so that the copy in Mirakl Connect matches what the action produced.
Four type values apply to returns. ACCEPT_RETURN accepts the requested return, which moves it toward OPENED, or declines it, which records a rejection_reason and reports REQUEST_DECLINED:
{
"type": "ACCEPT_RETURN",
"data": {
"action_id": "9f0a1b2c-3d4e-5f60-7181-92a3b4c5d6e7",
"channel_id": "0024",
"channel_store_id": "2005",
"channel_order_id": "0024_COMMERCIAL_ID-A",
"channel_return_id": "RET-0024-001",
"accepted": true
}
}The three others follow the same shape:
UPDATE_RETURN_TRACKING_INFORMATION: record thetrackingof the return, which is the carrier, the number, and the URL, plus thelabel_urland therma_id.ACKNOWLEDGE_RETURN_RECEPTION: confirm that the returned goods arrived, then re-sync the return atRECEIVED.CLOSE_RETURN: close the return out, then re-sync it atCLOSED.
Each type gives the event's data a different shape. API and event directory names the payload schema of each one.
When the connector cannot carry an action out, for example because the return is in the wrong state, it reports FAILED with the matching ActionError code, such as RETURN_IN_WRONG_STATE.
Reporting an outcome on an action that is already in a final state returns a 400 with ACTION_ALREADY_FINAL.
Upload the documents of a return, most often its RETURN_LABEL, with uploadOrderDocument, the same operation the orders use. Make the call against the order, because its path carries the channel_order_id. The document names the return through its entity, with type: RETURN and the id of the return. Remove a document with deleteOrderDocument.
A buyer returns one defective unit of the order 0024_COMMERCIAL_ID-A:
- The connector synchronizes the return with
upsertReturnsatREQUEST_INITIATED, as in step 2, and the response lists it underreturn_success. - An
ACCEPT_RETURNevent arrives. The connector accepts the return on the channel, reportsSUCCESS, and re-syncs it atOPENED. - An
UPDATE_RETURN_TRACKING_INFORMATIONevent arrives with the carrier and the tracking number. The connector records them on the channel, reportsSUCCESS, and re-syncs the return with itstracking. - The goods arrive, and an
ACKNOWLEDGE_RETURN_RECEPTIONevent follows. The connector marks the return as received, reportsSUCCESS, and re-syncs it atRECEIVED. - A
CLOSE_RETURNevent closes the return, and the connector re-syncs it atCLOSED.
The seller can refund the buyer at any point of that sequence, through a REFUND order action. That refund is an adjustment on the order line, and it never touches the return.
What it looks like: the connector reads the returns and the orders from the channel on two independent schedules, and it sends a return whose order has not reached Mirakl Connect yet.
The failure: the return lands in return_errors with DATA_NOT_FOUND, inside a 200. The field points at the channel_order_id, or at the channel_order_line_id of a line.
The fix: send the order with upsertOrders first, then its returns (step 1).
What it looks like: the connector checks the HTTP status of upsertReturns and moves on.
The failure: the returns that failed sit inside a successful response, and the connector never learns it. Those returns never appear in Mirakl Connect, so the seller cannot work with them.
The fix: read return_success and return_errors on every response, and drive only the failed entries again, after you fix what the field points at (step 3).
What it looks like: the store carries sub-channels, and the connector sends the return with its channel_order_id alone.
The failure: several orders share that channel_order_id, so the return resolves to none of them and it fails.
The fix: carry the sub_channel_code of the order on your own return state, and send it on every return (step 2).
What it looks like: the connector sends only the fields that changed, such as the new status, and expects Mirakl Connect to merge them into the return it holds.
The failure: there is no PATCH, so every field the call omits is lost, including the return lines.
The fix: send the return whole on every call (step 2).
What it looks like: the connector performs the action, reports SUCCESS with updateActionStatus, and stops there.
The failure: updateActionStatus carries no return state, so the copy of the return in Mirakl Connect drifts from the channel.
The fix: follow every action that changes the state with upsertReturns (step 4).
- Orders: the order a return is opened against, and the refund recorded as an adjustment on the order line.
- Sync orders into Connect: how to synchronize the order before its returns.
- Handle order action events: the action loop the return actions follow, and the
REFUNDaction. - Data model: the definition, field by field, of the return and the return line.
- Event APIs reference: the complete payload of each return action.