Skip to main content
POST
Issue Bank Account
Issues an NGN or USD deposit account for an approved account. The banking provider is selected automatically based on the currency and whether the account is a business or an individual. The details each provider needs are prefilled from the account’s application. Check Get Issuance Requirements first to see the prefilled payload and anything missing, then pass the missing pieces in accountData.

NGN accounts

NGN accounts are issued immediately.
If the provider still needs details that are neither on the application nor in accountData, the call returns 400 with code MISSING_ACCOUNT_DETAILS listing them (see Errors).

USD accounts

Every USD account we open is a real bank account — the first one and every one after it. Each has its own account number, in the client’s name, at the same bank. There is no “physical” tier and no “virtual” tier: accounts opened later are not virtual accounts layered over the first.You will see the term anyway, because our storage for deposit accounts is called virtual accounts — which is why the webhook announcing even a client’s first USD account is account.virtual_account.created. That is an internal name, not a product distinction.The only real distinction is primary vs additional, and it is visible on every account as the reference field: null on the primary, set on the ones you named. See Multiple USD deposit accounts below.
USD accounts require review. The first call records the request and returns 202 Accepted; the deposit account is set up once the request is approved:
requestId identifies this request — quote it when asking us about a request that is taking longer than you expect. Call the endpoint again once the account is approved — the response then includes the deposit account with accountNumber, routingNumber and swiftCode. While review is in progress, repeat calls keep returning 202 with the same requestId, so retrying is safe and never creates a second request. Two other 202 bodies can come back while you wait. If the review asks you to correct something, data.status is changes_requested and data.message carries the note; re-submit with corrected accountData. Once the request is approved on our side but the banking partner is still finishing its own checks, data.status is pending_provider_review (with the provider state and no requestId); keep retrying until the account is returned. If the request was declined, the call returns 409 with code REQUEST_DECLINED (see Errors).
Rather than polling, subscribe to account.virtual_account.created — it fires as soon as the deposit account exists, with the account details in the payload.

Individual USD accounts

Individual accounts have no representatives. When the account was onboarded with its identity details via Update Individual Details (idDocument, address.line2, and a tax number from taxId / nin / bvn) — plus the passport/ID from the completed Sumsub KYC — no extra payload is needed:
You only need accountData.onboardingDetails to override a field that wasn’t set on the account, e.g.:

Multiple USD deposit accounts

A client can hold more than one USD deposit account, each with its own account number. Pass a reference — your own stable id for whatever you need to reconcile separately, such as a storefront, a branch, a marketplace or a channel:
Only the account number differs — bank name, routing number and account holder are shared, because all of these accounts belong to one client at the same bank. Each is still a real account with its own number, not a label over the primary. That account number is what separates the money: funds sent to it are credited against that reference, so you can tell which source a deposit came from without reconciling by amount or sender name. reference and label are echoed back on List Bank Accounts and Get Funding Instructions, so you can hand the right details to the right source without keeping your own mapping. The client’s primary account is the one issued without a reference, and it reports reference: null. That field is the reliable way to tell the two apart, and it is returned on List Bank Accounts and Get Funding Instructions as well as at creation — so you can classify an account at any time rather than having to remember the order you created things in. A client can only ever hold one account with reference: null: a second call without a reference returns the existing account rather than opening another.
The reference is the idempotency key. The same reference always returns the same account with status: already_exists, so a retry, a duplicated job or a replayed request can never mint a second account for one source. There is no cap on how many references a client can have.
A repeat call (with or without a reference) returns the existing account with 200 instead of 201:
Requesting an additional account requires the client to already hold its primary account — that is what proves the provider approved the entity. Issue one without a reference first, or the call is rejected.Additional accounts are USD only. A reference with currency: "NGN" returns 400; for per-customer NGN accounts use the customer virtual account endpoint instead. Not every USD provider can issue more than one account per client — where it can’t, the call returns 400 explaining so.

Key Behaviours

Entries in accountData.representatives are merged into the prefilled representative with the same relatedPersonId, so you only send the fields you’re adding — names, addresses and ownership come from the application. Individual accounts use accountData.onboardingDetails instead (see above).
The account’s application must be approved before bank accounts can be issued. If provider-required details are missing, the response lists them under errors (USD) or missingFields (NGN).
Re-issuing. A USD call without a reference returns the client’s existing account with status: already_exists (200) rather than creating another — safe to retry. A USD call with a reference behaves the same way per reference. NGN is one account per provider and returns 409 Conflict once one exists.

Errors

Error bodies carry status and message; the ones below also carry a code. 400 with code MISSING_ACCOUNT_DETAILS when an NGN provider still needs fields you have not supplied:
400 with code APPLICATION_NOT_APPROVED when the account’s application is not yet approved:
409 with code REQUEST_DECLINED when a USD request was declined during review. The message includes the decision note when one was left:
USD provider-side validation failures return 400 with an errors array; a duplicate NGN issuance returns 409 with a plain message; malformed request bodies return 400 with "message": "Validation failed" and an errors array.

Authorizations

X-API-Key
string
header
required

Your Rolla API key

Path Parameters

accountId
string<uuid>
required

Identifier of an account owned by the same user as your API key's business

Example:

"eec3cbed-79d8-4370-87a0-b6be9e287337"

Body

application/json
currency
enum<string>
required
Available options:
NGN,
USD
Example:

"NGN"

accountData
object

Optional overrides merged over the details prefilled from the account's application. The shape depends on the provider: call GET /accounts/{accountId}/bank-accounts/requirements to see the prefilled payload and what is missing. For USD business accounts, entries in representatives merge into the prefilled person with the same relatedPersonId; USD individual accounts use onboardingDetails only.

Example:
reference
string

Your own stable id for whatever you need to reconcile separately (a storefront, a branch, a marketplace, a channel). Supplying it issues an additional USD deposit account under the same client, with its own account number, so incoming funds are attributable to that one reference. Omit it for the client's primary account.

Idempotent: the same reference always returns the same account, so a retry cannot create a duplicate. USD only: sending it with currency: "NGN" returns 400. The client must already hold its primary USD account.

Required string length: 1 - 100
Example:

"store-amazon-uk"

label
string

Human-readable name stored alongside the account and echoed back on reads, e.g. "Amazon UK". Only meaningful together with reference.

Required string length: 1 - 120
Example:

"Amazon UK"

Response

The account already exists and is returned as-is (USD, with or without a reference)

status
integer
required
Example:

200

message
string
required
Example:

"Client already onboarded"

success
boolean
required
Example:

true

data
object
required