Skip to content

Returns

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.

Business context

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.

When to use this

  • Call upsertReturns whenever a return is created or changes on the channel.
  • Handle an OrderActionEvent whenever one arrives with a type on the return side, which is ACCEPT_RETURN, UPDATE_RETURN_TRACKING_INFORMATION, ACKNOWLEDGE_RETURN_RECEPTION, or CLOSE_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.

How it works

ChannelMiddlewareMiraklSales channelChannel ConnectorMirakl ConnectSales channelChannel ConnectorMirakl ConnectThe order is already synchronizedReturn created or changedupsertReturns (origin + returns)200 (return_success / return_errors)OrderActionEvent (ACCEPT_RETURN, action_id)Perform the return actionupdateActionStatus (SUCCESS or FAILED)upsertReturns (resulting state)
ChannelMiddlewareMiraklSales channelChannel ConnectorMirakl ConnectSales channelChannel ConnectorMirakl ConnectThe order is already synchronizedReturn created or changedupsertReturns (origin + returns)200 (return_success / return_errors)OrderActionEvent (ACCEPT_RETURN, action_id)Perform the return actionupdateActionStatus (SUCCESS or FAILED)upsertReturns (resulting state)

Three properties shape everything below.

  • A return references resources Mirakl Connect already knows. The channel_order_id must name an order you synchronized before with upsertOrders. The channel_order_line_id of 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_code on the return. Without it, a channel_order_id that several orders share resolves to none of them, and the return fails with the message that the sub_channel_code is required. Read Naming the sub-channel of an order.
  • upsertReturns is partially successful. A request that is syntactically valid returns 200, with a result for each return. A 400 or a 404 is reserved for a problem with the whole request, such as a malformed body, or an unknown channel or store.

The return and its lines

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 a label_url for 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 return lifecycle

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 a rejection_reason says 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.

accepted

declined

goods received

closed out

REQUEST_INITIATED

OPENED

REQUEST_DECLINED

RECEIVED

CLOSED

accepted

declined

goods received

closed out

REQUEST_INITIATED

OPENED

REQUEST_DECLINED

RECEIVED

CLOSED

Step by step

1. Synchronize the order first

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.

2. Build and send the return

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"
        }
      ]
    }
  ]
}

3. Reconcile the response for each return

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.

4. Handle the return actions

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:

  1. Deduplicate on the envelope id.
  2. Persist the action_id.
  3. Perform the action on the channel.
  4. Report the outcome with updateActionStatus, either SUCCESS, or FAILED with one or more bounded ActionError codes and a message a human can read.
  5. 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 the tracking of the return, which is the carrier, the number, and the URL, plus the label_url and the rma_id.
  • ACKNOWLEDGE_RETURN_RECEPTION: confirm that the returned goods arrived, then re-sync the return at RECEIVED.
  • CLOSE_RETURN: close the return out, then re-sync it at CLOSED.

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.

5. Attach the documents of the return

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.

Complete example

A buyer returns one defective unit of the order 0024_COMMERCIAL_ID-A:

  1. The connector synchronizes the return with upsertReturns at REQUEST_INITIATED, as in step 2, and the response lists it under return_success.
  2. An ACCEPT_RETURN event arrives. The connector accepts the return on the channel, reports SUCCESS, and re-syncs it at OPENED.
  3. An UPDATE_RETURN_TRACKING_INFORMATION event arrives with the carrier and the tracking number. The connector records them on the channel, reports SUCCESS, and re-syncs the return with its tracking.
  4. The goods arrive, and an ACKNOWLEDGE_RETURN_RECEPTION event follows. The connector marks the return as received, reports SUCCESS, and re-syncs it at RECEIVED.
  5. A CLOSE_RETURN event closes the return, and the connector re-syncs it at CLOSED.

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.

Common mistakes

Upserting a return before its order

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).

Reading a 200 as total success

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).

Omitting the sub_channel_code

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).

Sending a delta of the return

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).

Reporting the action outcome without re-syncing the return

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).