Skip to main content
Once a virtual account reaches ACTIVE, it can receive money. This guide covers what to hand out, what lands at your destination wallet, and how to tie the two together. If the account is not ACTIVE yet, see Creating a virtual account first. deposit_instructions stays null until the banking partner issues the account.

Sharing the deposit instructions

Read deposit_instructions from the account and pass every populated field to whoever is paying in. You get the same object from the virtual_account.status.v2 webhook and from Get Virtual Account Details, which returns the whole account:
Which fields are populated depends on the rail. Fields that do not apply come back empty, either as null or as an empty string, so check for both rather than assuming a fixed set. Pass on the beneficiary name exactly as given: a payment made out to a different name may be returned.
Send the payer only the rails listed in payment_rails. A payment sent over a rail the account does not accept may be delayed or returned.

What happens when money arrives

The deposit is converted and settled to the destination address you set when you created the account. What lands is the deposited amount, less conversion and any developer_fee you configured, so the settled amount will not equal the amount sent. Both fee components apply if you set both: Settlement is not instant, and the two legs move on different clocks. The fiat leg depends on the rail the payer used, so an ACH deposit and a Fedwire deposit do not arrive on the same timeline. The crypto leg then depends on the destination network.

Monitoring the deposit

Subscribe to transaction.status to follow a deposit from arrival to settlement. This is the event that tells you money has landed, not the virtual account events: those only describe the account itself. A virtual account deposit arrives with transaction_type set to ONRAMP.
The payload carries what you need to account for the deposit without a follow-up call:
hash is the link between the deposit and what appears in your wallet. Store it against your record of the deposit, and reconciliation against the chain becomes a lookup rather than a guess.
Expect more than one event per deposit. The same transaction ID arrives with each status change, so key on data.id and treat a repeat as an update rather than a new deposit.

Reconciling the deposit

Webhooks tell you about a deposit as it happens. To check the record afterwards, or to catch up on anything you missed, use Fetch Virtual Account Transactions, which lists what has arrived on one account and is paginated.
Reconcile against these records rather than against your wallet balance. A balance tells you that funds arrived, not which deposit they came from, and a wallet receiving settlements from several virtual accounts gives you no way to attribute them.
Keep your own mapping of virtual account ID to customer. The settlement arriving on chain does not carry the customer with it.

Troubleshooting

Nothing has arrived. Confirm the payer used a rail in payment_rails, and that they used every field exactly as given. An incomplete or mistyped beneficiary name is the most common cause of a returned payment. The settled amount looks wrong. Check developer_fee_fixed and developer_fee_percent on the account. Both are deducted, alongside conversion. The deposit shows on the account but not at the wallet. The fiat leg has completed and the crypto leg has not. Give the destination network time to confirm before treating it as missing.
Something not adding up?Contact us in your dedicated Slack channel with the virtual account ID and we will trace the deposit.