Virtual bank accounts have become one of the most popular ways for African fintechs and ecommerce platforms to collect payments, because they let a customer pay with a normal bank transfer while the business still gets a fully trackable, unique account number behind the scenes. Payscribe's official Node.js/TypeScript SDK makes integrating this feature far simpler than hand-building requests against their REST API. This guide walks through installing the SDK, configuring it, and creating your first virtual account start to finish.
What You Need Before You Start
- Node.js 18+
- A Payscribe secret API key
Installing the SDK
npm install @payscribe/sdk
Setting Up Your Environment
Create a .env file in your project and add:
PAYSCRIBE_SECRET_KEY=ps_sk_test_YOUR_SECRET_KEY PAYSCRIBE_ENVIRONMENT=sandbox PORT=3000
Choose your environment: "sandbox" | "production"
Each one points to a different address on Payscribe's servers:
- sandbox → https://sandbox.payscribe.ng/api/v1/
- production → https://api.payscribe.ng/api/v1/
Note: If environment is omitted, the SDK defaults to sandbox.
Setting Up the Client
import { Payscribe } from "@payscribe/sdk";
const payscribe = new Payscribe({
secretKey: process.env.PAYSCRIBE_SECRET_KEY!,
environment: "sandbox"
});
Note: For internal testing against a custom endpoint, you can override the baseUrl directly:
const payscribe = new Payscribe({
secretKey: process.env.PAYSCRIBE_SECRET_KEY!,
baseUrl: "https://sandbox.payscribe.ng/api/v1/"
});
With the client set up, you're ready to start creating virtual accounts.
Virtual Accounts
Creating a Static (Permanent) Virtual Account
Static accounts are permanent and reusable, ideal for a customer you expect to receive repeat payments from (subscriptions, wallet funding, etc.). They're tied to an existing Payscribe customer record.
const account = await payscribe.virtualAccounts.createStatic({
customerId: "customer-uuid",
banks: ["9psb"],
currency: "NGN"
});
Some partner banks Palmpay, in this case require additional identity verification fields:
const account = await payscribe.virtualAccounts.createStatic({
customerId: "customer-uuid",
banks: ["palmpay"],
currency: "NGN",
identity: {
type: "bvn",
number: "2233990011"
}
});
TypeScript users get a matching input type for compile-time safety:
import type { CreateStaticVirtualAccountInput } from "@payscribe/sdk";
const body: CreateStaticVirtualAccountInput = {
customerId: "customer-uuid",
banks: ["9psb"],
currency: "NGN"
};
Creating a Dynamic Virtual Account
Dynamic accounts are best suited to one-off transactions checkout flows, single orders since they expire after a set window.
const account = await payscribe.virtualAccounts.createDynamic({
reference: "order_123",
amount: 2500,
amountType: "EXACT",
description: "Payment for order_123",
currency: "NGN",
expiresIn: {
duration: 1,
type: "hours"
},
customer: {
name: "Ada Lovelace",
email: "ada@example.com",
phone: "08099228833"
}
});
amountType accepts one of two values: "EXACT" | "ANY"
Note: Pick EXACT when the customer must pay a fixed amount, and ANY when you want to accept whatever amount they send.
import type { CreateDynamicVirtualAccountInput } from "@payscribe/sdk";
const body: CreateDynamicVirtualAccountInput = {
reference: "order_123",
amount: 2500,
amountType: "EXACT",
expiresIn: {
duration: 1,
type: "hours"
},
customer: {
name: "Ada Lovelace",
email: "ada@example.com",
phone: "08099228833"
}
};
Checking, Activating, and Deactivating Accounts
// Get virtual account
const account = await payscribe.virtualAccounts.get("5031240100");
// Deactivate virtual account
const result = await payscribe.virtualAccounts.deactivate("5031240100");
// Activate virtual account
const result = await payscribe.virtualAccounts.activate("5031240100");
Confirming a Payment
Once a customer pays into a virtual account, you can confirm the transaction using the session ID from Payscribe:
const payment = await payscribe.virtualAccounts.confirmPayment({
sessionId: "100004240807072606117680115283",
amount: 5000,
accountNumber: "5300000217"
});
If you're tracking your own transaction ID internally, pass it along too:
const payment = await payscribe.virtualAccounts.confirmPayment({
transId: "transaction-id",
sessionId: "100004240807072606117680115283",
amount: 5000,
accountNumber: "5300000217"
});
Testing a Transfer Without a Real Bank (Sandbox Only)
const simulation = await payscribe.virtualAccounts.simulateTransfer({
reference: "test-ref",
amount: "4500.00",
description: "A test transfer",
currency: "NGN",
account: "4804760006",
name: "Ada Lovelace",
bank: "120001",
senderAccountNumber: "1100000309",
senderName: "Ada Lovelace",
hash: "generated-hash"
});
This is a fast way to check your webhook and confirmation logic without waiting for a bank to actually move money.
SDK Reference
Full method signatures, typed inputs, and additional configuration options are available in the SDK package itself:
https://www.npmjs.com/package/@payscribe/sdk
Need More Details?
For full endpoint references, request/response schemas, and additional configuration options, check out the official API documentation: [https://docs.payscribe.co]
Need a Hand?
Questions, edge cases, or something not working as expected? Our team's got you reach out at support@payscribe.co

