UNPKG

@vegaci_shared/vsplit-payment-gateway

Version:

A B2B payment gateway integration package for Stripe with split payment capabilities

605 lines (499 loc) 15.4 kB
# VSplit Payment Gateway A comprehensive B2B payment gateway integration package for Stripe with advanced split payment capabilities. ## Features - 🎯 **Simple Integration**: Minimal setup with just configuration - 💳 **Single Card Payments**: Traditional one-card payment processing - 🔄 **Customer Split Payments**: Let customers split their payment across multiple cards - ⏱️ **Timeout Management**: Automatic cancellation and refunds for incomplete payments - 💰 **Optional Merchant Splits**: Revenue sharing between merchant, platform, drivers, etc. - 🔒 **Secure**: Follows Stripe security best practices - 📱 **React Ready**: Built-in React hooks and components - 🎨 **Customizable**: Theming and styling options - 📊 **Real-time Status**: Payment verification and status tracking - 🪝 **Webhooks**: Event-driven architecture for notifications - 📱 **TypeScript**: Fully typed for better development experience ## 🚀 Live Demo Experience VSplit in action with our interactive demo application: **[→ Try Live Demo](https://vsplit-payment-gateway.vercel.app)** ### Local Demo Setup 1. **Clone & Setup:** ```bash git clone https://github.com/ModyG/vsplit-payment-gateway.git cd vsplit-payment-gateway npm run demo ``` 2. **Add your Stripe keys** to `demo/vsplit-demo/.env.local` 3. **Visit:** `http://localhost:3000` ### Demo Scenarios - **Customer Split Payment** - Customer chooses to split total across multiple cards - **Single Card Payment** - Traditional one-card payment processing - **Merchant Revenue Sharing** - Optional splits for merchant/platform/drivers - **Timeout & Auto-Refund** - Automatic refunds if split payments incomplete ## Installation ```bash npm install @vsplit/payment-gateway # or yarn add @vsplit/payment-gateway ``` ## Quick Start ### 1. Basic Setup (Vanilla JS/TS) ```typescript import VSplitPaymentGateway from '@vsplit/payment-gateway'; // Initialize the gateway const gateway = new VSplitPaymentGateway({ stripePublishableKey: 'pk_test_...', apiEndpoint: 'https://your-backend.com/api', apiKey: 'your-api-key', // optional currency: 'usd', defaultTimeout: 600, // 10 minutes }); // Single payment const paymentResult = await gateway.initializePayment({ amount: 5000, // $50.00 in cents currency: 'usd', orderId: 'order_123', customer: { email: 'customer@example.com', name: 'John Doe', }, }); // Process the payment const result = await gateway.processPayment(paymentResult.paymentId, { // Stripe payment method or elements }); ``` ### 2. React Integration ```tsx import React from 'react'; import { VSplitProvider, useVSplit, PaymentForm, } from '@vsplit/payment-gateway/react'; // Wrap your app function App() { return ( <VSplitProvider config={{ stripePublishableKey: 'pk_test_...', apiEndpoint: 'https://your-backend.com/api', }} > <PaymentPage /> </VSplitProvider> ); } // Payment component function PaymentPage() { const { initializePayment, status, loading, error } = useVSplit(); const handlePayment = async () => { await initializePayment({ amount: 5000, currency: 'usd', orderId: 'order_123', }); }; return ( <div> <button onClick={handlePayment} disabled={loading} > Start Payment </button> <PaymentForm onSuccess={(result) => console.log('Payment successful:', result)} onError={(error) => console.error('Payment failed:', error)} /> </div> ); } ``` ### 3. Customer Split Payments Customer wants to pay $100 but split across 3 cards: ```typescript // Customer chooses to split payment const splitSession = await gateway.initializeSplitPayment({ totalAmount: 10000, // $100.00 numberOfCards: 3, cardAmounts: [4000, 3500, 2500], // $40 + $35 + $25 = $100 currency: 'usd', orderId: 'order_123', customer: { email: 'customer@example.com', name: 'John Doe', }, timeout: 600, // 10 minutes to complete all payments }); // Process each card payment for (let i = 0; i < splitSession.cardPayments.length; i++) { const result = await gateway.processSplitPayment( splitSession.sessionId, i, paymentMethod // Customer's card data for this split ); if (!result.success) { console.log(`Card ${i + 1} failed:`, result.error); // Customer can retry or all payments will be refunded after timeout } } ``` ### 4. Merchant Revenue Splitting (Optional) After customer pays, split revenue between recipients: ````typescript // Initialize payment with automatic merchant splits const paymentResult = await gateway.initializePaymentWithMerchantSplits({ amount: 10000, // $100.00 customer payment currency: 'usd', orderId: 'order_123', customer: { email: 'customer@example.com', name: 'John Doe', }, // Optional: Automatically split revenue after successful payment merchantSplits: [ { amount: 8500, label: 'Merchant Revenue', recipient: 'merchant_123' }, // $85 { amount: 1000, label: 'Platform Fee', recipient: 'platform_123' }, // $10 { amount: 500, label: 'Processing Fee', recipient: 'processor_123' }, // $5 ], }); // Process customer's payment first const result = await gateway.processPayment(paymentResult.paymentId, paymentMethod); // If customer payment succeeds, merchant splits are processed automatically if (result.success) { console.log('Customer paid $100, revenue split between 3 recipients'); } ### 5. React Customer Split Payment Component ```tsx import { CustomerSplitPayment } from '@vsplit/payment-gateway/react'; function CustomerSplitPaymentPage() { const [paymentAmount, setPaymentAmount] = useState(10000); // $100 const [numberOfCards, setNumberOfCards] = useState(2); const handleSplitAmountChange = (cardIndex: number, amount: number) => { // Update split amounts ensuring they sum to total }; return ( <div> <h2>Split Your Payment</h2> <p>Total: ${(paymentAmount / 100).toFixed(2)}</p> <label> How many cards would you like to use? <select value={numberOfCards} onChange={(e) => setNumberOfCards(+e.target.value)}> <option value={1}>1 Card (Full Payment)</option> <option value={2}>2 Cards</option> <option value={3}>3 Cards</option> <option value={4}>4 Cards</option> </select> </label> {numberOfCards > 1 ? ( <CustomerSplitPayment totalAmount={paymentAmount} numberOfCards={numberOfCards} onStepComplete={(stepIndex, result) => { console.log(`Card ${stepIndex + 1} payment completed:`, result); }} onAllComplete={(session) => { console.log('All card payments completed:', session); }} onTimeout={(session) => { console.log('Payment timeout - refunding all successful payments'); }} onError={(error) => { console.error('Split payment error:', error); }} /> ) : ( <SinglePayment amount={paymentAmount} /> )} </div> ); } ```` ### 6. React Merchant Split Component (Optional) ```tsx import { MerchantSplitPayment } from '@vsplit/payment-gateway/react'; function MerchantSplitPaymentPage() { const merchantSplits = [ { amount: 8500, label: 'Your Revenue', recipient: 'merchant_123' }, { amount: 1000, label: 'Platform Fee', recipient: 'platform_123' }, { amount: 500, label: 'Payment Processing', recipient: 'stripe_123' }, ]; return ( <MerchantSplitPayment amount={10000} // $100 total customer payment merchantSplits={merchantSplits} onPaymentComplete={(result) => { console.log('Customer payment completed:', result); }} onSplitsComplete={(splits) => { console.log('Revenue splits completed:', splits); }} onError={(error) => { console.error('Payment or split error:', error); }} /> ); } ``` ## Configuration ### VSplitConfig ```typescript interface VSplitConfig { /** Stripe publishable key */ stripePublishableKey: string; /** API endpoint for your backend integration */ apiEndpoint: string; /** Optional API key for authentication */ apiKey?: string; /** Environment (sandbox/production) */ environment?: 'sandbox' | 'production'; /** Default currency (ISO 4217) */ currency?: string; /** Default timeout for split payments in seconds */ defaultTimeout?: number; /** Custom styling options */ theme?: PaymentTheme; } ``` ### PaymentTheme ```typescript interface PaymentTheme { /** Primary color */ primaryColor?: string; /** Border radius */ borderRadius?: string; /** Font family */ fontFamily?: string; /** Custom CSS classes */ customClasses?: { container?: string; button?: string; input?: string; error?: string; success?: string; }; } ``` ## Event Handling ```typescript // Listen to payment events gateway.on('payment:success', (result) => { console.log('Payment succeeded:', result); }); gateway.on('payment:failed', (result) => { console.log('Payment failed:', result); }); gateway.on('split:completed', (session) => { console.log('All split payments completed:', session); }); gateway.on('split:timeout', (session) => { console.log('Split payment timed out:', session); // Automatic refunds are handled internally }); gateway.on('error', (error) => { console.error('Gateway error:', error); }); ``` ## Backend Integration ### Required API Endpoints Your backend needs to implement these endpoints: #### POST /payment/initialize ```typescript { amount: number; currency: string; orderId: string; customer?: CustomerInfo; metadata?: Record<string, string>; } ``` #### POST /payment/split/initialize ```typescript { splits: Array<{ amount: number; label?: string }>; timeout?: number; } ``` #### POST /payment/refund ```typescript { paymentIntentId: string; amount?: number; reason?: string; } ``` ### Example Backend (Node.js/Express) ```typescript import Stripe from 'stripe'; import express from 'express'; const stripe = new Stripe('sk_test_...'); const app = express(); app.post('/api/payment/initialize', async (req, res) => { try { const { amount, currency, orderId } = req.body; const paymentIntent = await stripe.paymentIntents.create({ amount, currency, metadata: { orderId }, automatic_payment_methods: { enabled: true }, }); res.json({ success: true, data: { id: paymentIntent.id, clientSecret: paymentIntent.client_secret, status: paymentIntent.status, amount: paymentIntent.amount, currency: paymentIntent.currency, created: paymentIntent.created, }, }); } catch (error) { res.status(400).json({ success: false, error: error.message, }); } }); app.post('/api/payment/split/initialize', async (req, res) => { try { const { splits, timeout } = req.body; const paymentIntents = await Promise.all( splits.map((split) => stripe.paymentIntents.create({ amount: split.amount, currency: 'usd', automatic_payment_methods: { enabled: true }, }) ) ); const session = { sessionId: `split_${Date.now()}`, paymentIntents: paymentIntents.map((pi) => ({ id: pi.id, clientSecret: pi.client_secret, status: pi.status, amount: pi.amount, currency: pi.currency, created: pi.created, })), status: 'pending', totalAmount: splits.reduce((sum, split) => sum + split.amount, 0), currency: 'usd', expiresAt: Date.now() + timeout * 1000, completedPayments: 0, failedPayments: 0, }; res.json({ success: true, data: session, }); } catch (error) { res.status(400).json({ success: false, error: error.message, }); } }); ``` ## Webhook Handling ```typescript import { WebhookEvent } from '@vsplit/payment-gateway'; app.post('/webhooks/vsplit', (req, res) => { const event: WebhookEvent = req.body; switch (event.type) { case 'payment.succeeded': // Handle successful payment break; case 'split_payment.completed': // Handle completed split payment break; case 'split_payment.timeout': // Handle split payment timeout break; default: console.log(`Unhandled event type: ${event.type}`); } res.json({ received: true }); }); ``` ## Styling ### CSS Classes The package includes built-in CSS classes that you can customize: ```css /* Import the base styles */ @import '@vsplit/payment-gateway/dist/styles.css'; /* Customize as needed */ .vsplit-container { border-radius: 12px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); } .vsplit-button { background: linear-gradient(45deg, #007bff, #0056b3); } ``` ### Custom Theme ```typescript const gateway = new VSplitPaymentGateway({ // ... other config theme: { primaryColor: '#007bff', borderRadius: '8px', fontFamily: 'Inter, sans-serif', customClasses: { container: 'my-custom-container', button: 'my-custom-button', }, }, }); ``` ## Error Handling ```typescript try { const result = await gateway.processPayment(paymentId, paymentMethod); if (!result.success) { // Handle payment failure console.error('Payment failed:', result.error); } } catch (error) { // Handle unexpected errors console.error('Unexpected error:', error); } ``` ## TypeScript Support The package is fully typed. Import types as needed: ```typescript import { VSplitConfig, PaymentResult, PaymentSessionConfig, SplitPaymentConfig, PaymentStatus, WebhookEvent, } from '@vsplit/payment-gateway'; ``` ## Testing ```typescript // Use Stripe test keys for development const gateway = new VSplitPaymentGateway({ stripePublishableKey: 'pk_test_...', apiEndpoint: 'http://localhost:3000/api', environment: 'sandbox', }); // Test card numbers (Stripe test cards) // 4242424242424242 - Visa // 4000000000000002 - Card declined // 4000000000009995 - Insufficient funds ``` ## Security Best Practices 1. **API Keys**: Never expose secret keys in frontend code 2. **HTTPS**: Always use HTTPS in production 3. **Validation**: Validate all inputs on your backend 4. **Webhooks**: Verify webhook signatures 5. **PCI Compliance**: This package handles sensitive data securely through Stripe ## Support - 📧 Email: support@vsplit.com - 📚 Documentation: https://docs.vsplit.com - 🐛 Issues: https://github.com/ModyG/vsplit/issues ## License MIT License - see LICENSE file for details.