Skip to main content
POST
Create Virtual Account
A virtual account is a named bank account in a single currency, opened inside an approved virtual account group. It carries its own bank details for receiving deposits and its own balance, which can fund a payout or be a leg of a transfer. The group must be through onboarding first: status enabled and onboarding_status approved. Create Virtual Account Group covers who can open a group and what the account needs to get there: an identity profile, plus an associated person marked as a signer on a business account. Provisioning is asynchronous. The call returns as soon as Hop has recorded the virtual account and asked the provider to open the underlying bank account: the bank details arrive later. Requires an API key with write access on the virtual_accounts scope. A newly created virtual account comes back with status: "pending", provisioned_at: null, and every bank detail field set to null: beneficiary_name, bank_name, account_number, account_number_last4, iban, swift_bic, routing_number, routing_number_type, bank_address and beneficiary_address. It cannot be paid into yet, so do not publish this response as funding instructions. Poll Get Virtual Account until status is active; at that point provisioned_at is set and the bank details are filled in. Activation depends on the provider opening the account and is not instant. A virtual account can also stay pending indefinitely if the provider never returns payable bank details; contact Hop if one does not activate. Once active it also appears in List Deposit Instructions, which is the surface to hand to a payer.

Path Parameters

string
required
The account’s external ID (starts with acct_)
string
required
The virtual account group’s external ID (starts with vag_); see Create Virtual Account Group. A group that does not exist on this account returns 404.

Headers

string
required
Key for this virtual account, scoped to the account. Canonical lowercase 8-4-4-4-12 UUID, for example 9f8c3a21-4d5e-4b67-8a90-1c2d3e4f5a6b. See Idempotency.
Replaying a key that already created a virtual account returns that virtual account with 200, unchanged, and does not open a second one at the provider or re-charge any creation fee. Only group_id and currency are compared on a replay. Reusing a key with a different currency, or against a different group, returns 409 IDEMPOTENCY_CONFLICT with details.virtual_account_id naming the virtual account the key already created. Reusing it with a different label is not an error: the original virtual account is returned and the new label is ignored, so a label is never changed this way. Use a fresh key to open a differently labelled virtual account. While a request with the same key is still in flight, a second one fails fast with 409 IDEMPOTENCY_REQUEST_IN_PROGRESS. Retry after a short backoff.

Request Body

string
required
Currency of the virtual account, for example EUR. The provider backing the group must support opening an account in it; a currency the group’s provider has no account profile for is rejected with 502.
string
Optional label for your own reference (max 255 characters). Not shown to payers, not unique, and cannot be changed through this API.
A group may hold several virtual accounts in the same currency. Each call with a new Idempotency-Key opens another one. There is no per-currency limit on this endpoint, so guard against accidental duplicates by reusing your key on retries.

Response

Returns 201 with the new virtual account, or 200 with the existing one when the Idempotency-Key was already used.
string
Virtual account identifier (starts with va_)
string
Always returns "virtual_account"
string
Account ID (starts with acct_). The response does not repeat group_id.
string
Currency code of the virtual account
string
Virtual account status: pending (created, bank details not yet issued: not payable), active (payable and usable as a payout funding source or transfer leg), frozen (balance movements blocked by Hop) or disabled (closed by Hop; terminal). A create always returns pending.
string
Label, or null
object
Balance buckets, each a decimal string formatted for the currency. A new virtual account is all zeroes.
string
Account holder a payer should address the deposit to, or null while pending
string
Bank holding the account, or null while pending
string
Full account number, or null while pending and on accounts identified by IBAN
string
Masked account number, or the masked IBAN when the account has no account number. null while pending. Despite the name, this field can carry IBAN digits.
string
Full IBAN, or null while pending and on accounts identified by account number
string
SWIFT/BIC code, or null
string
Routing number or sort code, or null
string
What routing_number holds, for example ROUTING_NUMBER or SORT_CODE; null when there is no routing number
object
Bank address for wire instructions (address_line, city, region, postal_code, country), or null
object
Account holder address for wire instructions, same shape as bank_address, or null
string
ISO 8601 timestamp when the bank details became available, or null while pending
string
ISO 8601 timestamp when created
string
ISO 8601 timestamp when last updated
string
ID of the API key that created the virtual account (starts with ak_)
string
Actor that last updated the virtual account, or null
Once the virtual account is active, its id can be passed as a payout funding_source, see Create Payout, or as a leg of a same-currency transfer.

Errors

Request Example

Response Example