Virtual Accounts
Virtual Accounts give each customer a dedicated bank account number. When the customer makes a bank transfer to that number, the payment is automatically matched to them — no manual reconciliation required.
Provider support
Virtual Accounts are supported by Paystack (Wema Bank and Titan Bank), Monnify, and Squad. Paystack is the primary implementation. You must have at least one of these providers configured under Provider Keys before creating virtual accounts.
Endpoints
/v1/virtual-accounts/v1/virtual-accounts/v1/virtual-accounts/:idCreate a Virtual Account
Creates a dedicated bank account number for a customer. Accounts are scoped per email and provider combination.
/v1/virtual-accountsCreates a virtual account for a customer. Returns the existing account if one already exists for this email and provider.
Request body
| Parameter | Type | Required | Description |
|---|---|---|---|
customer_email | string | Required | Customer's email address. A dedicated account is created per email+provider combination — calling this endpoint again with the same email returns the existing account. |
customer_name | string | Required | Customer's full name. |
customer_phone | string | Optional | Customer's phone number. |
preferred_bank | string | Optional | Bank to create the virtual account with. Options: wema-bank, titan-paystack. Defaults to wema-bank. |
provider_id | string | Optional | Force a specific provider. Omit to auto-select. |
metadata | object | Optional | Up to 20 key-value string pairs. |
curl -X POST https://api.popfab.io/v1/virtual-accounts \
-H "Authorization: Bearer sk_test_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"customer_email": "ada@example.com",
"customer_name": "Ada Okafor",
"customer_phone": "+2348012345678",
"preferred_bank": "wema-bank"
}'{
"id": "ppfb_va_a1b2c3d4e5f6",
"customer_email": "ada@example.com",
"customer_name": "Ada Okafor",
"account_number": "9876543210",
"account_name": "POPFAB/Ada Okafor",
"bank_name": "Wema Bank",
"currency": "NGN",
"provider": "paystack",
"active": true,
"metadata": {},
"created_at": "2025-03-19T12:00:00.000Z",
"updated_at": "2025-03-19T12:00:00.000Z"
}customer_email returns the existing active account without creating a duplicate.List Virtual Accounts
Returns a cursor-paginated list of all virtual accounts for your merchant, newest first.
/v1/virtual-accountsReturns a paginated list of virtual accounts.
Query parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
limit | integer | Optional | Results per page. Default 20, max 100. |
cursor | string | Optional | Pagination cursor from a previous response next_cursor field. |
curl "https://api.popfab.io/v1/virtual-accounts?limit=50" \
-H "Authorization: Bearer sk_test_YOUR_API_KEY"Get a Virtual Account
/v1/virtual-accounts/:idRetrieves a single virtual account by its POPFAB ID.
curl https://api.popfab.io/v1/virtual-accounts/ppfb_va_a1b2c3d4e5f6 \
-H "Authorization: Bearer sk_test_YOUR_API_KEY"How Payments Are Matched
When a customer makes a bank transfer to their dedicated virtual account number, Paystack detects the inbound credit and sends a charge.success webhook to POPFAB's inbound webhook URL. POPFAB receives this event and automatically creates a payment record linked to the matching customer. Merchants should listen for payment.success webhooks from POPFAB to be notified when a virtual-account payment is received.
Provider Support
| Provider | Virtual Accounts | Banks available |
|---|---|---|
| Paystack | ✓ | Wema Bank, Titan Bank |
| Monnify | ✓ | Multiple |
| Squad | ✓ | GTBank |
| Flutterwave | — | — |
| Interswitch | — | — |
| Payaza | — | — |