Skip to content

Flutterwave Integration

Flutterwave is a leading payment technology company providing seamless payment solutions across Africa and globally. This guide covers how to integrate Flutterwave payments using Voltax.

Before you begin, you’ll need:

  • A Flutterwave account (sign up at flutterwave.com)
  • Your Flutterwave secret key (found in Settings → API)

Initialize a Flutterwave provider with your credentials:

import Voltax from '@noelzappy/voltax';
const flutterwave = Voltax('flutterwave', {
secretKey: process.env.FLUTTERWAVE_SECRET_KEY!,
});
import { Currency } from '@noelzappy/voltax';
const payment = await flutterwave.initiatePayment({
amount: 5000,
email: 'customer@example.com',
currency: Currency.NGN,
reference: `flw-${Date.now()}`, // Required!
callbackUrl: 'https://yoursite.com/payment/callback',
});
// Redirect customer to complete payment
console.log(payment.authorizationUrl);
// "https://checkout.flutterwave.com/v3/hosted/pay/xxxxxxxxxx"
const payment = await flutterwave.initiatePayment({
amount: 10000,
email: 'customer@example.com',
currency: Currency.NGN,
reference: `order-${Date.now()}`,
mobileNumber: '+2348012345678',
description: 'Premium Subscription',
callbackUrl: 'https://yoursite.com/callback',
metadata: {
orderId: 'ORD-12345',
plan: 'premium',
},
customerName: 'John Doe',
});

Flutterwave supports extensive customization through top-level fields in the payment DTO:

Customize the payment page appearance:

const payment = await flutterwave.initiatePayment({
amount: 5000,
email: 'customer@example.com',
currency: Currency.NGN,
reference: `flw-${Date.now()}`,
// Flutterwave-specific options at top level
customerName: 'John Doe', // Customer name displayed on checkout
pageTitle: 'My Store Checkout', // Checkout page title
logoUrl: 'https://yoursite.com/logo.png', // Your logo on checkout page
});

Control session behavior:

const payment = await flutterwave.initiatePayment({
amount: 5000,
email: 'customer@example.com',
currency: Currency.NGN,
reference: `flw-${Date.now()}`,
sessionDuration: 30, // Session timeout in minutes (1-1440)
maxRetryAttempts: 3, // Max payment retry attempts (1-10)
linkExpiration: new Date('2026-12-31'), // Link expiration date
});

Specify allowed payment methods:

const payment = await flutterwave.initiatePayment({
amount: 5000,
email: 'customer@example.com',
currency: Currency.NGN,
reference: `flw-${Date.now()}`,
paymentOptions: 'card,banktransfer,ussd,mobilemoney',
});
});

Available Payment Options:

  • card - Debit/Credit cards
  • banktransfer - Bank transfers
  • ussd - USSD payments
  • mobilemoney - Mobile money
  • barter - Barter by Flutterwave
  • nqr - NQR payments

For recurring payments:

const payment = await flutterwave.initiatePayment({
amount: 5000,
email: 'customer@example.com',
currency: Currency.NGN,
reference: `sub-${Date.now()}`,
paymentPlan: 12345, // Payment plan ID (from Flutterwave dashboard)
});

Split payments between multiple accounts:

const payment = await flutterwave.initiatePayment({
amount: 10000,
email: 'customer@example.com',
currency: Currency.NGN,
reference: `split-${Date.now()}`,
subaccounts: [
{ id: 'RS_xxxxxxxxxxxxxxxxx' },
{ id: 'RS_yyyyyyyyyyyyyyyyy' },
],
});

All Flutterwave-specific options are available as top-level fields:

interface FlutterwavePaymentDTO {
// Base required fields
amount: number;
email: string;
currency: Currency;
reference: string; // Required for Flutterwave
// Optional base fields
callbackUrl?: string;
description?: string;
mobileNumber?: string;
metadata?: Record<string, any>;
// Flutterwave-specific options
customerName?: string; // Customer name for checkout display
pageTitle?: string; // Checkout page title
logoUrl?: string; // Logo URL for checkout page
sessionDuration?: number; // Session timeout in minutes (1-1440)
maxRetryAttempts?: number; // Maximum retry attempts (1-10)
paymentPlan?: number; // Payment plan ID for subscriptions
paymentOptions?: string; // Comma-separated payment options
linkExpiration?: Date; // Link expiration date
subaccounts?: Array<{ id: string }>; // Subaccounts for split payments
}

After the customer completes payment, verify the transaction:

import { PaymentStatus } from '@noelzappy/voltax';
const result = await flutterwave.verifyTransaction('flw-123456');
console.log(result);
// {
// status: 'SUCCESS',
// reference: 'flw-123456',
// externalReference: 'FLW-MOCK-xxxxxxxxxx',
// raw: { ... }
// }
if (result.status === PaymentStatus.SUCCESS) {
// Access detailed transaction data
const { amount, currency, customer } = result.raw.data;
console.log(`Received ${currency} ${amount} from ${customer.email}`);
}

Voltax maps Flutterwave statuses to standardized values:

Flutterwave StatusVoltax Status
successfulSUCCESS
failedFAILED
OtherPENDING

For a quick status check:

const status = await flutterwave.getPaymentStatus('flw-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 } from '@noelzappy/voltax';
import { randomUUID } from 'crypto';
const app = express();
app.use(express.json());
const flutterwave = Voltax('flutterwave', {
secretKey: process.env.FLUTTERWAVE_SECRET_KEY!,
});
// Initiate payment
app.post('/api/payments/flutterwave', async (req, res) => {
try {
const { amount, email, customerName, orderId } = req.body;
const reference = `order-${orderId}-${randomUUID()}`;
const payment = await flutterwave.initiatePayment({
amount,
email,
currency: Currency.NGN,
reference,
mobileNumber: req.body.phone,
callbackUrl: `${process.env.BASE_URL}/payment/callback`,
metadata: {
orderId,
createdAt: new Date().toISOString(),
},
customerName,
pageTitle: 'My Store - Checkout',
logoUrl: `${process.env.BASE_URL}/logo.png`,
sessionDuration: 30,
maxRetryAttempts: 3,
paymentOptions: 'card,banktransfer,ussd',
});
// Store reference in database
await savePaymentReference(orderId, reference);
res.json({
success: true,
checkoutUrl: payment.authorizationUrl,
reference: payment.reference,
});
} catch (error) {
console.error('Payment initialization failed:', error);
res.status(400).json({
success: false,
error: error.message
});
}
});
// Payment callback
app.get('/payment/callback', async (req, res) => {
const { tx_ref, status } = req.query;
try {
// Always verify server-side regardless of callback status
const result = await flutterwave.verifyTransaction(tx_ref as string);
if (result.status === PaymentStatus.SUCCESS) {
await markOrderAsPaid(tx_ref as string);
res.redirect('/order/success');
} else if (result.status === PaymentStatus.PENDING) {
res.redirect('/order/pending');
} else {
res.redirect('/order/failed');
}
} catch (error) {
console.error('Verification failed:', error);
res.redirect('/order/error');
}
});
// Webhook endpoint
app.post('/webhooks/flutterwave', async (req, res) => {
const payload = req.body;
// Verify webhook signature (implement based on Flutterwave docs)
if (payload.event === 'charge.completed') {
const { tx_ref } = payload.data;
// Verify and fulfill
const result = await flutterwave.verifyTransaction(tx_ref);
if (result.status === PaymentStatus.SUCCESS) {
await fulfillOrder(tx_ref);
}
}
res.status(200).send('OK');
});
app.listen(3000);
CurrencyCodeCountries
Nigerian NairaNGNNigeria
Ghanaian CediGHSGhana
Kenyan ShillingKESKenya
South African RandZARSouth Africa
US DollarUSDInternational

Flutterwave supports many more currencies. Check their documentation for the complete list.