Skip to main content

Virtual accounts

Virtual accounts give a customer a bank account number that routes inbound transfers into your Payscribe collection flow.

Engineering flowBuild, verify, then reconcile
Test this flow in sandbox
  1. 01Create customerPersist the customer ID before creating an account.
  2. 02Create accountChoose static for repeat payments or dynamic for one invoice.
  3. 03Receive paymentThe customer transfers to the issued account.
  4. 04Verify and reconcileVerify the signed event and match transaction data once.

Use a dashboard-issued sandbox API key on your server. Do not enter credentials into this documentation site.

Choose an account type

TypeBest forBehaviour
StaticRepeat collections for one customerA persistent account number.
DynamicA single invoice or time-bound paymentFixed amount and expiry.

Technical flow

Create customer → create virtual account → customer transfers → verified webhook → reconcile transaction → update your business state

Do not mark an order paid only from the account-creation response. Verify the signed payment webhook and reconcile its transaction/reference first.

Supported providers

ProviderStaticDynamicNotes
9PSBYesYesSupports both account types.
PalmPayYesNoStatic accounts require BVN details.

Create an account

Create a customer first, then create the account using POST /collections/virtual-accounts/create with your server-side API key.

Prefer an SDK in Node.js or PHP?

Use the Node.js SDK guide for static or dynamic accounts, or the PHP SDK guide for customer creation and virtual accounts. Both guides keep the complete SDK workflow inside these docs.

curl -X POST https://sandbox.payscribe.ng/api/v1/collections/virtual-accounts/create \
-H "Authorization: Bearer $PAYSCRIBE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"customer_id":"cus_abc123","bank":"9psb"}'

For a dynamic account you would include account_type: "dynamic" with an order amount and expiry, but the public create endpoint currently only issues static 9PSB/PalmPay accounts — see the Collections API reference for the current status of dynamic accounts. Until then, use static accounts for all API-driven collections.

Confirm payment safely

When the transfer arrives, verify accounts.payment.status using the raw-body webhook signature, store the event ID once, and reconcile the resulting transaction. See Webhooks and Sandbox testing.

Build the full flow

Use the Receive a payment via virtual account recipe for customer creation, sandbox simulation, webhook handling, and reconciliation. See the Collections API reference for all parameters and account lifecycle operations.

Was this page helpful?

Report a docs issue →