Skip to main content
Whether a refund is allowed is covered elsewhere; this page is about the refund record — its identifiers, the extra details some refunds ask you for, how you are told the outcome, and what to tell a customer who is waiting.

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, plus acquiringOrderId if the question involves the original payment.
  • Reconciling your own books → merchantRefundOrderId and origPaymentRequestId. 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 payMethodRefId inside payMethodResponse. 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?.
Both 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 optional userInfo 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.
The general mechanism, and the notation used for the field paths, is in Conditionally Required Fields by Payment Method.

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 new refundRequestId, and the corrected details. Two things to check before you resubmit:
  • The refundable amount. Use remainingRefundAmount from 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.
Reusing the same 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.
The same logic applies in reverse: an order Waffo has already refunded does not need a second gesture from you, and paying the customer again off-platform is the mirror-image mistake.

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 a remainingRefundAmount greater 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 refundSource is for.
An order under an active dispute is separately blocked from refunds, with its own error (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 for REFUND_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 what refundStatus 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.
Whether a refund can be made at all on a given method, and the per-method deadlines for making it, are a different question — see Refund Limits by Payment Method.

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, the finalDealAmount — 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:
  1. 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.
  2. Check finalDealAmount, not refundAmount. If a fee was not returned, the customer received less than they expected and may read that as “not arrived”.
  3. 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.
If all three check out and the money is still missing, that is a support case: send the 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.