npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@tjoc/payments

v2.0.0

Published

A comprehensive payment integration system that intelligently routes payments between Stripe and Paystack based on geographical context, with built-in retry logic and fallback mechanisms.

Downloads

10

Readme

Payment Integration Package

A comprehensive payment integration system that intelligently routes payments between Stripe and Paystack based on geographical context, with built-in retry logic and fallback mechanisms.

Features

  • Intelligent Provider Routing: Automatically selects the best payment provider based on customer location and currency
  • Multi-Provider Support: Seamlessly integrates with both Stripe and Paystack
  • Geographic Detection: Detects customer country from IP address or browser locale
  • Retry Logic: Built-in retry mechanisms with exponential backoff
  • Fallback Support: Automatic fallback to secondary provider if primary fails
  • Webhook Handling: Unified webhook processing for both providers
  • TypeScript Support: Fully typed interfaces and comprehensive error handling

Installation

# Using pnpm (recommended)
pnpm add @tjoc/payments

# Using npm
npm install @tjoc/payments

# Using yarn
yarn add @tjoc/payments

Quick Start

Basic Setup

import { 
  PaymentRouter, 
  StripeProvider, 
  PaystackProvider,
  CountryDetectionService 
} from '@tjoc/payments';

// Initialize providers
const stripeProvider = new StripeProvider({
  apiKey: process.env.STRIPE_SECRET_KEY!,
});

const paystackProvider = new PaystackProvider({
  secretKey: process.env.PAYSTACK_SECRET_KEY!,
  publicKey: process.env.PAYSTACK_PUBLIC_KEY!,
});

// Create payment router
const paymentRouter = new PaymentRouter({
  providers: {
    primary: stripeProvider,
    fallback: paystackProvider
  },
  routing: {
    paystackCountries: ['NG', 'GH', 'ZA', 'KE'], // Nigeria, Ghana, South Africa, Kenya
    defaultProvider: 'stripe'
  },
  retryConfig: {
    maxRetries: 2,
    retryDelay: 1000
  }
});

Creating a Payment

// Create a payment with automatic provider selection
const transaction = await paymentRouter.createPayment({
  amount: 100.00,
  currency: 'USD',
  customerId: 'cust_123',
  description: 'Product purchase'
}, {
  country: 'US', // Optional: helps with provider selection
  currency: 'USD'
});

console.log('Payment created:', transaction.id);
console.log('Provider used:', transaction.provider);

Geographic Detection

// Detect country from IP address
const geoInfo = await CountryDetectionService.detectCountryFromIP('192.168.1.1');
if (geoInfo) {
  console.log('Country:', geoInfo.country);
  console.log('Currency:', geoInfo.currency);
}

// Get country information and preferred provider
const countryInfo = CountryDetectionService.getCountryInfo('NG');
console.log('Preferred provider for Nigeria:', countryInfo.preferredProvider); // 'paystack'

// Check if country supports Paystack
const supportsPaystack = CountryDetectionService.isPaystackCountry('NG');
console.log('Nigeria supports Paystack:', supportsPaystack); // true

API Reference

PaymentRouter

The main class that handles intelligent routing between payment providers.

Constructor

interface PaymentRouterConfig {
  providers: {
    primary: PaymentProvider;
    fallback?: PaymentProvider;
  };
  routing: {
    paystackCountries: string[]; // Country codes that should use Paystack
    defaultProvider: 'stripe' | 'paystack';
  };
  retryConfig?: {
    maxRetries: number;
    retryDelay: number;
  };
}

Methods

Payment Operations
// Create a new payment
createPay ment(options: CreatePaymentOptions, context?: PaymentContext): Promise<Transaction>

// Confirm a payment
confirmPayment(paymentId: string, context?: PaymentContext): Promise<Transaction>

// Cancel a payment
cancelPayment(paymentId: string, context?: PaymentContext): Promise<Transaction>

// Get payment details
getPayment(paymentId: string, context?: PaymentContext): Promise<Transaction>
Customer Operations
// Create a customer
createCustomer(data: Partial<Customer>, context?: PaymentContext): Promise<Customer>

// Update customer
updateCustomer(customerId: string, data: Partial<Customer>, context?: PaymentContext): Promise<Customer>

// Get customer
getCustomer(customerId: string, context?: PaymentContext): Promise<Customer>

// Delete customer
deleteCustomer(customerId: string, context?: PaymentContext): Promise<boolean>
Subscription Operations
// Create subscription
createSubscription(options: CreateSubscriptionOptions, context?: PaymentContext): Promise<Subscription>

// Update subscription
updateSubscription(subscriptionId: string, data: Partial<Subscription>, context?: PaymentContext): Promise<Subscription>

// Cancel subscription
cancelSubscription(subscriptionId: string, context?: PaymentContext): Promise<Subscription>

// Get subscription
getSubscription(subscriptionId: string, context?: PaymentContext): Promise<Subscription>

// List customer subscriptions
listCustomerSubscriptions(customerId: string, context?: PaymentContext): Promise<Subscription[]>

CountryDetectionService

Static service for geographic detection and provider recommendations.

Methods

// Detect country from IP address
static detectCountryFromIP(ipAddress?: string): Promise<GeoLocation | null>

// Detect country from browser
static detectCountryFromBrowser(): GeoLocation | null

// Get currency for country
static getCurrencyForCountry(countryCode: string): string

// Get preferred provider for country
static getPreferredProvider(countryCode: string): 'stripe' | 'paystack'

// Check if country supports Paystack
static isPaystackCountry(countryCode: string): boolean

// Get comprehensive country information
static getCountryInfo(countryCode: string): CountryInfo

Provider Classes

StripeProvider

interface StripeConfig {
  apiKey: string;
  webhookHandlers?: WebhookHandlerConfig;
}

const stripe = new StripeProvider(config);

PaystackProvider

interface PaystackConfig {
  secretKey: string;
  publicKey: string;
  webhookSecret?: string;
  testMode?: boolean;
}

const paystack = new PaystackProvider(config);

Routing Logic

The payment router uses the following logic to select providers:

  1. Country-based routing: If the customer's country is in the paystackCountries list, Paystack is preferred
  2. Currency-based routing: If the currency is NGN (Nigerian Naira), Paystack is preferred
  3. Default provider: Falls back to the configured default provider
  4. Retry logic: If the primary provider fails, retries with exponential backoff
  5. Fallback provider: If all retries fail, attempts with the fallback provider

Supported Countries for Paystack

  • NG - Nigeria
  • GH - Ghana
  • ZA - South Africa
  • KE - Kenya

Webhook Handling

Setting up Webhooks

// Stripe webhooks
const stripeProvider = new StripeProvider({
  apiKey: process.env.STRIPE_SECRET_KEY!,
  webhookHandlers: {
    'payment_intent.succeeded': async (event) => {
      console.log('Stripe payment succeeded:', event.data.object);
    },
    'payment_intent.payment_failed': async (event) => {
      console.log('Stripe payment failed:', event.data.object);
    }
  }
});

// Paystack webhooks
const paystackProvider = new PaystackProvider({
  secretKey: process.env.PAYSTACK_SECRET_KEY!,
  publicKey: process.env.PAYSTACK_PUBLIC_KEY!,
  webhookSecret: process.env.PAYSTACK_WEBHOOK_SECRET
});

Processing Webhooks

// In your webhook endpoint
app.post('/webhooks/:provider', async (req, res) => {
  const provider = req.params.provider as 'stripe' | 'paystack';
  const signature = req.headers['stripe-signature'] || req.headers['x-paystack-signature'];
  
  try {
    await paymentRouter.handleWebhook(provider, req.body, signature);
    res.json({ success: true });
  } catch (error) {
    res.status(400).json({ error: error.message });
  }
});

Error Handling

The package includes comprehensive error handling:

import { PaymentProviderError, ConfigurationError } from '@your-org/payments';

try {
  const transaction = await paymentRouter.createPayment(options);
} catch (error) {
  if (error instanceof PaymentProviderError) {
    console.error('Payment provider error:', error.code, error.message);
  } else if (error instanceof ConfigurationError) {
    console.error('Configuration error:', error.message);
  } else {
    console.error('Unknown error:', error);
  }
}

Environment Variables

# Stripe
STRIPE_SECRET_KEY=sk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...

# Paystack
PAYSTACK_SECRET_KEY=sk_test_...
PAYSTACK_PUBLIC_KEY=pk_test_...

# Environment
NODE_ENV=development

Examples

See the usage examples for comprehensive implementation examples including:

  • Express.js integration
  • Next.js API routes
  • React hooks for frontend
  • Webhook handling
  • Error management

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Add tests
  5. Submit a pull request

License

MIT License - see LICENSE file for details.