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 a Paystack provider with your credentials:

import Voltax from '@noelzappy/voltax';
const paystack = Voltax('paystack', {
secretKey: process.env.PAYSTACK_SECRET_KEY!,
});
import { Currency } from '@noelzappy/voltax';
const payment = await paystack.initiatePayment({
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 paystack.initiatePayment({
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 as top-level fields in the payment DTO:

Limit which payment methods customers can use:

import { PaystackChannel } from '@noelzappy/voltax';
const payment = await paystack.initiatePayment({
amount: 5000,
email: 'customer@example.com',
currency: Currency.NGN,
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 paystack.initiatePayment({
amount: 10000,
email: 'customer@example.com',
currency: Currency.NGN,
// 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 paystack.initiatePayment({
amount: 5000,
email: 'customer@example.com',
currency: Currency.NGN,
plan: 'PLN_xxxxxxxxxx',
// Limit number of subscription invoices
invoiceLimit: 12, // 12 months
});

All Paystack-specific options are available as top-level fields in the payment DTO:

interface PaystackPaymentDTO {
// Base fields
amount: number;
email: string;
currency: Currency;
reference?: string;
callbackUrl?: string;
description?: string;
metadata?: Record<string, any>;
// Paystack-specific options
channels?: PaystackChannel[]; // Limit payment channels
subaccount?: string; // Subaccount for split payments
splitCode?: string; // Split code for multi-party splits
bearer?: 'account' | 'subaccount'; // Who bears Paystack fees
transactionCharge?: number; // Flat fee to charge (in kobo)
plan?: string; // Subscription plan code
invoiceLimit?: number; // Max subscription charges
}

After the customer completes payment, verify the transaction:

import { PaymentStatus } from '@noelzappy/voltax';
const result = await 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 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 paystack = Voltax('paystack', {
secretKey: process.env.PAYSTACK_SECRET_KEY!,
});
// Initiate payment
app.post('/api/payments/initialize', async (req, res) => {
try {
const { amount, email, orderId } = req.body;
const payment = await paystack.initiatePayment({
amount,
email,
currency: Currency.NGN,
reference: `order-${orderId}-${Date.now()}`,
callbackUrl: `${process.env.BASE_URL}/payment/callback`,
description: `Payment for Order #${orderId}`,
metadata: { orderId },
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 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