To assign a DVA at signup: create a Paystack customer when the user registers, immediately call the dedicated_account endpoint with the customer code, store the returned account number in your database, and display it to the user. Handle creation failures with a retry queue so users are not blocked from completing registration if the Paystack API is temporarily unavailable.
app.post('/api/register', async function(req, res) {
var email = req.body.email;
var firstName = req.body.firstName;
var lastName = req.body.lastName;
var phone = req.body.phone;
var password = req.body.password;
// Step 1: Create the user in your database
var user = await db.users.create({
email: email,
first_name: firstName,
last_name: lastName,
phone: phone,
password: hashPassword(password),
dva_status: 'pending',
});
// Step 2: Create Paystack customer
try {
var customerResponse = await fetch('https://api.paystack.co/customer', {
method: 'POST',
headers: {
Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: email,
first_name: firstName,
last_name: lastName,
phone: phone,
}),
});
var customerData = await customerResponse.json();
var customerCode = customerData.data.customer_code;
await db.users.update(user.id, {
paystack_customer_code: customerCode,
});
// Step 3: Create DVA
var dvaResponse = await fetch('https://api.paystack.co/dedicated_account', {
method: 'POST',
headers: {
Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
customer: customerCode,
preferred_bank: 'wema-bank',
}),
});
var dvaData = await dvaResponse.json();
if (dvaData.status) {
await db.users.update(user.id, {
dva_account_number: dvaData.data.account_number,
dva_bank_name: dvaData.data.bank.name,
dva_account_name: dvaData.data.account_name,
dva_status: 'active',
});
} else {
// DVA creation failed - queue for retry
await retryQueue.add('create-dva', { userId: user.id, customerCode: customerCode });
}
} catch (err) {
// Paystack API error - queue for retry
await retryQueue.add('create-dva', { userId: user.id });
}
// Return success regardless - user can start using the app
res.json({ success: true, userId: user.id });
});
The Paystack API call takes time and can fail. If you block the registration on DVA creation, users will see a slow signup or get errors they do not understand. The better pattern: complete registration immediately and create the DVA in the background.
// Background job processor
async function processDvaCreation(job) {
var userId = job.data.userId;
var user = await db.users.findById(userId);
if (user.dva_status === 'active') {
return; // Already created
}
// Ensure Paystack customer exists
var customerCode = user.paystack_customer_code;
if (!customerCode) {
var customerResponse = await fetch('https://api.paystack.co/customer', {
method: 'POST',
headers: {
Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: user.email,
first_name: user.first_name,
last_name: user.last_name,
phone: user.phone,
}),
});
var customerData = await customerResponse.json();
customerCode = customerData.data.customer_code;
await db.users.update(userId, { paystack_customer_code: customerCode });
}
// Create DVA
var dvaResponse = await fetch('https://api.paystack.co/dedicated_account', {
method: 'POST',
headers: {
Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
customer: customerCode,
preferred_bank: 'wema-bank',
}),
});
var dvaData = await dvaResponse.json();
if (dvaData.status) {
await db.users.update(userId, {
dva_account_number: dvaData.data.account_number,
dva_bank_name: dvaData.data.bank.name,
dva_account_name: dvaData.data.account_name,
dva_status: 'active',
});
// Notify the user
await sendEmail(user.email, 'dva_ready', {
accountNumber: dvaData.data.account_number,
bankName: dvaData.data.bank.name,
});
} else {
throw new Error('DVA creation failed: ' + dvaData.message);
// Job framework will retry automatically
}
}
Get weekly developer tips
Join 25,000+ developers. Practical guides, job tips, and new content — straight to your inbox.
No spam. Unsubscribe anytime.
Immediate display: If DVA creation succeeds during registration, show the account number on the welcome screen. "Your personal account number is 0123456789 at Wema Bank. Transfer any amount to deposit into your wallet."
Pending state: If DVA creation is still processing, show a placeholder. "Your account number is being set up. We will notify you when it is ready. You can start exploring the app in the meantime."
Ready notification: When the background job completes, send a push notification, email, or SMS. "Your account number is ready! Transfer to 0123456789 at Wema Bank to make your first deposit."
Error state: If DVA creation fails permanently after retries, show a support contact. "We could not set up your account number. Please contact support." This should be rare.
// API endpoint to check DVA status
app.get('/api/my-dva', async function(req, res) {
var user = await db.users.findById(req.userId);
if (user.dva_status === 'active') {
res.json({
ready: true,
accountNumber: user.dva_account_number,
bankName: user.dva_bank_name,
accountName: user.dva_account_name,
});
} else {
res.json({
ready: false,
message: 'Your account number is being set up. Check back shortly.',
});
}
});
If your Paystack account requires BVN validation before DVA creation, split the signup into two phases:
This means the user can start using the app immediately but cannot deposit until their identity is verified and the DVA is created. This is standard practice for fintech apps that need KYC compliance.
Show the verification status clearly in the app: "Identity verification in progress" during validation, "Verification complete" when done, and the account number once the DVA is created.
If you expect thousands of signups per day, batch DVA creation and manage rate limits:
For the full DVA implementation guide, see dedicated virtual accounts complete implementation. For reconciling deposits, see reconciling DVA deposits.
KES 2,999
The definitive guide to building payment systems with Paystack — from your first transaction to production-grade payment infrastructure across Africa. 9 modules, 47 lessons. Free preview available.
Start Paystack Course