Marketplaces / BestBuy Technical Scope / BestBuy Order management / BestBuy Refund Order

BestBuy Refund Order

Summary of Changes: (The purpose of this table is to keep traceability and Product team to highlight the things that were changed into the scope, based on comments or discussions)

Version Date Name Applied changes
v1.0 29.05.2025 Bogomil First publish

The purpose of this page is to describe in details the refund flow on MIRAKL.

The refund/cancellation request on MIRAKL is per item line id and we can include each separate item as additional “refund“ or “cancellation“ node. To process the refund/cancellation , we have to specify a reason which need to be added in the Refund UI for BestBuy Marketplace. In order to obtain the reasons, we should use GET RE01 - List reasons call and then, to make a refund/cancellation , we should use PUT OR28 - Request a refund or OR30 - Request cancelations on order lines

  • GET RE01 - List reasons

API Call:/api/reasons

API Docs: https://help.mirakl.net/help/api-doc/seller/mmp.html#OR24

Please note we need to store only the reasons which are with type = “REFUND“ and type = “RETURN

Example response:

{
    "reasons": [
                {
            "code": "14",
            "is_shop_right": false,
            "label": "No response from the shop",
            "type": "REFUND"
        },
        {
            "code": "15",
            "is_shop_right": true,
            "label": "Out of stock",
            "type": "REFUND"
        },
        {
            "code": "16",
            "is_shop_right": true,
            "label": "Cancelled by the client prior to shipping",
            "type": "REFUND"
        },
        {
            "code": "17",
            "is_shop_right": true,
            "label": "Item returned",
            "type": "REFUND"
        },
        {
            "code": "18",
            "is_shop_right": true,
            "label": "Item not received",
            "type": "REFUND"
        },
        {
            "code": "19",
            "is_shop_right": true,
            "label": "Agreement found with the vendor",
            "type": "REFUND"
        },
        {
            "code": "34",
            "is_shop_right": true,
            "label": "Cancelled by the client prior to shipping",
            "type": "CANCELATION"
        },
        {
            "code": "SYSTEM_LATE_SHIPMENT_CANCELATION",
            "is_shop_right": false,
            "label": "Canceled due to late shipment",
            "type": "CANCELATION"
        },
        {
            "code": "SYSTEM_CANCELATION_DEBIT_FAILED",
            "is_shop_right": false,
            "label": "Debit failed",
            "type": "CANCELATION"
        },
        {
            "code": "SYSTEM_CANCELATION_DEBIT_TIMEOUT",
            "is_shop_right": false,
            "label": "Debit timed out",
            "type": "CANCELATION"
        }
    ],
    "total_count": 54
}

Bear in mind we need to display the label into the UI but to send the code. Because in our UI we cannot distinguish the refund from the cancellation we need to add in the label what type is the reason is for the refund or for cancellation. E.G. [REFUND] - {label} or [RETURN] - {label}

We want to set a logic and have a default RETURN and REFUND reasons if there is no reason specified in the refund. At the moment if there is no reason we receive error “[INTERNAL]Could find refund reason code by label '’. We want to add additional checkbox field in Order Refund Reasons > Default which will be used to specify default reasons for the debenhams and the logic should support default reasons per reason type. In order to be able to filter reasons by type we want to add another new field Order Refund Reasons > Type which indicates if the reasons is: “Cancellation” or “Refund” or “All”. **Having the type we can have two default reasons one for RETURN and one for REFUND type. Based on our MIRAKL abstraction and the check we are doing before each refund (checking the can_refund and can_cancel flags we should be correct default reason type).

If for some reason we have more than one default reason per type we pick the first available and we do not want to return an error.

“[INTERNAL]Could not find refund reason code by label '’ should be returned only if there is no reason in the refund and there is no default reason set.

Reason Code Reason Label Type
17 Item returned - Damaged/defective/wrong REFUND
44 Item returned - Buyer changed mind REFUND
18 Item not received REFUND
15 Out of stock REFUND
16 Cancelled by client prior to shipping REFUND
45 Shipping fee refund REFUND
35 Tax refund REFUND
19 Product price discount (customer keeps product) REFUND
55 Pricing Error REFUND
41 Operator request to cancel due to fraud suspicion REFUND
34 Chargeback REFUND
14 No response from shop REFUND
51 Cannot ship due to PO Box address provided REFUND
SYSTEM_REFUND_EDI Refunded through EDI integration REFUND
RETURN_BROKEN_ITEM Broken item RETURN
RETURN_CHANGED_MIND Changed my mind RETURN
RETURN_COUNTERFEIT_ITEM Counterfeit item RETURN
RETURN_DAMAGED_PACKAGING Damaged packaging RETURN
RETURN_DEFECTIVE_ITEM Defective item RETURN
RETURN_DELIVERED_PRODUCT_DIFFERENT Delivered product different from ordered product RETURN
RETURN_MISSING_ITEM Missing item RETURN
RETURN_CM_DONT_WANT Don''t want the product anymore RETURN
RETURN_CM_DONT_LIKE Don''t like the product RETURN
RETURN_CM_QUALITY Quality not as expected RETURN
RETURN_DPD_WRONG_SIZE Wrong size RETURN
RETURN_DPD_WRONG_COLOR Wrong color RETURN
RETURN_DEFECTIVE_ON_ARRIVAL Defective on arrival RETURN
RETURN_PRODUCT_DOES_NOT_FIT Product does not fit RETURN
RETURN_PDNT_TOO_BIG Product too big RETURN
RETURN_PDNT_TOO_SMALL Product too small RETURN
RETURN_OTHER Other reason RETURN
  • PUT OR28 - Request a refund

API Call: /api/orders/refund

API Docs: https://help.mirakl.net/help/api-doc/seller/mmp.html#OR24

*Note:* Each payment row (type=refund) will need to be send as a separate request. If even one of the refunds failed it will fail the whole feed. Thus we have agreed to push them per payment row. Which means we will have one request with all of the refund row nodes Example call: (one item in order)*

{
  "order_tax_mode": "TAX_EXCLUDED",
  "refunds": [
    {
      "amount": 1.5,
      "currency_iso_code": "USD",
      "excluded_from_shipment": false,
      "order_line_id": "Order_00010-A-1",
      "quantity": 0,
      "reason_code": "15",
      "shipping_amount": 2,
      "shipping_taxes": [
        {
          "amount": "1",
          "code": "tax1"
        },
        {
          "amount": "1",
          "code": "tax2"
        }
      ],
      "taxes": [
        {
          "amount": "1",
          "code": "tax1"
        },
        {
          "amount": "1",
          "code": "tax2"
        }
      ]
    }
  ]
}

Example call: (two items in order)

{
  "refunds": [
    {
      "amount": 10.00,
      "currency_iso_code": "GBP",
      "order_line_id": "Order_25082022-6-A-1",
      "quantity": 1,
      "reason_code": "15",
      "excluded_from_shipment": false,
      "shipping_amount": 0,
shipping_taxes": [
        {
          "amount": "1",
          "code": "tax1"
        },
        {
          "amount": "1",
          "code": "tax2"
        }
      ],
      "taxes": [
        {
          "amount": "1",
          "code": "tax1"
        },
        {
          "amount": "1",
          "code": "tax2"
        }
      ]
    },
    {
      "amount": 10.00,
      "currency_iso_code": "GBP",
      "order_line_id": "Order_25082022-6-A-2",
      "quantity": 1,
      "reason_code": "15",
      "excluded_from_shipment": false,
      "shipping_amount": 0,
      shipping_taxes": [
        {
          "amount": "1",
          "code": "tax1"
        },
        {
          "amount": "1",
          "code": "tax2"
        }
      ],
      "taxes": [
        {
          "amount": "1",
          "code": "tax1"
        },
        {
          "amount": "1",
          "code": "tax2"
        }
      ]
    }
  ]
}

MIRAKL allows us to refund:

  • Partially items;
  • Shipping
  • Orders

So the only validation we will need is to make sure we are not refunding more than we can for particular order item line!

Mapping:

Integration Field Integration Notes Hemi Mapping Hemi Notes
order_tax_mode N/A
refunds
amount Refund Row > Amount Refund rows with type “item“
currency_iso_code Order > Order currency
order_line_id Order Item >Item Order Line ID
quantity Order Item > Quantity Based on the Refund Row > Amount we need to calculate the quantity!

• If we are doing partial line refund we specify the quantity as 0. • If we are doing full line refund (the full quantity) we specify the actual quantity we have for the item e.g. 1, 2, 3 etc. Note: For each full like we are having quantity = 1 For each partial like we will have quantity = 0 | | | reason_code | | | Order Payment > Reason | We need to use the reason code. | | | shipping_amount | | | Refund Row > Amount | Refund rows with type “shipping“ | | | shipping_taxes | | | | | | | | amount | | | We need to calculate this based on the shipping cost added for the refund We need to get the % of the shipping cost = % of the Shipping cost VAT

Refund rows with type “shipping“

Please note if there is no shipping cost we do not want to include this in the payload | | | | code | | ****“TAXDEFAULT“ | Hardcoded as “TAXDEFAULT“ Please note if there is no shipping cost we do not want to include this in the payload | | | taxes | | | | Please note if there is no taxes on the order we do not want to include this object in the payload | | | | amount | | | We need to calculate this based on the item price added for the refund We need to get the % of the item price = % of the Item VAT Refund rows with type “item“

Also we would like to calculate in couple of ways:#If we are making full item refund to get it from Orders > Total Marketplace VAT

If we are making partial and full item refunds we want to get the tax from Product in Order > Marketplace VAT Item Price

If we have partial item refund and we are making full item refund to calculate it based on Product in Order > Marketplace VAT Item Price - already refunded VAT -

If we are having item refund and we are making order full refund to calculate it based on Orders > Total Marketplace VAT - already refunded VAT

code “TAXDEFAULT“ Hardcoded as “TAXDEFAULT“

Example Response: (one item in order)

{
    "order_tax_mode": "TAX_INCLUDED",
    "refunds": [
        {
            "amount": 10.00,
            "amount_breakdown": {
                "parts": [
                    {
                        "amount": 10.00,
                        "commissionable": true,
                        "debitable_from_customer": true,
                        "payable_to_shop": true
                    }
                ]
            },
            "currency_iso_code": "GBP",
            "excluded_from_shipment": false,
            "order_line_id": "Order_25082022-6-A-1",
            "quantity": 1,
            "reason_code": "15",
            "refund_id": "1109",
            "shipping_amount": 2.00,
            "shipping_amount_breakdown": {
                "parts": [
                    {
                        "amount": 2.00,
                        "commissionable": true,
                        "debitable_from_customer": true,
                        "payable_to_shop": true
                    }
                ]
            },
            "shipping_taxes": [],
            "taxes": []
        }
    ]
}

Response Mapping:

Integration Field Integration Notes Integration required Hemi Mapping Hemi Notes
order_tax_mode
refunds
amount N/A
amount_breakdown N/A
currency_iso_code N/A
excluded_from_shipment N/A
order_line_id N/A This will be used for the mapping
quantity N/A
reason_code N/A
refund_id Order Payment Details > Transaction ID Because each order item is pushed in a separate transaction we will receive more than one refund_id thus we will have to concatenate them with “-“
shipping_amount
shipping_amount_breakdown
shipping_taxes
taxes
  • PUT OR30 - Request cancelations on order lines

API Call: /api/orders/cancel

API Docs: https://help.mirakl.net/help/api-doc/seller/mmp.html#OR30

*Note:** Each payment row (type=refund) will need to be send as a separate request.

Example call: (one item in order)

{
  "cancelations": [
    {
      "amount": 2,
      "currency_iso_code": "USD",
      "order_line_id": "Order_00013-A-1",
      "quantity": 0,
      "reason_code": 34,
      "shipping_amount": 0,
      "shipping_taxes": [
        {
          "amount": "1",
          "code": "tax1"
        },
        {
          "amount": "1",
          "code": "tax2"
        }
      ],
      "taxes": [
        {
          "amount": 1,
          "code": "tax1"
        },
        {
          "amount": 1,
          "code": "tax2"
        }
      ]
    }
  ],
  "order_tax_mode": "TAX_EXCLUDED"
}

Example call: (two items in order)

{
  "cancelations": [
    {
      "amount": 1996,
      "currency_iso_code": "GBP",
      "order_line_id": "419244321-PUM-A-1",
      "quantity": 0,
      "reason_code": 34,
      "shipping_amount": 0
      "shipping_taxes": [
        {
          "amount": "1",
          "code": "tax1"
        },
        {
          "amount": "1",
          "code": "tax2"
        }
      ],
      "taxes": [
        {
          "amount": 1,
          "code": "tax1"
        },
        {
          "amount": 1,
          "code": "tax2"
        }
      ]

    },
    {
      "amount": 1996,
      "currency_iso_code": "GBP",
      "order_line_id": "419244321-PUM-A-2",
      "quantity": 0,
      "reason_code": 34,
      "shipping_amount": 0
       "shipping_taxes": [
        {
          "amount": "1",
          "code": "tax1"
        },
        {
          "amount": "1",
          "code": "tax2"
        }
      ],
      "taxes": [
        {
          "amount": 1,
          "code": "tax1"
        },
        {
          "amount": 1,
          "code": "tax2"
        }
      ]
    }
  ]
        "order_tax_mode": "TAX_EXCLUDED"
}

MIRAKL allows us to refund:

  • Partially items;
  • Shipping
  • Orders

So the only validation we will need is to make sure we are not refunding more than we can for particular order item line!

Mapping:

Integration Field Integration Notes Integration required Hemi Mapping Hemi Notes
cancellations
amount Refund Row > Amount Refund rows with type “item“
currency_iso_code Order > Order currency
order_line_id Product In Order >Item Order Line ID
quantity Product In Order > Quantity Based on the Refund Row > Amount we need to calculate the quantity!

• If we are doing partial line refund we specify the quantity as 0. • If we are doing full line refund (the full quantity) we specify the actual quantity we have for the item e.g. 1, 2, 3 etc. | | | reason_code | | | Order Payment > Reason | We need to use the reason code. | | | shipping_amount | | | Refund Row > Amount | Refund rows with type “shipping “ | | | shipping_taxes | | | N/A | |

Example Response: (one item in order)

{
  "cancelations": [
    {
      "amount": 2,
      "cancelation_id": "1116",
      "currency_iso_code": "USD",
      "eco_contributions": [],
      "order_line_id": "Order_00013-A-1",
      "purchase_information": {
        "purchase_commission_on_price": 1.00,
        "purchase_commission_on_shipping": 1.50,
        "purchase_price": 1.00,
        "purchase_shipping_price": 1.50
      },
      "quantity": 0,
      "reason_code": "34",
      "shipping_amount": 3,
      "shipping_taxes": [
        {
          "amount": 1,
          "code": "tax1",
          "purchase_tax": {
            "purchase_amount": 0.50,
            "purchase_rate": 7.5000
          },
          "rate": 17.5000
        },
        {
          "amount": 1,
          "code": "tax2",
          "purchase_tax": {
            "purchase_amount": 0.50,
            "purchase_rate": 7.5000
          }
        }
      ],
      "taxes": [
        {
          "amount": 1,
          "code": "tax1",
          "purchase_tax": {
            "purchase_amount": 0.50,
            "purchase_rate": 7.5000
          },
          "rate": 17.5000
        },
        {
          "amount": 1,
          "code": "tax2",
          "purchase_tax": {
            "purchase_amount": 0.50,
            "purchase_rate": 7.5000
          }
        }
      ]
    }
  ],
  "order_tax_mode": "TAX_EXCLUDED"
}

Response Mapping:

Integration Field Integration Notes Integration required Hemi Mapping Hemi Notes
cancelations
amount N/A
cancellation_id Order Payment Details > Transaction ID Because each order item is pushed in a separate transaction we will receive more than one refund_id thus we will have to concatenate them with “-“
currency_iso_code N/A
eco_contributions N/A
order_line_id N/A This will be used for the mapping
purchase_information N/A
quantity N/A
reason_code N/A
shipping_amount N/A
shipping_taxes N/A
taxes N/A
order_tax_mode N/A

PUT OR29 - Cancel an order not yet debited from the customer

API Call: /api/orders/{order_id}/cancel

API Docs: https://help.mirakl.net/help/api-doc/seller/mmp.html#OR29

We have to specify in the URL our Orders > Marketplace Order Id

Cancel an order not yet debited from the customer. All accepted but NOT shipped orders are treated as “Not Yet Debited” which means that if a cancellation has to happen, we need to use the OR29 call instead of OR30. Please note only full order cancellations for non debited orders are allowed and we would like to add internal validation and return internal error if not full cancellation is done.

Example call:

PUT https://mirakl.marketplace.laredoute.com/api/orders/12341231-A/cancel

Example Response: 204: No Content

Please note since there is no content in the response we wont have a transaction id for the refund so we need to make a OR11 - List Orders call for the specific order that we have cancelled and store the transaction ID.

This needs to be done after each 204: No Content response for the specific order that we are cancelling.

We have developed all possible scenarios:

  • If we have can_cancel = true and customer_debited_date = null and can_refund = false We need to use the OR29 to cancel the order
  • If we have can_cancel = true and customer_debited_date = date (in a 2023-12-04T12:26:07.043Z format) and can_refund = false we need to use the OR30 to cancel
  • If we have for some reason can_refund = true and can_cancel = true we need to use the OR30 to cancel (this is not an expected behavior anyways, if for some reason it happens for whatever reason we want to have it covered)
  • If we have can_cancel = false and customer_debited_date = null and can_refund = true We need to use the OR28 to refund the order (this is not an expected behavior anyways, if for some reason it happens for whatever reason we want to have it covered)
  • If we have can_cancel = false and customer_debited_date = date (in a 2023-12-04T12:26:07.043Z format) and can_refund = true We need to use the OR28 to refund the order


Specifics:

We will have couple of cases here because we will have one Order Payment row with type = refund but in MIRAKL there might be couple of transaction:

  • If all transaction are successfully and we receive the refund_id or the cancellation_id ,we need to mark the Order Payment > Status = "Completed" and Refund Row > Status = "Completed"
  • If not all transactions are completed but we have one or more completed we mark the Order Payment > Status = “Partially Completed“, Refund Row > Status = “Completed“ for the successful line and Refund Row > Status = “Error“.

Note: The error message stating which Order Item Line failed is stored in Order Error table.

  • If all transactions failed we mark Order Payment > Status = “Error“, Refund Row > Status = “Error“ and store the error in Order Error table.

How to decide when to make a cancellation or refund is stated on the order. There are two flags which we can rely on in the order payload called "can_cancel" and “can_refund“ based on them we will know which is the correct request. If we have a case where both flags are set as true we pick as default the cancellation flow,

Is this article helpful?
0 0 0