Skip to main content
A virtual bank account (VBA) gives an account its own bank coordinates to receive fiat. Incoming credits are automatically converted to a stablecoin and credited to the account’s wallet.

Prerequisites

The account must be verified and have a linked account-holder party.

Lanes

The rail is resolved from the inCurrency you request and your tenant’s enabled pay-in configuration — you don’t pick a provider.

Create a virtual bank account

Provide a display name, the fiat inCurrency, the targetCryptocurrency to convert to, and a unique idempotencyKey:
Response

The fields that matter

Always surface the referenceCode to the end user and tell them to include it in their transfer. It’s how an incoming credit is routed to the right account.

Summary fields vs. depositRails

The top-level iban/bic/accountNumber/routingNumber fields always describe the primary rail. depositRails lists every rail the account is reachable over. A USD account typically exposes four rails sharing the same account and routing number — except SWIFT, which carries a BIC instead of a routing number: A EUR account exposes a single SEPA rail.
Build your payment-instruction UI from depositRails rather than the summary fields. If you only render iban/accountNumber, a customer sending by wire or SWIFT will be missing the bank address their bank asks for.

PENDING accounts

On the EUR lane, an account can come back status: PENDING with bankAccountType omitted — the provider hasn’t returned the deposit rails yet. Don’t show payment instructions until it reaches ACTIVE and depositRails is populated. Register a webhook to hear about the transition instead of polling.

Proving wallet ownership

On some setups, converted funds settle straight to the customer’s own self-custody wallet. Where that applies, the customer must prove they control that wallet first — Venly can’t sign for a wallet it doesn’t hold the keys for. You don’t need to know up front whether this applies to you. Call prepare: if a proof is required you get the exact message to sign, and if it isn’t you get 400 ownership-proof-not-applicable and can create the account directly.
1

Ask for the message

POST /accounts/{accountId}/virtual-bank-accounts/prepare with the destination walletAddress and blockchain.Nothing is persisted — no preparation id, no expiry. Two calls for the same account and wallet return an equivalent message, so this is safe to repeat.
2

Have the customer sign it verbatim

The customer signs message exactly as returned, blind. It embeds an opaque provider token, so don’t reformat, re-encode, pretty-print, or reconstruct it — the signature is checked against those exact bytes.
3

Submit it with the create call

Include the ownershipProof block — walletAddress, blockchain, message, signature — when creating the virtual bank account.
Where a proof isn’t required the ownershipProof field is ignored, so you can send it unconditionally if that is simpler than branching. Only an externally-owned account can sign: the scheme is EIP-191, and ERC-1271 contract signatures are not supported. A smart-contract wallet cannot complete this step.

Verification gates

Provisioning onboards the account holder for verification, so their verification state can block you.
A verified party is not automatically ready. The account holder must also have accepted our partners’ terms themselves — see Partner-terms consent. Until that acceptance is recorded, provisioning is blocked, and the fix is to present the party’s consent link to your end customer rather than to retry.
These states can block you:

Reading them back

Next steps

Wallets & balances

Where converted funds land.

Pay-outs

The other direction: crypto out, fiat to a bank beneficiary.

Supported chains & assets

Which fiat currencies and stablecoins are supported.

Webhooks

Hear about deposits and rail population without polling.