Skip to main content

Create a return

POST 

/returns

Takes some or all lines of a paid order back. The server prices the refund from the original order; you send the lines, not the amounts. A new return answers 201; a retry with the same Idempotency-Key answers 201 with the same record.

Before you call​

  • The company needs a plan with returns.
  • With X-User-ID, the acting user needs the return permission and an open shift at the outlet.
  • Without X-User-ID (MPOS-2389): you may return your own partner order with no acting user and no open shift. The call then runs as your order source, the same actor as POST /orders without a user. All of these must hold:
    • the order was created by your application's order source with POST /orders;
    • every refund_tenders row names your source's partner rail: the payment_method_id of the order's tender on that rail. Never cash, never another payment method;
    • the outlet needs no approval for returns, and you send no approval_token.
  • Anything else without X-User-ID answers 400 USER_ID_REQUIRED. Exchanges always need X-User-ID and an open shift.
  • Send approval_token when the outlet needs an approval for returns (this needs X-User-ID).
  • An order of a kitchen sales type (dine_in, takeaway, pickup, delivery, qr_ordering) can be returned, refunded or exchanged only once its kitchen ticket is served or completed (kitchen_status on GET /orders/{id} is served or completed). Other sales types and the replacement order of an exchange are not affected.

Request​

  • A returned line names a line of the order by order_line_id.
  • refund_tenders: each row names an eligible tender of the order by payment_method_id (from eligible_refund_tenders of POST /returns/quote) or the cash method.
  • More than one tender is allowed only for a full refund of an untouched order, and the amounts must add up to the refund.

Behaviour​

  • On a Terms Payment order the list holds the tenders of its settlement payments in place of the Terms Payment line.
  • A group with refundable: false (for example reason: legacy_tender, a tender recorded without a payment method) is refused: refund it in POS, or to another eligible tender.
  • A partner order (one created with POST /orders) is refunded to the original tender, never in cash.
  • A cash refund larger than the shift's petty cash records nothing.
  • Returning a kitchen sale that has a kitchen ticket moves no stock back.
  • A Dine In table bill is several orders, one per round: return, refund or exchange one round at a time. Reverse the rounds a table settlement paid instead of the settlement itself.
  • A Dine In round paid through a table settlement lists its share of the settlement's tenders in eligible_refund_tenders.
  • The kitchen check runs before the approval, the petty cash and the tenders, so an approval_token is not used up.

Retries and idempotency​

  • After a timeout or a network error, retry with the same Idempotency-Key and the same body: the stored answer is replayed, or the write runs once.
  • An error from this call is stored under the Idempotency-Key: after you fix the cause, send a new key. But never send a new key after 409 DATA_CONFLICT (see the next bullet).
  • On 409 DATA_CONFLICT the same request is already recorded or still being committed, or the acting user's shift was closed while it ran.
  • Do not send the same request again with a new Idempotency-Key: a new key can create a second return. First read GET /returns?order_id= for the order, and create again with a new key only if the return is still absent after a short wait.
  • 409 KITCHEN_NOT_FULFILLED is not stored: once the kitchen has served or completed the order, retry with the same key and the same body.

Errors​

StatusCodeWhen
400VALIDATION_FAILEDThe body is not valid. A line that is not part of the order has a field error on lines[i].order_line_id with code NOT_FOUND (INVALID_FORMAT when the order_line_id is not a UUID).
400IDEMPOTENCY_KEY_REQUIREDIdempotency-Key is missing.
400USER_ID_REQUIREDX-User-ID is missing, and the call is not your own partner order refunded to your rail with no approval (see Before you call).
403PLAN_FEATURE_REQUIREDThe plan has no returns. data.reason is not_in_plan or disabled (the merchant can turn it on in Settings > Features), and data.feature is the feature key. A missing Public API add-on answers the same code without data.
403APPROVAL_REQUIREDThe outlet needs an approval and no token was sent.
403APPROVER_NOT_ELIGIBLEThe token's approver is not allowed.
403APPROVAL_TOKEN_INVALIDThe token is unknown, used, expired, or issued for another order, user or type; see data.reason.
403PERMISSION_DENIEDThe acting user may not do this.
403OUTLET_FORBIDDENThe outlet is not allowed.
404NOT_FOUNDUnknown original order, or an order of another outlet.
409SHIFT_NOT_OPENYou sent X-User-ID and the user has no open shift at the outlet.
409INSUFFICIENT_PETTY_CASHA cash refund is larger than the shift's petty cash.
409IDEMPOTENCY_KEY_REUSEDThe key was used with another body.
409IDEMPOTENCY_IN_PROGRESSThe first request with this key is still running.
409DATA_CONFLICTSee Retries and idempotency.
409DINE_IN_ROUND_UNPAIDThe Dine In round's bill is not paid yet.
409SETTLEMENT_SALE_NOT_REVERSIBLEThe order is the payment record of a whole table (dine-in or online settlement).
409KITCHEN_NOT_FULFILLEDThe kitchen ticket is not served or completed, or there is no ticket; see data.kitchen_status (null when there is no ticket).
422UNPROCESSABLEA business rule failed; read message.
422POST_SALE_DISABLEDThe merchant turned this operation off in the post-sale policy.
422POST_SALE_WINDOW_EXPIREDThe order is older than the policy allows; data.max_days is the limit in days.
422INVALID_USERThe acting user is not valid.
422REFUND_TENDER_NOT_ELIGIBLEA tender id is not eligible, or its group has refundable: false; the field is in data.fields.
422PARTNER_REFUND_ORIGINAL_TENDERA partner order: a cash row is above the cash the order was paid with.
422REFUND_TENDER_INVALID_AMOUNTA tender amount is not above 0.
422REFUND_TENDER_DUPLICATEThe same tender appears twice.
422REFUND_MULTI_TENDER_REQUIRES_FULLMore than one tender, but not a full refund of an untouched order.
422REFUND_TENDER_SUM_MISMATCHThe tender amounts do not add up to the refund.
422REFUND_TENDER_EXCEEDS_REMAININGA Dine In round asks more of one non-cash tender than it can still take.

Request​

Responses​

The new return