Skip to main content
The Refund FAQ covers the rules that apply to every refund: amount validation, idempotent retries, cross-currency conversion, asynchronous status, and fee return. This page answers the question that comes after those: why the identical request succeeds on one payment method and is rejected on another. Cross-currency arithmetic lives in Exchange Rates, and the error codes involved are in Error Codes & Limits Supplement. The short version: refund capability is a property of the payment method, not of your account. Two methods enabled on the same account, charged through the same integration, can have completely different refund behaviour.

Why does the same refund request succeed on one payment method and fail on another?

Because each payment method carries its own refund rules, and Waffo does not soften them. The API surface is identical for every method — the difference is which requests the method accepts. The table below groups the behaviour we see by payment-method category. Treat it as the shape of the variation you have to design for, not as a lookup table for a specific method: the exact rules for the methods enabled on your account are part of your payment-method configuration. Three consequences worth designing for:
  1. Do not hardcode “this method supports partial refunds” in your own code. Submit the refund and handle the rejection.
  2. Do not assume that because one method on your account supports something, another does.
  3. A refund that Waffo accepted can still end in a failed final state.

Is partial refund available on every payment method I have enabled?

No. Partial refund is a capability that has to be available for the specific payment method and enabled for your account — it is the Refundable column on your Service → Payin row. Where the row permits only a full refund, a partial refund request is rejected with A0014 (“Order cannot be refunded due to refund rules”) while a full refund on the same order succeeds. The same code is returned when the row allows one partial refund and you ask for a second. A0017 (“Order cannot be refunded due to payment channel not supported”) is a different failure: the payment method itself cannot carry a refund at all, so neither a partial nor a full refund goes through on it. Where a payment method could behave in more than one way, the most restrictive option applies. Practically:
  • If a method can refund only in full for your account, partial requests fail even though the method is capable of partial refunds elsewhere.
  • If a method allows only one partial refund for your account, the second request fails even though the first succeeded.
Waffo does not silently downgrade a partial refund into a full refund, and does not queue it for later. If you need a capability that is currently rejected, ask your Waffo integration contact whether it can be enabled — it is a configuration change, not something you can pass as a parameter.

How many refunds can one order take?

Three separate ceilings apply, and you hit whichever is lowest: Some methods start at exactly one partial refund per order and can be raised from there; a few place no limit on the count at all. Because the lowest ceiling wins, build your reconciliation so that a rejected second refund is a normal branch, not an incident.

Is there a deadline for refunding an order?

Yes, and the clock always starts at the original order, never at the moment you decide to refund. The window is a property of the payment-method row on your account, and you can read it in two places rather than guessing: The shape varies by category — prepaid electronic money and post-pay methods tend to have the shortest windows, cards the longest, subject to the issuer — but the figures are per method and per account, so do not carry one method’s window over to another. After the window closes the refund is rejected — there is no override. If your product allows returns over a long period, check the refund window of the methods you accept before you publish the policy, and settle late returns outside the original payment.

I refunded the order, but its orderStatus is unchanged. Did the refund work?

Yes, most likely. A refund does not change the original order’s status. The original order stays in the state it reached when it was paid; the refund is a separate record with its own status, and that is the only place refund progress appears. So “the order still shows as paid” is not evidence that the refund was lost. If your bookkeeping keys refund state off the original order, it will look permanently stuck — key it off the refund record instead.

I resent a refund immediately and it was rejected as a duplicate. Was anything refunded?

Probably not by the second request — that is what the protection is for. Two kinds of guard exist:
  • Duplicate detection. Some methods reject a second request that carries the same original transaction reference and the same amount within a short window — a rule commonly seen on wallets that otherwise place no limit on the number of partial refunds.
  • Minimum interval. Some methods require a short gap between consecutive refund requests on the same order.
Both are protections against accidental double refunds, so do not treat the rejection as a failure to be retried in a tight loop. The safe pattern:
  1. Keep the same refundRequestId when you resend the same refund — it is the idempotency key, and it makes a retry harmless.
  2. Do not fire genuine second refunds on the same order back-to-back; let the first reach a final state.
  3. Between attempts, call /api/v1/refund/inquiry rather than resending.

The user closed or deleted their account. Can I still refund them?

Not always. On post-pay / credit methods a closed user account blocks partial refunds, and once a defined period has passed since the closure the refund is rejected outright. Full refunds usually remain possible for longer. There is no way for Waffo to route around a closed account: the money has to go back to the account it came from. If the refund is rejected for this reason, settle with the user by other means.

Can I refund before the payment is captured?

Only in full. On methods where authorization and capture are separate steps: Capture itself has a deadline too, and the capture amount can never exceed the original authorized amount. If you need to return part of an authorization, capture the amount you are keeping rather than capturing the whole authorization and refunding the difference.

Why can one method on my account only be refunded in full while another accepts several partial refunds?

Because refund capability follows the payment method, not the account. It is routine for one account to have a card method that is full-refund only next to a wallet method that accepts repeated partial refunds. Nothing about your account, your contract type, or the API you call changes that. The design implication is concrete: your refund UI and your customer-service scripts should be driven by the method that was used on the order, not by a single account-wide rule.

Is there a minimum refund amount, and a maximum?

The maximum is always the same: the original payment amount, less anything already refunded or in progress. There is no payment method on which you can return more than was taken; asking for more is rejected with A0003. The minimum is the practical one people trip over. It is the smallest amount the currency can express, and on cross-currency orders it is the smallest amount the converted figure can express — which is why a refund that looks non-zero to you can be rejected. If the converted amount comes out as zero or below, the refund is rejected with A0014; see Limits, Currency & Configuration Errors. A useful habit for cross-currency orders: refund by proportion of the original order rather than by an absolute figure in your own currency, so the converted amount scales with the original payment instead of rounding away.

The refund reports success, but the user says the money has not arrived

Both statements can be true at once. A successful refund means the refund request completed successfully — it does not mean the funds have already landed in the user’s account. Settlement of the refund is keyed off that successful result, not off the user’s balance. In practice the money follows quickly on most methods, but the two events are distinct and the gap is outside Waffo’s control: So the support answer is “the refund has gone through; how quickly it shows up depends on the user’s bank or wallet”. Escalate to Waffo support only when the refund has been in a successful final state for a materially long time and the user still cannot see it — and bring the original order ID and the refund ID.

The refund ended in ORDER_REFUND_FAILED. What happened, and what do I do?

ORDER_REFUND_FAILED is a final state — the money did not move and will not move on that refund record. The most common cause on card payments is that the issuing bank declined the refund after Waffo had already accepted the request, which is why the failure arrives asynchronously rather than as an API error. What to do:
  1. Read the refund order notification or /api/v1/refund/inquiry for the reason.
  2. Do not resend with the same refundRequestId expecting a different outcome — a final state does not reopen.
  3. If the decline is not explained by the amount, the window, or the method’s rules, raise it with Waffo support with the original order ID and the refund ID. Refunds that fail for a reason outside your control are handled case-by-case.
  4. Where the card cannot be credited at all, settle with the user by another route.

Which of these limits apply to me, and where do I look them up?

There is no single “refund capability” field you can read before submitting. What you can rely on:
  • The Merchant Portal → PayIn page lists the payment methods enabled for your account, with their currencies and amount limits.
  • /api/v1/paymethodconfig/inquiry returns the same configuration programmatically.
  • The refund API’s rejection is the authoritative answer for a specific request: A0014 means the agreement’s refund rules do not allow it (shape, count, window, or a converted amount that rounds to nothing), A0017 means the payment method cannot carry a refund at all, A0027 means the platform count ceiling was reached, and A0003 means the amount exceeds what is left or required refund fields are missing and are listed in the response.
Because of that, the robust integration pattern is attempt, then branch — not predict, then attempt.

Where do I look next?