Deciding whether to offer a refund
Every on-ramp and off-ramp order carries two read-only fields that answer the question before you build the request:
The destination rule depends on the payment provider and, for crypto, on your account’s configuration:
refundDestinationRequired is the field to branch on — it is answered per operation, so you never have to keep your own table of countries and providers.
Requesting a refund
A cancelled off-ramp order whose trade already executed is not one of these: the crypto was sold, so there is no deposit left to send back and
refundable is false. What failed there is the fiat payout, and the way out is to retry it against another destination account — see Change Fiat Account and Reprocess. Refunding and reprocessing never apply to the same order.202 means the refund was registered, 200 means one already existed for that deposit and nothing new was created.
A fiat deposit that arrives but never matches an on-ramp order has no order to hang the refund off. Those are listed by List Refundable Deposits and refunded by depositUuid.
That listing answers two different questions, and includeRequested picks which one:
Ask for the wider list when you show the customer their own payments. Approval is not instant, so with the default list a deposit disappears from the only place it was visible right after the customer asks for it back; with
includeRequested=true it stays, and latestRefund says what is happening to it. A deposit leaves that list once its refund reaches COMPLETED — the money is back in the customer’s account.
The listing has no refundable field, so in the wider mode a deposit being there no longer means it can be claimed. latestRefund is what tells them apart: null or REJECTED when a refund can still be requested, any other state when one is already under way.
The reverse also holds while on-ramp refunds are not enabled for your account: a deposit not being there does not mean it does not exist. Neither call offers a deposit you could not refund anyway, so the claimable half is left out of both. What ?includeRequested=true still returns is any deposit whose refund Ripio support already started for the customer — that money is moving, and the customer’s screen has to be able to say so.
Following the outcome
ThelatestRefund block on the order (and on each refundable deposit) carries the state of its most recent refund, or null if there never was one:
rejectionReason is empty unless the refund was REJECTED:
A rejection is not final: nothing was paid out, so
refundable stays true and the refund can be requested again.
initiatedBy tells you who originated it, which matters because a refund is not necessarily one you asked for — Ripio may return a deposit on its own after a failed order, or register one on the customer’s behalf. On-ramp: PARTNER, SYSTEM or OPS. Off-ramp: PARTNER, WIDGET (the end user, from the widget) or OPS.
A refund emits an event only when it completes:
ON-RAMP.ORDER.REFUNDED and ON-RAMP.DEPOSIT.REFUNDED on the on-ramp, OFF-RAMP.ORDER.REFUNDED on the off-ramp. Every other transition is silent — in particular a rejection is never an event on either ramp, so latestRefund is the only way to learn about one. Poll it if you need to know that a refund was declined.The off-ramp event carries no hash of the returned crypto: read refundedTxnHash on the order for that.