@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
Maintainers
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/paymentsQuick 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); // trueAPI 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): CountryInfoProvider 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:
- Country-based routing: If the customer's country is in the
paystackCountrieslist, Paystack is preferred - Currency-based routing: If the currency is NGN (Nigerian Naira), Paystack is preferred
- Default provider: Falls back to the configured default provider
- Retry logic: If the primary provider fails, retries with exponential backoff
- 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=developmentExamples
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
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests
- Submit a pull request
License
MIT License - see LICENSE file for details.
