Create a Virtual Bank Account
Issue a dedicated NGN account number for a customer. Three steps: create the customer, verify their BVN, then create the account.
BVN verification must complete with an eligible result (exact name match) before account creation. The raw BVN is encrypted at the KYC boundary and never echoed, logged, or returned.
Full Workflow
Create the Customer
import { Pay100 } from "@100pay-hq/100pay.js";
const client = new Pay100({
publicKey: "your_public_key",
secretKey: "your_secret_key",
});
const customer = await client.customer.create(
{
externalReference: "user-8f2c1a", // your stable user ID, unique per app
firstName: "Ada",
lastName: "Obi",
email: "ada@example.com",
phone: "+2348012345678", // +234 phone required for VBAs
},
{ idempotencyKey: crypto.randomUUID() }
);Verify Their Identity (BVN)
const verification = await client.customer.identityVerification.create(
customer.data.id,
{ method: "bvn", bvn: "12345678901" },
{ idempotencyKey: crypto.randomUUID() }
);
// Processing is asynchronous — poll until terminal
const result = await client.customer.identityVerification.get(
customer.data.id,
verification.data.id
);
// result.data.status → "verified", result.data.eligibility.status → "eligible"Create the Virtual Bank Account
const vba = await client.customer.virtualBankAccount.create(
customer.data.id,
{
identityVerificationId: verification.data.id,
externalReference: "vba-user-8f2c1a",
// Optional overrides (defaults come from your app settings):
// sweepDestination: "platform" | "merchant_settlement" | "merchant_vba" | "none"
// depositFeeBearer: "customer" | "merchant"
},
{ idempotencyKey: crypto.randomUUID() }
);
// Provisioning is asynchronous — 202 means poll the account
const account = await client.customer.virtualBankAccount.get(
customer.data.id,
vba.data.id
);
console.log(account.data.account?.number); // "5013195013"
console.log(account.data.walletId); // the dedicated ledger walletSweep Destination & Fee Bearer
Both are captured immutably when the account is created. Later changes to your app settings only affect new accounts.
| Setting | Options | Default |
|---|---|---|
sweepDestination | platform · merchant_settlement · merchant_vba · none | platform |
depositFeeBearer | customer · merchant | customer |
platformkeeps physical custody aligned with the account that pays withdrawals — the recommended default.merchantfee bearer sponsors deposit fees from your main NGN wallet. If your balance can’t cover a fee, the configured fallback applies (charge_customer, deferred receivable, or held deposit).
Manage the app-level defaults with client.customer.bankingSettings.get() / .update(data, { ifMatch }).
One operational VBA per customer per app. Failed provisioning can be retried with client.customer.virtualBankAccount.retry(...) once automatic attempts are exhausted.
Last updated on