Skip to content

Paystack Integration

import { Aside, Tabs, TabItem, Steps } from ‘@astrojs/starlight/components’;

Paystack is one of Africa’s leading payment processors, supporting businesses in Nigeria, Ghana, South Africa, and Kenya. This guide covers how to integrate Paystack payments using Voltax.

Before you begin, you’ll need:

  • A Paystack account (sign up at paystack.com)
  • Your Paystack secret key (found in Settings → API Keys & Webhooks)

Initialize Voltax with your Paystack credentials:

import Voltax from '@noelzappy/voltax';
const voltax = new Voltax({
paystack: {
secretKey: process.env.PAYSTACK_SECRET_KEY!,
},
});
import { Currency } from '@noelzappy/voltax';
const payment = await voltax.paystack.initializePayment({
amount: 5000, // 5,000 NGN (Voltax handles kobo conversion)
email: 'customer@example.com',
currency: Currency.NGN,
reference: `txn-${Date.now()}`,
callbackUrl: 'https://yoursite.com/payment/callback',
});
// Redirect customer to complete payment
console.log(payment.authorizationUrl);
// "https://checkout.paystack.com/xxxxxxxxxx"

Attach custom data to track orders and customers:

const payment = await voltax.paystack.initializePayment({
amount: 15000,
email: 'customer@example.com',
currency: Currency.NGN,
description: 'Order #12345',
metadata: {
orderId: 'ORD-12345',
customerId: 'CUST-67890',
items: ['Product A', 'Product B'],
cart_id: 398,
},
});

Paystack supports several advanced options through the options.paystack field:

Limit which payment methods customers can use:

import { PaystackChannel } from '@noelzappy/voltax';
const payment = await voltax.paystack.initializePayment({
amount: 5000,
email: 'customer@example.com',
currency: Currency.NGN,
options: {
paystack: {
channels: [
PaystackChannel.CARD,
PaystackChannel.BANK_TRANSFER,
PaystackChannel.USSD,
],
},
},
});

Available Channels:

ChannelValueDescription
CARD"card"Debit/Credit cards
BANK"bank"Pay with bank account
BANK_TRANSFER"bank_transfer"Bank transfer
USSD"ussd"USSD payment
QR"qr"QR code payment
MOBILE_MONEY"mobile_money"Mobile money (Ghana)
EFT"eft"Electronic Funds Transfer (South Africa)
APPLE_PAY"apple_pay"Apple Pay
PAYATTITUDE"payattitude"PayAttitude

Split payments between accounts using subaccounts or split codes:

const payment = await voltax.paystack.initializePayment({
amount: 10000,
email: 'customer@example.com',
currency: Currency.NGN,
options: {
paystack: {
// Use a subaccount
subaccount: 'ACCT_xxxxxxxxxx',
// Or use a split code for multi-party splits
splitCode: 'SPL_xxxxxxxxxx',
// Who bears the transaction charge
bearer: 'subaccount', // or 'account'
// Additional charge to add (in kobo)
transactionCharge: 10000, // ₦100 extra
},
},
});

For recurring payments with Paystack Plans:

const payment = await voltax.paystack.initializePayment({
amount: 5000,
email: 'customer@example.com',
currency: Currency.NGN,
options: {
paystack: {
plan: 'PLN_xxxxxxxxxx',
// Limit number of subscription invoices
invoiceLimit: 12, // 12 months
},
},
});
interface PaystackOptions {
// Limit payment channels
channels?: PaystackChannel[];
// Subaccount for split payments
subaccount?: string;
// Split code for multi-party splits
splitCode?: string;
// Who bears Paystack fees: 'account' (you) or 'subaccount'
bearer?: 'account' | 'subaccount';
// Flat fee to charge on transaction (in kobo)
transactionCharge?: number;
// Subscription plan code
plan?: string;
// Max number of subscription charges
invoiceLimit?: number;
}

After the customer completes payment, verify the transaction:

import { PaymentStatus } from '@noelzappy/voltax';
const result = await voltax.paystack.verifyTransaction('txn-123456');
console.log(result);
// {
// status: 'SUCCESS',
// reference: 'txn-123456',
// externalReference: '1234567890',
// raw: { ... }
// }
if (result.status === PaymentStatus.SUCCESS) {
// Payment successful - fulfill order
const amount = result.raw.data.amount / 100; // Convert from kobo
console.log(`Received ₦${amount}`);
}

Voltax maps Paystack statuses to standardized values:

Paystack StatusVoltax Status
successSUCCESS
failedFAILED
reversedFAILED
abandonedFAILED
OtherPENDING

For a quick status check:

const status = await voltax.paystack.getPaymentStatus('txn-123456');
if (status === PaymentStatus.SUCCESS) {
console.log('Payment successful!');
}

Here’s a full Express.js integration example:

import express from 'express';
import Voltax, { Currency, PaymentStatus, PaystackChannel } from '@noelzappy/voltax';
const app = express();
app.use(express.json());
const voltax = new Voltax({
paystack: { secretKey: process.env.PAYSTACK_SECRET_KEY! },
});
// Initialize payment
app.post('/api/payments/initialize', async (req, res) => {
try {
const { amount, email, orderId } = req.body;
const payment = await voltax.paystack.initializePayment({
amount,
email,
currency: Currency.NGN,
reference: `order-${orderId}-${Date.now()}`,
callbackUrl: `${process.env.BASE_URL}/payment/callback`,
description: `Payment for Order #${orderId}`,
metadata: { orderId },
options: {
paystack: {
channels: [
PaystackChannel.CARD,
PaystackChannel.BANK_TRANSFER,
],
},
},
});
res.json({
success: true,
checkoutUrl: payment.authorizationUrl,
reference: payment.reference,
});
} catch (error) {
res.status(400).json({ success: false, error: error.message });
}
});
// Payment callback
app.get('/payment/callback', async (req, res) => {
const { reference } = req.query;
try {
const result = await voltax.paystack.verifyTransaction(reference as string);
if (result.status === PaymentStatus.SUCCESS) {
// Mark order as paid in your database
res.redirect('/order/success');
} else {
res.redirect('/order/failed');
}
} catch (error) {
res.redirect('/order/error');
}
});
app.listen(3000);
CurrencyCodeCountry
Nigerian NairaNGNNigeria
Ghanaian CediGHSGhana
South African RandZARSouth Africa
Kenyan ShillingKESKenya
US DollarUSDInternational