ACTIVE, and what to expect on the first deposit.
Before you start
- An approved customer. Virtual accounts belong to a customer, so the customer has to exist and have reached
APPROVED. See Onboarding individual customers or Onboarding business customers. - Confirm your customer has the capability. Call Get Customer Capabilities and check the
on_rampentry for the currency and rail you intend to use. A customer can be approved without being eligible for every corridor. - A destination wallet that you have custody of. The converted funds settle to an address you nominate, and Fin.com does not custody them for you. Have the address ready on the network you intend to use, and the means to sign transactions out of it.
Choosing the source and destination
A virtual account has two sides. The source is the fiat side, meaning the bank details your customer hands out. The destination is the crypto side, meaning where the converted funds settle.This guide covers issuing USD virtual accounts only.
destination.wallet format follows the network: Ethereum, Base and Polygon take a hexadecimal address, Solana takes base58. Check it carefully. Funds settled to a wrong address cannot be recovered.
Creating the account
Call Create Virtual Account with the customer in the path.developer_fee is your own markup on each deposit. Set a fixed amount, a percentage, or both, and both are applied.
What comes back
A200 with the account in data. The field to read first is status, and on a fresh account it is PROCESSING:
One account per currency and rail
A customer can hold only one virtual account per source currency and rail. Requesting one that already exists returns422, with the colliding source in errors and the virtual_account_id of the existing account:
422 here as a lookup result, not a failure.
Waiting for the account to go live
New accounts are reviewed before the banking partner issues them. The account moves through these states:Which webhooks to subscribe to
Subscribe to both:virtual_account.status.v2 is the one that matters operationally. It carries the full account object, so when status becomes ACTIVE the same payload contains the populated deposit_instructions. You do not need a follow-up call to fetch them.
event_reference_id carries the virtual account ID, so you can match the event to your own record without parsing data.How long it takes
Issuance is not instant and is not a fixed interval. It depends on the banking partner and on the customer’s risk profile, and aREQUEST_FOR_INFORMATION pauses it until you respond.
Build for this rather than polling tightly:
- Drive off the webhook. Treat
ACTIVEas an event you react to, not a state you wait on inside a request. - If you must poll, poll slowly. Get Virtual Account Details returns the same object. Minutes between calls, not seconds.
- Handle
REQUEST_FOR_INFORMATION. Therfiobject is populated only in this state and tells you what is outstanding. Nothing progresses until it is answered. - Do not show a customer any bank details until you have seen
deposit_instructionspopulated.
Next: receiving the first deposit
The account can now receive money. See Receiving the first deposit for what to hand to the payer, what lands at your destination wallet, and how to reconcile it.Managing accounts
- List Virtual Accounts returns every account for a customer, paginated.
- Get Virtual Account Details returns one account, including its deposit instructions.
- Fetch Virtual Account Transactions returns what has been received.
Need help getting set up?Contact us in your dedicated Slack channel to confirm which banking partners and corridors are enabled for you.
