Skip to main content
What happens when a stablecoin payment does not arrive as expected, and what you must send when you refund a USDC or USDT order. Order fields, chain selection and confirmation behaviour are in Stablecoin Payments; rules common to all payment methods are in the Refund FAQ.

What are the exception cases, and does the order still succeed?

Waffo classifies an off-spec transfer into one of these cases — the label is what support uses when you raise a ticket. Two rules run through the table: settlement is always based on the order amount, never on what was transferred; and a return of funds to the shopper is not a refund on your account — no refund order, nothing in your refund reports.

The shopper overpaid — do I get the extra?

No, the order completes at the order amount and the surplus is not yours. A small excess — within a tolerance of the order amount, or smaller than the cost of sending it back — is not returned and is not credited to you either; a larger excess goes back to the paying address, less that transfer cost. So never reconcile a stablecoin order against the on-chain amount.

The shopper underpaid or paid too late — can I still fulfil?

No, neither case pays the order, so do not release goods on the strength of an on-chain transfer you observed yourself. Waffo sends the received amount back to the paying address less the transfer cost; if it does not cover that cost, nothing is sent back. Guide shoppers to pay the full order amount in one transfer, inside the payment window on the payment page.

Wrong chain, wrong token, or an old address — will it auto-resolve?

No. WRONG_TOKEN, WRONG_CHAIN and NO_MATCH_ORDER are never handled automatically: the order does not succeed and the funds do not go back on their own. Raise a support ticket with the transaction hash, chain, token and order id. The usual cause of NO_MATCH_ORDER is a reused receiving address — addresses are issued per order, so if you cache one or let a shopper pay in twice, the second transfer matches no order.

Why is a return slow when the shopper paid from an exchange?

Automatic returns only go to a self-custody wallet (an EOA). Funds sent from an exchange withdrawal address or a contract address cannot safely be returned there — the address is not the shopper’s own — so the case goes to manual handling and takes considerably longer. Where you can, tell shoppers to pay from their own wallet rather than straight from an exchange account.

Where can I see these exception cases myself?

Nowhere in the Portal, and this is the honest answer rather than a missing screen: no merchant-facing view carries on-chain detail. The transaction list and the transaction detail have no chain column, no transaction hash, no confirmation count and no received-amount-versus-order-amount comparison, so an overpay, an underpay or a wrong-chain transfer is not something you can look up. What you can see is the order: it either reached a final success state or it did not. Everything above is a statement about where the funds went, not about the order, and none of these cases creates a refund order on your account — so they never appear in your refund list or refund reports either. That leaves one route when a shopper insists they paid: raise the order id with support, together with the transaction hash, chain and token the shopper can give you. Those four facts are what the case is identified by. The one exception is the x402 signature path, where a successful order returns an on-chain settlement receipt on the API, transaction hash included — see x402 stablecoin acquiring.

What must I send when I refund a stablecoin order?

A refund destination address is mandatory for every USDC and USDT refund. Send it in extendInfo on /api/v1/order/refund. The outer extendInfo value is a string containing JSON, not a nested JSON object. Here is a complete request body. Replace each placeholder with the value for your order and customer:
Set refundAmount to the full refundable order amount. The refund address must be valid for the original payment chain. Omit it and the request fails parameter validation up front with A0003 and the message Parameter validation failed ( missing refund optional field ). msgParams.missingFields contains extendInfo.refundAddress. No refund order is created, so there is nothing to inquire about afterwards; on fiat orders it is unnecessary and ignored if sent. Treat this as an integration change: if you already call the refund API and then add stablecoin acceptance, update your refund path first. Collect the address from the shopper yourself — Waffo cannot contact your shopper to ask for one.

Can I refund to a different chain, or to any wallet?

No to both. The chain is read from the original payment and locked; there is no chain parameter on the refund request and any attempt to supply one is ignored. The chain determines which address format is accepted, and the address is validated against that chain’s format when the refund is processed: Two format details worth building into your own input validation, because they are checked and they surprise people:
  • Mixed-case EVM addresses are checksum-verified (EIP-55). An address that is entirely lower-case or entirely upper-case is accepted as-is; one with mixed case must have a valid EIP-55 checksum. So an address that has been “tidied up” by hand — one letter re-cased — fails, while the same address all in lower case passes.
  • Tron addresses are Base58Check-decoded, not just pattern-matched. A single mistyped character fails the checksum rather than being accepted and failing later on-chain.
A rejected address fails with a message beginning INVALID_REFUND_ADDRESS_FORMAT, followed by the specific reason. Unlike a missing address, a malformed one is caught one step later — after the refund order has already been created — so the outcome is a refund order in ORDER_REFUND_FAILED, visible on refund inquiry and in the Portal’s Refunds list with that reason. Nothing moved on-chain. Because the failed record already exists, retrying with a corrected address is a fresh request with a new refundRequestId: resending the old id returns the failed record, not a new attempt. Check remainingRefundAmount before you resend. Use a self-custody (EOA) wallet address. A contract-based wallet, including a multi-signature wallet, is not supported as a refund destination, and the Portal states the same rule in the refund drawer. The Portal applies the same constraints: in the refund drawer the chain is a read-only label for the original payment chain, noted as “Refund must use the same chain as the original payment,” the address field is validated against that chain’s format as you type, and the detail page then shows the address used. No Portal view surfaces on-chain detail — no transaction hash, confirmation count or network fee.

Can I issue a partial refund on a stablecoin order?

No. The published payment method catalogue lists USDC and USDT as full refund only, and the refund-shape check enforces it: a refund for less than the full amount is refused, and so is a second refund after a full one. Confirm the shape that applies to your own agreement on the Refundable column of Service → Payin, or refundAllowed on your configuration response — the four shapes and their codes are explained in Reading Your Payment Method Configuration. So plan a stablecoin refund as one all-or-nothing action per order. If your business needs partial value returned, that is a commercial arrangement outside the refund API, not a partial refund.

Who pays the network fee on a refund?

Waffo. The on-chain cost of a merchant-initiated refund is not deducted from your settlement balance and not deducted from what the shopper receives — the shopper gets the full refund amount. That is the opposite of the exception cases above, where the return to the shopper is net of the cost of sending it.