Which identifiers does a refund carry, and which do I quote to whom?
A refund carries up to six identifiers, three of which are yours and three of which are Waffo’s:
Choosing between them:
- Talking to Waffo support →
acquiringRefundOrderId, plusacquiringOrderIdif the question involves the original payment. - Reconciling your own books →
merchantRefundOrderIdandorigPaymentRequestId. These are the only two that mean anything inside your system. - Retrying a refund →
refundRequestId, unchanged. A new one creates a new refund; that is the whole point of the field. - Talking to the customer → none of the above. The customer sees the
original payment’s reference in their own payment history, which comes back
on the original order as
payMethodRefIdinsidepayMethodResponse. If you need to point a third party at the money, that is the reference they will recognise — see Which Amount and Currency Fields Do I Check?.
merchantRefundOrderId and refundRequestId are visible as columns in
Portal → Transactions → Refunds, so a refund raised through the API can be found
in the Portal by your own number, and one raised in the Portal can be found by
its Waffo number.
Why does a refund ask me for the customer’s bank account, name or nationality?
Because for some payment methods the money cannot simply be pushed back along the path it came — the refund is executed as a payout to the customer, and a payout needs payee details that a payment never required. It is a property of the payment method, not of your account or of the individual refund. The API models this on the refund request as an optionaluserInfo object that
becomes mandatory when the method requires it:
Where do you get the values? From the customer. Waffo does not hold the
customer’s bank account, and neither did the original payment — which is exactly
why the field is being asked for. In practice this means a refund on one of these
methods is not a one-click operation: you have to go back to the customer for
their account details first, so build that into your returns process rather than
discovering it at the moment you press Refund.
You are told which fields are missing, rather than having to guess. Both
entry points work the same way:
- In the Portal, opening the refund drawer asks for exactly the fields that order needs, with a searchable bank list where a bank has to be chosen from a fixed set and a country list for nationality. Names are capped at 60 characters, other text fields at 64, and the phone number is validated against the payment’s country dial code. Middle name is the one optional field.
- Through the API, a refund submitted without a required field comes back telling you which field paths are missing, so you can collect those and resubmit. It is normal for a second round to ask for more than the first — supply what you are asked for and resubmit rather than pre-filling everything.
I typed the bank account wrong and the refund failed. Can I fix that refund?
No. A refund record is not editable, and there is no “correct and resend” action on a failed one. Raise a new refund, with a newrefundRequestId, and the
corrected details.
Two things to check before you resubmit:
- The refundable amount. Use
remainingRefundAmountfrom the refund response or refund inquiry rather than assuming the failed attempt released everything — it is the authoritative figure and it already accounts for every refund on the order. - The details themselves. A refund that failed on wrong payee details will fail again on the same details. Confirm the account with the customer, not from your own records.
refundRequestId will not help either: it is the idempotency
key, so resending it asks for the original refund back rather than for a new
attempt with new details. Idempotent-retry behaviour is covered in
Refund FAQ.
Can a customer start a refund themselves?
No. A refund is initiated by you — through the Portal or through the refund API — and there is no customer-facing path to one. The Waffo checkout does not offer a refund action, and neither does the subscription self-management page a customer can reach: cancelling a subscription there stops future charges, it does not reverse past ones.refundSource on a refund record makes the same point in field form. Its four
values are:
There is no customer value, because there is no customer path. What a customer
can do is raise a dispute with their bank, which is a different mechanism with
different money and different deadlines — see
Chargeback FAQ.
Practical consequence for your product: if you want self-service returns, build
the request flow on your side and call the refund API when you approve it. Do not
wait for a customer-facing Waffo screen to point them at.
I already refunded the customer myself. Will calling the refund API pay them twice?
Yes. A refund raised through Waffo is a real movement of money, and Waffo has no knowledge of anything you settled with the customer outside the platform — a bank transfer you made yourself, a store credit, a cash refund at a counter. Nothing reconciles the two, so a refund call after an off-platform refund pays the customer a second time. The safeguard is the refund record itself, not a check Waffo can perform for you:- Read the order’s refund history before refunding, in the Portal or via
refund inquiry, and read
remainingRefundAmount. That tells you what Waffo has already sent — including refunds you did not raise. - Record off-platform settlements in your own system and gate your refund action on that. This is the only place that information exists.
- Prefer refunding through Waffo where the payment method allows it, precisely so that the refund lands in the same record as the payment.
Can I refund only part of the amount from the Portal?
Yes. The Portal’s refund drawer opens with the full refundable amount pre-filled and the amount field is editable: you may enter any amount greater than zero and not more than the payment amount, in the order’s currency and within that currency’s decimal precision. A reason is mandatory alongside it, and you confirm the exact figure in a dialog before the refund is created. Whether a second partial refund is then available on the same order is a payment-method question, not a Portal one — some methods permit one partial refund and no more. See Refund Limits by Payment Method before you plan a staged refund, and note that a stablecoin order refunded from the Portal additionally requires a receiving address on the original chain.The refund record says RDR, ETHOCA or CDRN. Can I still refund the order?
That order has already been refunded automatically, to head off a dispute the
alert service saw coming. So:
- No further refund is available on that order. As soon as the order carries
a non-failed refund raised by the chargeback alert service, every later refund
attempt is rejected with a dedicated error —
A0039 Order has already been refunded by chargeback alert service— whatever the amount. The check does not look at whether the automatic refund covered the full payment, so aremainingRefundAmountgreater than zero on such an order does not mean you can refund the rest through the API or the Portal. If you believe money is still owed to the customer, that is a support case. - Do not refund the customer again outside Waffo on the assumption that the
automatic refund did not happen. Read the refund record first — that is what
refundSourceis for.
A0019). The distinction matters: A0039 means already refunded,
A0019 means locked while the dispute runs. Neither is retryable as-is.
When does the refund webhook fire, and where does it go?
It fires when the refund reaches its final state — completed or failed. There is no intermediate “refund accepted” webhook, so you will not receive a notification forREFUND_IN_PROGRESS.
Where it is delivered:
The event type is
REFUND_NOTIFICATION, and its body is the same structure as
the refund inquiry response, so one parser serves both. That is deliberate: an
integration that can read refund inquiry can read the webhook, and polling is a
legitimate fallback rather than a second implementation.
Two operational notes. refundNotifyUrl is capped at 256 characters — shorter
than the payment notifyUrl — and the same delivery rules apply as for payment
webhooks: reachable HTTPS on a standard port, and the expected success response
body. Delivery troubleshooting is in
Webhook retry and
Portal webhook log.
Can I get the refund result by polling instead of waiting for a webhook?
Yes./api/v1/refund/inquiry returns the refund’s current state and is the
documented fallback when you have no notification URL configured, when signature
verification fails, or when you simply want the answer now. It returns
refundStatus, refundFailedReason when it failed, refundCompletedAt,
remainingRefundAmount and the full identifier set.
The same applies to payments — Order Inquiry is a first-class way to get a
result, not a workaround. What polling does not do is remove the need to handle
the webhook: build the webhook path, and use inquiry to close gaps and to answer
“where is it now” questions from your support team.
How long does a refund take to reach the customer?
It depends on how they paid, and the honest range is wide. Waffo’s part — moving the refund to its final state — is whatrefundStatus reports; the last leg is
in the hands of the customer’s bank, card issuer or wallet provider, and Waffo
does not commit to a delivery date for it. The Portal’s support screen shows
indicative processing times per payment method; use those as the reference when
you talk to a customer. The shape of the answer is stable even if the figures are
not:
How to use this with a customer:
- While the refund shows as in progress, tell them the refund is moving; there is nothing to escalate.
- Once the refund shows as completed and the money still has not arrived
after the indicative window for their method, that is worth reporting — with
the
acquiringRefundOrderId. - Do not promise a date. Card refunds in particular land on a statement cycle, not on a day you can predict.
Does a refund give the customer back the fees and taxes they paid?
Not necessarily, and the API is explicit about it: on a refund, thefinalDealAmount — the amount the customer receives — may exclude a
service or tax fee the customer originally paid, which is why it can be smaller
than the corresponding order amount.
So there are two different amounts to keep straight when you communicate with a
customer:
Tell the customer the second one. If your policy is to make them whole including
fees, you have to price that in yourself; a refund of the order amount does not
automatically carry the fees back.
What happens to the fee you paid on the original payment, and to a
merchant-borne tax, is a settlement question rather than a refund-record one —
see Refund FAQ and
Fee & Tax Treatment.
How long can the refund reason be, and does the customer see it?
refundReason is mandatory on every refund. The limit depends on where you
raise it: the API accepts up to 256 characters, and the Portal’s refund form
caps the field at 128 with a live character count.
It is an internal annotation: it is carried on the refund record, appears in the
Portal and comes back on refund inquiry, and it is what your own support team
reads six months later. Write it for that reader — an order reference, a returns
ticket number, a short reason — rather than as a message to the customer.
Where do I see my refunds, and what can I export?
Portal → Transactions → Refunds is the list. Its columns cover the whole identifier set plus the state of each refund:
The list filters on the refund identifiers, status, currency, Refund Batch ID and
created datetime, and it can be exported. Exports run as background tasks with
their own span and size limits and their own status list — including the case
where an export succeeds with a non-zero failed count — all of which is in
Export Center. Which columns the transaction and
refund exports carry is in
Payment Method Config & Limits.
If a refund you raised through the API is not in the list, search by your own
refundRequestId or merchantRefundOrderId before concluding it was lost — those
are columns, and a refund is findable by your own number.
The refund says it succeeded but the customer says the money never arrived
Work through it in this order, because three different situations produce the same complaint:- Check the indicative window for their payment method (the Portal’s support screen shows it). A card refund that has not yet reached the next statement cycle is not late.
- Check
finalDealAmount, notrefundAmount. If a fee was not returned, the customer received less than they expected and may read that as “not arrived”. - Check where the money was sent. On methods refunded to a wallet balance it goes to the wallet, not the card behind it — a customer looking at their card statement will not see it.
acquiringRefundOrderId and the date. Refunds that report success but
fail downstream, and refunds that end in ORDER_REFUND_FAILED, are covered in
Refund Limits by Payment Method.
Refunding a stablecoin payment has its own required field — a receiving address
on the same chain — and its own rules about who pays the network fee; those are
in Stablecoin exceptions.
Need a refund traced? Contact support with the
acquiringRefundOrderId.