Overview
Offramps with transfers let your users convert stablecoin to international fiat currencies through a quote-based flow. Unlike payment routes, which create persistent pipes for USD offramps, transfers are one-time operations with locked exchange rates and fees. Use transfers for international payouts to currencies like COP, MXN, and BRL. The process involves three steps:- Create a payment account: register the user’s bank account details as a payment account.
- Create a quote: get a quote with the exchange rate, fees, and destination amount.
- Create a transfer: execute the transfer using the quote before it expires.
Before you begin
Make sure you have:- API access to the payment accounts, quotes, and transfers endpoints.
- User bank account details: the destination bank account information (details vary by country and rail).
- A stablecoin source: users need stablecoin on a supported chain to transfer.
Key concepts
Payment accounts
A payment account is a stored representation of a user’s bank account or other fiat destination. See Payment Accounts for the general concept and the US-specific fields; this page covers the additional fields required for international destinations. For international transfers, you’ll create anexternalFiatAccount type payment account containing the user’s bank details for the destination country.
Quotes
A quote locks in the exact exchange rate, fees, and destination amount for a transfer, unlike an exchange rate preview, which is indicative only and doesn’t lock anything in. Quotes have an expiration time, so you must create the transfer before the quote expires. Key information in a quote includes:- Exchange rate: the rate used for currency conversion, excluding fees.
- Fees: breakdown of Rain fees and any sender fees.
- Destination amount: the exact amount the user receives in fiat.
- Expiration: when the quote expires and is no longer valid.
Transfers
A transfer executes the movement of funds from crypto to fiat using a locked quote. When you create a transfer, Rain generates adepositAddress where the user sends their stablecoin. Once Rain receives the funds, it automatically converts and sends them to the destination bank account.
API flow
Action / API callExternal / networkWebhook Rain sends you
Step 1: create a payment account
Before creating a quote, you must register the user’s bank account as a payment account. The required fields vary by destination country.Request: Colombian peso (COP)
Colombia supports multiple rails:
co_ach for bank transfers, co_bre_b for
Bancolombia transfers, and co_mobile_wallet for mobile wallet payments.Request: Mexican peso (MXN)
Request: Brazilian real (BRL)
Brazil supports
br_pix for instant PIX payments and br_ted for traditional
bank transfers.First-party and third-party transfersRain supports both first-party and third-party transfer destinations:
- First-party (
thirdParty: false): the bank account belongs to the same user initiating the transfer. - Third-party (
thirdParty: true): the bank account belongs to a different party, for example a vendor or another individual.
Response
Required fields by rail
Colombia (COP)
Mexico (MXN)
Brazil (BRL)
Additional fields may be required depending on the transfer amount or specific
compliance requirements. Contact your Rain representative for detailed
requirements.
Step 2: create a quote
Once you have a payment account, request a quote to see the exchange rate, fees, and destination amount.Request
You can optionally specify a source
address if you know which wallet will be
sending the funds. Some rails may require this information.Response
Quote fields
Step 3: create a transfer
If the user is happy with the exchange rate and fees, create a transfer using the quote.Request
Request parameters
Headers
Reusing an
idempotency-key with a different request body returns a 409 conflict. Generate a new key for each distinct transfer.Response
The response includes the transfer details along with adepositAddress where the user sends their stablecoin:
Response fields
Alternative: fund a transfer from fiat
Instead of funding a transfer with crypto, you can quote a fiat source such aswire or ach. The transfer then comes back with a fiat depositAddress containing bank deposit instructions, and you send the source amount there instead of to an onchain address.
Quote request (fiat source)
Quote response (fiat source)
Transfer request (fiat source)
Transfer response (fiat source)
A fiat-source transfer returns a
depositAddress with type: "fiat": the
bank deposit instructions to fund it. Send exactly the source amount, and
include the transferMessage reference with your payment so Rain can match
the funds to the transfer. A fiat source doesn’t need a refundAddress.What happens when crypto is deposited
When a user sends stablecoin to the deposit address:- Crypto received: Rain detects the incoming stablecoin transfer.
- Transfer created: a transaction of type
transferis created, and atransactionTransferwebhook with actioncreatedis sent. - Validation: the amount and currency are validated against the transfer.
- Conversion: stablecoin is converted to the destination fiat currency.
- Status updates: as the transfer progresses,
transactionTransferwebhooks with actionupdatedare sent for status changes. - Fiat transfer: funds are sent to the user’s bank account via the specified rail.
- Transfer completed: the transfer settles, and a
transactionTransferwebhook with actioncompletedis sent.
Webhooks
Rain sends webhooks during the transfer lifecycle to keep you informed of status changes:
See the transfer object reference for the full webhook payload schema.
Transfer statuses
Query transfers
You can query all transfer transactions via the Transactions API. Filter bytype=transfer to see transfer transactions:
Cancel a transfer
To cancel a transfer that hasn’t completed, callDELETE /v1/transfers/{transactionId} with the transaction ID the create call returned:
200 with the transfer, its status now cancelled. Once a transfer passes the point where it can be stopped, the call returns 409 with Transfer can no longer be cancelled.
Supported configurations
Source (crypto)
Source (fiat)
Destination (fiat)
Additional currencies and rails are being added regularly. Contact your Rain
representative for the latest supported configurations.
Error handling
Quote errors
Transfer errors
If you receive a
503 response with TransferPersistenceError, your transfer has already been initiated with the payment provider. Rain automatically reconciles the transfer asynchronously. Don’t retry the request, since this could result in duplicate transfers. Use the idempotency-key header to safely handle retries in case of network timeouts.Best practices
- Use idempotency keys: always include a unique
idempotency-keyheader with each transfer request to prevent duplicate transfers on retries. - Display quote details: show users the exchange rate, fees, and destination amount before they confirm the transfer.
- Handle expiration: implement logic to refresh quotes if the user takes too long to confirm.
- Monitor webhooks: set up webhook handlers to track transfer status in real time.
- Validate bank details: create payment accounts during user onboarding to catch errors early.
- Provide clear instructions: make sure users understand they must send the exact amount to the deposit address.
- Handle 503 responses: if you receive a 503 error, don’t retry immediately. The transfer may have been initiated and is reconciled automatically.
What’s next
Set up onramps
Enable fiat deposits into crypto.
Set up offramps
Enable fiat withdrawals from crypto via payment routes.
Payment accounts
See the full request, response, and field reference for registering a bank account.
Set up webhooks
Receive transfer notifications as they happen.