Card funding workflow
1
Create the wallet
App The user logs in for the first time and the wallet is created. Read its addresses and send them to your backend.See Wallet creation.
2
Create the application with the wallet address
Backend Create the user’s consumer application with Full schemas: Create a consumer application, Create a corporate application.
walletAddress (and solanaAddress where relevant), then run KYC as usual. For a corporate program, the wallet goes on initialUser.walletAddress of the company application.3
Receive the collateral contract
Backend When the application is approved, Rain deploys the user’s collateral contract on your program’s chain and sends The
contract.created. The wallet on the application is the contract’s owner and appears in adminAddresses. You can read the contract at any time:Response (abbreviated)
tokens entries carry no symbol or decimals. Resolve them in the app with rain.tokenMetadata(chainId:address:), which returns nil rather than guessing when the decimals can’t be established.4
Fund the contract from the wallet
Backend Hand the app the contract’s Users can also fund the contract from anywhere else (an exchange withdrawal straight to the deposit address, for example); the wallet is the convenient path, not the only one.
depositAddress (or proxyAddress when no deposit address is returned) and the accepted token addresses.App Funding is an ordinary token send from the wallet to that address, so it inherits everything from Sending funds, including gas sponsorship.5
Watch spending power update
Backend Rain detects the deposit and sends a
transaction.created webhook of type collateral. Spending power updates within minutes; read it with GET /v1/issuing/users/{userId}/balances and show it in the app next to the wallet balance. Neither the wallet balance nor the on-chain contract balance is the spending limit; the balances endpoint is.6
Issue the card and spend
Backend Create the card with
POST /v1/issuing/users/{userId}/cards. From here the wallet isn’t involved in a purchase: Rain authorizes each transaction against the user’s spending power, settles with the network by liquidating collateral from the contract, and keeps the ledger. You consume transaction.created, transaction.updated, and transaction.completed webhooks to show card activity; there’s no approval webhook to build. See Transaction lifecycle and Managing collateral.7
Withdraw remaining collateral
Backend + App The user takes collateral back out by signing a withdrawal with the wallet, authorized by a signature your backend fetches from Rain. Details below.
Withdrawals
Users can withdraw available collateral from their collateral contract to any recipient address. Each withdrawal requires two authorizations: Rain approves the amount available for withdrawal through an admin signature, and the contract’s owner wallet signs the transaction. Your backend retrieves Rain’s admin signature, while your app uses the wallet SDK to sign and submit the withdrawal.1
Fetch the admin signature
Backend Request a signature for the exact withdrawal: chain, token, amount in the token’s base units, the admin (the user’s wallet address), and the recipient.A
Response
pending status with retryAfter means Rain is still computing it; wait and retry. Treat anything other than ready with non-empty signature.data as not ready. Return the signature and the contract’s proxyAddress and controllerAddress to the app. Full reference: Get withdrawal signature for a user.2
Execute the withdrawal
App Assemble the addresses and the signature and call
withdrawCollateral. The SDK checks that the wallet is an admin of the contract before signing (RAIN_407 otherwise), signs, and broadcasts. On EVM chains it returns the transaction hash; on Solana, the transaction signature.amount and decimals must reproduce the exact base-unit amount the signature was issued for. Pass the token’s real decimals; on Solana they aren’t checked against the mint.Quoting the fee and preparing without broadcasting
estimateWithdrawalFee quotes the withdrawal’s network cost in the chain’s native currency (EVM only). Because a withdrawal is an EIP-712-signed call, estimating from scratch asks the wallet to sign; to quote without a second signature, prepare once and estimate on the result:
prepareWithdrawal also serves apps that broadcast themselves: prepared.evmParameters holds the signed transaction parameters, and prepared.solanaTransfer the unsigned Solana transfer, without anything being sent. Preparation works on every chain, including the chains the Rain wallet can’t broadcast on, so it’s the path for a program funding on Avalanche while sends there are pending. With gas sponsorship on, the fee estimate is informational; the user doesn’t pay it.
Withdrawal errors
A signature is bound to one (token, amount, recipient) and is consumed by a successful broadcast. Cache it with those inputs so a retry after a transient failure reuses it; a different amount needs a new one.
Changing the owner wallet
The contract’s owner is fixed at deployment from the address on the application. Changing it today is a two-step operation your backend runs against the Rain API, described in Update a user’s wallet address: add the new wallet as an admin on every EVM collateral contract the user has, thenPATCH /v1/issuing/users/{userId} with the new walletAddress. Rain verifies the new wallet is an admin on all of the user’s EVM contracts and returns 423 Locked when it isn’t.
This matters for the Rain wallet in one scenario: a user who signs up again with a different contact gets a new account and therefore a new wallet, and withdrawals from their existing contract fail with RAIN_407. Avoid it by steering returning users to log in rather than sign up (see Authentication options), and handle it, when it happens, by changing the owner to the new wallet.
Coming at GA: SDK calls to set and change the collateral contract’s owner wallet from the app, so this no longer requires a manual admin step.
Corporate programs
The flow is the same with the company in place of the user. The initial user’s wallet goes on the corporate application and becomes the owner of the company’s contract; additional contracts on other chains can be created withPOST /v1/issuing/companies/{companyId}/contracts, which takes an explicit ownerAddress. Cards for the company’s members all spend from the company contract, and the owner wallet funds and withdraws it exactly as above, using the company variants of the endpoints (contracts, withdrawal signature).
Real-time funding from the wallet
Where your tenant has Real-time funding enabled, pre-funding the contract becomes optional: the user approves Rain’s operator once as a spender of the supported asset in their wallet, and at authorization time Rain pulls the purchase amount from the wallet into the contract before approving. It is available to Rain-managed programs only, on the assets and chains listed in the Real-time funding guide. A decline for insufficient spending power results when the wallet lacks the asset, the allowance is too low, or the pull fails within the authorization window. Real-time funding is in beta; the wallet-side approval steps for the SDK are documented as it goes live. Follow the Real-time funding guide for the current prerequisites and operator addresses.What’s next
Flow of funds
Rain-managed vs partner-managed, and what changes for the wallet.
Transaction webhooks and history
The events your backend receives along this flow.
Testing
Run the whole flow against the sandbox.