/api/v1/order/refund, /api/v1/refund/inquiry, Refund order notification).
Can I refund the same order more than once?
It depends on the payment method and your contract configuration:- Multiple partial refunds supported — each refund is validated so that
refunded + in-progress + current request ≤ original payment amount. A
single order allows up to 50 refunds in production; exceeding this returns
error
A0027. Sandbox and test environments use a lower cap, so hittingA0027there after only a few refunds is expected, not a bug. Every refund response includesremainingRefundAmountso you can track what is still refundable. - Not supported — once one refund has completed for the order, any further refund request is rejected.
refundStatus) to ORDER_PARTIALLY_REFUNDED; it only becomes
ORDER_FULLY_REFUNDED when the total successfully refunded amount equals the
order amount. The order’s orderStatus itself is not changed by a refund —
a fully refunded order still reports PAY_SUCCESS.
Why was my refund rejected?
A refund request must pass all of the following preconditions:
Validity windows and multi-refund support are
contract-dependent — check your contract in the Merchant Portal or contact
integration support for your exact configuration.
My refund request timed out. Can I safely resend it?
Yes.refundRequestId is the idempotency key:
- Resending with the same ID and same amount returns the current refund status; if the refund is still in an intermediate state, processing is pushed forward.
- Resending with the same ID but a different amount is rejected.
refundRequestId only when you intend to create an additional refund.
How are cross-currency refund amounts calculated?
When the user paid in a currency different from your order currency, the refund amount you submit (in order currency) is converted to the user’s currency. Two rules apply:- Round down — converted refund amounts are always rounded down, so the total refunded never exceeds what the user actually paid.
- Last refund tops up — with multiple partial refunds, FX rounding could
leave the refunded total slightly below the payment amount. The final
refund that exhausts the remaining balance returns the full remainder, so
a fully refunded order truly reaches
ORDER_FULLY_REFUNDED.
finalDealAmount in the refund inquiry response is the actual amount
the user receives in their currency.
I cancelled the order, but the user says they already paid
Cancellation only works on orders still in an intermediate state. If the user has in fact completed the payment, the cancel request fails and the order proceeds as a successful payment — you receive a payment success notification. To return the funds at that point, use the refund API; do not retry the cancel.How long does a refund take? The status stays in progress
Refunds are asynchronous. A successful/api/v1/order/refund call means
the request was accepted (REFUND_IN_PROGRESS), not completed. Waffo then
processes the refund with the payment method and automatically retries
recoverable failures until a final state is reached.
- Provide
refundNotifyUrlto receive the final result via the refund order notification, or poll/api/v1/refund/inquiry. - A refund is final only at
ORDER_PARTIALLY_REFUNDED,ORDER_FULLY_REFUNDEDorORDER_REFUND_FAILED— treatREFUND_IN_PROGRESSas pending, not failed.
Do all payment methods support API refunds?
No, and there are two distinct cases. Refunds not permitted. Two codes, two meanings.A0017 (“payment channel
not supported”) means the payment method itself cannot carry a refund — full or
partial. A0014 (“refund rules”) means the method can refund but your
agreement’s refund shape does not allow this request: a partial refund on a
full-refund-only row, or a second refund where only one is permitted. Asking for
more than the remaining refundable amount is a third thing again — a plain
A0003 parameter failure. See
Refund Limits by Payment Method.
Refunds needing extra fields. Some refunds require additional user
details, such as bank account information, because the money is returned by
transfer rather than reversed on the original payment. Which fields are
required is configured per channel, so do not decide it from the payment
method in your own code. Submit the refund; if fields are missing the API
returns A0003 together with the list of missing field names, and you resend
with those fields filled in.
For some payment methods refunds are executed over payout rails on Waffo’s
side — your API contract stays the same.
Can I submit many refunds at once?
Yes — the Batch Refunds page under the Portal’s Transaction module. It is enabled per merchant account, so if the page is not there it has not been switched on for you; ask support. The template and upload buttons are visible only to the roles that can already initiate a single refund. The flow is: export the batch refund template (CSV), fill it in, upload it, confirm the summary dialog (record count, total amount, currency), and Waffo creates a Refund Batch ID in the formBRP + MID + YYYYMMDD + a 6-digit
sequence — for example BRP<your merchant ID>20260225000001.
My whole batch file was rejected. Why?
Upload validation is all-or-nothing: a single bad row rejects the whole file, and you correct it and upload again. What is checked:- The file — must be the exported template in CSV, with exactly its four columns and no extra ones; not corrupted, encrypted or empty; at most 2,000 records and 2 MB; and not a file already uploaded before (duplicates are detected from the file content, not the name).
- Currency — one refund currency for the entire file, and it must equal each original order’s currency.
- Each row — the original order exists, is paid and not yet fully refunded, its payment method allows refunds, it is still inside the refund window, the amount is above zero and no more than the remaining refundable amount, and the order has no refund already in progress.
- Duplicates — the same order may not appear twice in one batch.
- Batch total — the file’s total must be covered by your pending-settlement balance plus your refund reserve balance at upload time.
How do I track a batch after submitting it?
Rows are processed independently: a failing row is marked with its reason and the rest continue — one failure does not stop the batch.
The batch list shows total / success / failed / in-progress counts, the batch
amount and currency, and the creation and update times. Every refund carries
its Refund Batch ID, so you can filter the refund list by batch, open any
individual refund’s detail as usual, and export the batch result including
failure reasons. There is no retry action on a batch — resubmit the failed
rows in a new file, or refund them one at a time.