Home
Softono
voltax

voltax

Open source TypeScript
13
Stars
1
Forks
0
Issues
0
Watchers
3 months
Last Commit

About voltax

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

Platforms

Web Self-hosted

Languages

TypeScript

⚑ 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: '[email protected]',
  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: '[email protected]',
  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: '[email protected]',
  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: '[email protected]',
  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

Releasing

To publish a new version of the Node.js SDK to npm:

cd packages/node

# Patch release (0.0.x) - bug fixes
npm run release:patch

# Minor release (0.x.0) - new features
npm run release:minor

# Major release (x.0.0) - breaking changes
npm run release:major

This triggers the release workflow which:

  • Runs tests
  • Builds the package
  • Creates a GitHub Release with auto-generated changelog
  • Publishes to npm and GitHub Packages

License

MIT Β© noelzappy


Built with ❀️ for African developers

⭐ Star us on GitHub