Package Exports
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@tjoc/payments) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
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.