> ## Documentation Index
> Fetch the complete documentation index at: https://waffo.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Stablecoin Exceptions & Refunds

> What happens when a shopper overpays, underpays, pays late, or pays on the wrong chain or with the wrong token — where you can and cannot see those cases, the exact address format a USDC/USDT refund must use, and why a stablecoin refund is all-or-nothing.

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](/docs/en/support/stablecoin-payments-faq);
rules common to all payment methods are in the [Refund FAQ](/docs/en/support/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.

| Case | What happened | Order succeeds? | Where the funds go |
| - | - | - | - |
| `OVERPAID` | Received amount above the order amount | Yes | You are settled on the order amount; the excess goes back to the paying address |
| `UNDERPAID` | Received amount below the order amount | No | Returned to the paying address |
| `LATE_PAID` | Transfer arrives after the payment window closed | No | Returned to the paying address |
| `WRONG_TOKEN` | A token other than the order's USDC/USDT was sent | No | Held for manual handling |
| `WRONG_CHAIN` | Sent on a chain other than the order's | No | Held for manual handling |
| `NO_MATCH_ORDER` | The transfer cannot be tied to any order | No | Held for manual handling |
| `UNSUPPORTED_WALLET_ADDRESS` | The paying address cannot receive an automatic return | As per the case above | Held for manual handling |

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](/docs/en/developer-docs/use-cases/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:

```json theme={null}
{
  "refundRequestId": "refund_20261008_001",
  "acquiringOrderId": "<acquiringOrderId>",
  "merchantId": "<merchantId>",
  "requestedAt": "2026-10-08T14:30:00.000Z",
  "refundAmount": "10.00",
  "refundReason": "Customer requested a refund",
  "extendInfo": "{\"refundAddress\":\"<customerRefundAddress>\"}"
}
```

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:

| Address family | Format accepted | Also rejected |
| - | - | - |
| EVM chains (Ethereum, Polygon, Arbitrum, Base, Optimism, Avalanche, BNB Smart Chain) | `0x` followed by 40 hexadecimal characters | The all-zero address. On Avalanche, X-Chain and P-Chain addresses — a C-Chain EVM address is required |
| Solana | 32–44 Base58 characters, case-sensitive | — |
| Tron | `T` followed by 33 Base58 characters, checksummed | An address whose checksum does not verify |

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](/docs/en/essentials/payment-methods) 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](/docs/en/support/payment-method-config-and-limits-faq).

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.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.