Skip to content

noelzappy/voltax

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

43 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

⚡ Voltax

The Unified Payment SDK for Africa

npm version License: MIT TypeScript PRs Welcome

Documentation · Report Bug · Request Feature


Why Voltax?

Building payment systems in Africa means dealing with multiple payment gateways, each with its own API, documentation, and quirks. Voltax solves this by providing:

  • 🔌 One Interface, Multiple Gateways - Write once, accept payments from Paystack, Flutterwave, Hubtel, and more
  • 🛡️ Type-Safe - Built with TypeScript and Zod for runtime validation
  • 🔄 Easy Provider Switching - Change payment providers without rewriting your code
  • Lightweight - Tree-shakeable, ESM & CJS support
  • 🧪 Well Tested - Comprehensive test coverage

Supported Payment Gateways

Gateway Countries Status
Paystack Nigeria, Ghana, South Africa, Kenya ✅ Ready
Flutterwave Nigeria, Ghana, Kenya, South Africa + ✅ Ready
Hubtel Ghana ✅ Ready
More coming... Contribute!

Installation

npm install @noelzappy/voltax
pnpm add @noelzappy/voltax
yarn add @noelzappy/voltax

Quick Start

Single Provider (Recommended)

import { Voltax, Currency, PaymentStatus } from '@noelzappy/voltax';

// Initialize a single provider
const paystack = Voltax('paystack', {
  secretKey: process.env.PAYSTACK_SECRET_KEY!,
});

// Initiate a payment
const payment = await paystack.initiatePayment({
  amount: 5000,
  email: 'customer@example.com',
  currency: Currency.NGN,
  reference: `order-${Date.now()}`,
  callbackUrl: 'https://yoursite.com/callback',
});

console.log(payment.authorizationUrl);
// Redirect customer to complete payment

// Verify the payment
const result = await paystack.verifyTransaction(payment.reference);

if (result.status === PaymentStatus.SUCCESS) {
  console.log('Payment successful!');
}

Multiple Providers

import { VoltaxAdapter, Currency } from '@noelzappy/voltax';

// Initialize multiple providers at once
const voltax = new VoltaxAdapter({
  paystack: { secretKey: process.env.PAYSTACK_SECRET_KEY! },
  flutterwave: { secretKey: process.env.FLUTTERWAVE_SECRET_KEY! },
  hubtel: {
    clientId: process.env.HUBTEL_CLIENT_ID!,
    clientSecret: process.env.HUBTEL_CLIENT_SECRET!,
    merchantAccountNumber: process.env.HUBTEL_MERCHANT_ACCOUNT!,
  },
});

// Use any configured provider
await voltax.paystack.initiatePayment({ ... });
await voltax.hubtel.initiatePayment({ ... });

Standardized API

All providers implement the same interface:

interface VoltaxProvider<TPaymentDTO> {
  initiatePayment(payload: TPaymentDTO): Promise<VoltaxPaymentResponse>;
  verifyTransaction(reference: string): Promise<VoltaxPaymentResponse>;
  getPaymentStatus(reference: string): Promise<PaymentStatus>;
}

Payment DTO

Each provider has its own typed payment DTO that extends the base schema. Common fields include:

// Base fields shared by all providers
{
  amount: number;         // Amount in major units (e.g., 100 for 100 NGN)
  email: string;          // Customer email
  currency: Currency;     // NGN, GHS, USD, KES, ZAR
  reference?: string;     // Your unique transaction reference
  mobileNumber?: string;  // Customer phone number
  description?: string;   // Transaction description
  callbackUrl?: string;   // Redirect URL after payment
  metadata?: object;      // Custom data
}

// Provider-specific fields are added at the top level
// e.g., Paystack adds: channels, subaccount, splitCode, etc.
// e.g., Hubtel adds: returnUrl, cancellationUrl (required fields)

VoltaxPaymentResponse

{
  status: PaymentStatus;      // SUCCESS, PENDING, or FAILED
  reference: string;          // Your transaction reference
  authorizationUrl?: string;  // Checkout URL
  externalReference?: string; // Provider's reference
  raw?: any;                  // Original provider response
}

Error Handling

Voltax provides structured error classes:

import {
  VoltaxValidationError,
  VoltaxGatewayError,
  VoltaxNetworkError,
} from '@noelzappy/voltax';

try {
  await voltax.paystack.initializePayment(payload);
} catch (error) {
  if (error instanceof VoltaxValidationError) {
    // Invalid payload - check error.errors for details
    console.error('Validation failed:', error.errors);
  } else if (error instanceof VoltaxGatewayError) {
    // Payment provider returned an error
    console.error('Gateway error:', error.message, error.statusCode);
  } else if (error instanceof VoltaxNetworkError) {
    // Network connectivity issue - safe to retry
    console.error('Network error:', error.message);
  }
}

Provider-Specific Features

Paystack

import { Voltax, PaystackChannel, Currency } from '@noelzappy/voltax';

const paystack = Voltax('paystack', {
  secretKey: process.env.PAYSTACK_SECRET_KEY!,
});

const payment = await paystack.initiatePayment({
  amount: 5000,
  email: 'customer@example.com',
  currency: Currency.NGN,
  // Paystack-specific options at top level
  channels: [PaystackChannel.CARD, PaystackChannel.BANK_TRANSFER],
  subaccount: 'ACCT_xxxxx',
  transactionCharge: 100,
});

Flutterwave

import { Voltax, Currency } from '@noelzappy/voltax';

const flutterwave = Voltax('flutterwave', {
  secretKey: process.env.FLUTTERWAVE_SECRET_KEY!,
});

const payment = await flutterwave.initiatePayment({
  amount: 5000,
  email: 'customer@example.com',
  currency: Currency.NGN,
  reference: 'order-123',  // Required for Flutterwave
  // Flutterwave-specific options at top level
  customerName: 'John Doe',
  pageTitle: 'My Store',
  logoUrl: 'https://yoursite.com/logo.png',
});

Hubtel

import { Voltax, Currency } from '@noelzappy/voltax';

const hubtel = Voltax('hubtel', {
  clientId: process.env.HUBTEL_CLIENT_ID!,
  clientSecret: process.env.HUBTEL_CLIENT_SECRET!,
  merchantAccountNumber: process.env.HUBTEL_MERCHANT_ACCOUNT!,
});

const payment = await hubtel.initiatePayment({
  amount: 100,
  email: 'customer@example.com',
  currency: Currency.GHS,
  reference: 'order-123',  // Required
  callbackUrl: 'https://yoursite.com/webhook',  // Required
  // Hubtel-specific options at top level
  returnUrl: 'https://yoursite.com/success',  // Required
});

Documentation

For complete documentation, visit voltax.noelzappy.dev

Contributing

We welcome contributions! Voltax aims to support all major African payment gateways, and we need your help.

Gateways we'd love to add:

  • M-Pesa (Kenya)
  • OPay (Nigeria)
  • Chipper Cash (Pan-African)
  • MTN MoMo (Ghana, Uganda)
  • Yoco (South Africa)
  • And many more!

See CONTRIBUTING.md for a complete guide on adding new payment gateways.

# Clone the repo
git clone https://github.com/noelzappy/voltax.git

# Install dependencies
cd voltax && npm install

# Run tests
cd packages/node && npm test

Monorepo Structure

voltax/
├── packages/
│   ├── node/          # Node.js SDK (@noelzappy/voltax)
│   ├── go/            # Go SDK (coming soon)
│   └── php/           # PHP SDK (coming soon)
└── docs/              # Documentation site

License

MIT © noelzappy


Built with ❤️ for African developers

⭐ Star us on GitHub

About

A polyglot open-source payment SDK designed to unify African payment infrastructure.

Topics

Resources

Contributing

Stars

Watchers

Forks

Packages