Use Cases
This guide covers real-world use cases and integration patterns for Zelta Pay API. Learn how to implement common scenarios and best practices.
E-commerce Integration
Section titled “E-commerce Integration”Online Store Payment Links
Section titled “Online Store Payment Links”Create payment links for individual products or orders:
async function createProductPaymentLink(product, customer) { const paymentLinkData = { concept: `${product.name} - ${product.category}`, amount: product.price * 100, // Convert to cents customerName: customer.name, isTest: process.env.NODE_ENV !== 'production', redirectUrl: `${process.env.FRONTEND_URL}/products/${product.id}/success`, metadata: { productId: product.id, category: product.category, customerId: customer.id, orderType: 'single_product' } };
return await createPaymentLink(process.env.ZELTA_API_KEY, paymentLinkData);}
// Usageconst product = { id: 'PROD-123', name: 'Wireless Headphones', category: 'Electronics', price: 99.99};
const customer = { id: 'CUST-456', name: 'John Doe'};
const paymentLink = await createProductPaymentLink(product, customer);console.log('Payment link created:', paymentLink.paymentLinkUrl);Shopping Cart Checkout
Section titled “Shopping Cart Checkout”Create payment links for complete shopping carts:
async function createCartPaymentLink(cart, customer) { const totalAmount = cart.items.reduce((sum, item) => sum + (item.price * item.quantity), 0);
const paymentLinkData = { concept: `Order #${cart.id} - ${cart.items.length} items`, amount: Math.round(totalAmount * 100), // Convert to cents customerName: customer.name, isTest: process.env.NODE_ENV !== 'production', redirectUrl: `${process.env.FRONTEND_URL}/orders/${cart.id}/success`, metadata: { cartId: cart.id, customerId: customer.id, itemCount: cart.items.length, items: cart.items.map(item => `${item.name} x${item.quantity}`).join(', '), orderType: 'shopping_cart' } };
return await createPaymentLink(process.env.ZELTA_API_KEY, paymentLinkData);}
// Usageconst cart = { id: 'CART-789', items: [ { name: 'Laptop', price: 999.99, quantity: 1 }, { name: 'Mouse', price: 29.99, quantity: 2 } ]};
const customer = { id: 'CUST-456', name: 'Jane Smith'};
const paymentLink = await createCartPaymentLink(cart, customer);console.log('Cart payment link:', paymentLink.paymentLinkUrl);Order Status Tracking
Section titled “Order Status Tracking”Track payment status for orders:
async function trackOrderPaymentStatus(orderId) { try { // Get all payment links const allLinks = await getAllPaymentLinks(process.env.ZELTA_API_KEY);
// Find payment link for this order const orderPaymentLink = allLinks.find(link => link.metadata?.orderId === orderId );
if (!orderPaymentLink) { throw new Error('Payment link not found for order'); }
// Get detailed payment link info const hashUrl = orderPaymentLink.paymentLinkUrl.split('/').pop(); const paymentLink = await getPaymentLink(process.env.ZELTA_API_KEY, hashUrl);
return { orderId: orderId, paymentStatus: paymentLink.status, amount: paymentLink.amount, customerName: paymentLink.customerName, concept: paymentLink.concept, createdAt: paymentLink.createdAt, completedAt: paymentLink.completedAt, cancelledAt: paymentLink.cancelledAt, expiresAt: paymentLink.expiresAt, isPaid: paymentLink.status === 'completed', isPending: paymentLink.status === 'pending', isCancelled: paymentLink.status === 'cancelled', isExpired: paymentLink.status === 'expired' }; } catch (error) { console.error('Error tracking order payment:', error); throw error; }}
// Usageconst orderStatus = await trackOrderPaymentStatus('ORD-123');console.log('Order payment status:', orderStatus);Subscription Management
Section titled “Subscription Management”Monthly Subscription Payments
Section titled “Monthly Subscription Payments”Create payment links for recurring subscriptions:
async function createSubscriptionPaymentLink(subscription) { const paymentLinkData = { concept: `${subscription.planName} - ${subscription.billingCycle}`, amount: subscription.amount, customerName: subscription.customerName, isTest: process.env.NODE_ENV !== 'production', redirectUrl: `${process.env.FRONTEND_URL}/subscriptions/${subscription.id}/success`, metadata: { subscriptionId: subscription.id, customerId: subscription.customerId, plan: subscription.planName, billingCycle: subscription.billingCycle, startDate: subscription.startDate, trialEndsAt: subscription.trialEndsAt, paymentType: 'subscription' } };
return await createPaymentLink(process.env.ZELTA_API_KEY, paymentLinkData);}
// Usageconst subscription = { id: 'SUB-456', planName: 'Premium Plan', billingCycle: 'monthly', amount: 2999, // $29.99 in cents customerName: 'Bob Smith', customerId: 'CUST-123', startDate: '2024-01-15', trialEndsAt: '2024-02-15'};
const paymentLink = await createSubscriptionPaymentLink(subscription);console.log('Subscription payment link:', paymentLink.paymentLinkUrl);Subscription Renewal Tracking
Section titled “Subscription Renewal Tracking”Track subscription renewals and payments:
async function trackSubscriptionRenewals(customerId) { try { // Get all payment links const allLinks = await getAllPaymentLinks(process.env.ZELTA_API_KEY);
// Filter by customer and subscription type const subscriptionPayments = allLinks.filter(link => link.metadata?.customerId === customerId && link.metadata?.paymentType === 'subscription' );
// Get detailed info for each payment const detailedPayments = await Promise.all( subscriptionPayments.map(async (link) => { const hashUrl = link.paymentLinkUrl.split('/').pop(); return await getPaymentLink(process.env.ZELTA_API_KEY, hashUrl); }) );
// Calculate subscription metrics const metrics = { totalPayments: detailedPayments.length, completedPayments: detailedPayments.filter(p => p.status === 'completed').length, pendingPayments: detailedPayments.filter(p => p.status === 'pending').length, totalAmount: detailedPayments .filter(p => p.status === 'completed') .reduce((sum, p) => sum + p.amount, 0), lastPayment: detailedPayments .filter(p => p.status === 'completed') .sort((a, b) => new Date(b.completedAt) - new Date(a.completedAt))[0], nextPayment: detailedPayments .filter(p => p.status === 'pending') .sort((a, b) => new Date(a.expiresAt) - new Date(b.expiresAt))[0] };
return { customerId: customerId, payments: detailedPayments, metrics: metrics }; } catch (error) { console.error('Error tracking subscription renewals:', error); throw error; }}
// Usageconst subscriptionData = await trackSubscriptionRenewals('CUST-123');console.log('Subscription data:', subscriptionData);Service Payments
Section titled “Service Payments”Consulting Services
Section titled “Consulting Services”Create payment links for consulting services:
async function createConsultingPaymentLink(consultation) { const paymentLinkData = { concept: `Consulting Session - ${consultation.serviceType}`, amount: consultation.hourlyRate * consultation.hours * 100, // Convert to cents customerName: consultation.clientName, isTest: process.env.NODE_ENV !== 'production', redirectUrl: `${process.env.FRONTEND_URL}/consultations/${consultation.id}/success`, metadata: { consultationId: consultation.id, clientId: consultation.clientId, serviceType: consultation.serviceType, hourlyRate: consultation.hourlyRate, hours: consultation.hours, scheduledDate: consultation.scheduledDate, consultantId: consultation.consultantId, paymentType: 'consulting' } };
return await createPaymentLink(process.env.ZELTA_API_KEY, paymentLinkData);}
// Usageconst consultation = { id: 'CONS-789', serviceType: 'Technical Consulting', hourlyRate: 150, hours: 2, clientName: 'Acme Corp', clientId: 'CLIENT-123', scheduledDate: '2024-01-20T14:00:00Z', consultantId: 'CONSULTANT-456'};
const paymentLink = await createConsultingPaymentLink(consultation);console.log('Consulting payment link:', paymentLink.paymentLinkUrl);Event Registration
Section titled “Event Registration”Create payment links for event registrations:
async function createEventRegistrationPaymentLink(event, attendee) { const paymentLinkData = { concept: `Event Registration - ${event.name}`, amount: event.ticketPrice * 100, // Convert to cents customerName: attendee.name, isTest: process.env.NODE_ENV !== 'production', redirectUrl: `${process.env.FRONTEND_URL}/events/${event.id}/registration-success`, metadata: { eventId: event.id, attendeeId: attendee.id, eventName: event.name, eventDate: event.date, ticketType: event.ticketType, venue: event.venue, paymentType: 'event_registration' } };
return await createPaymentLink(process.env.ZELTA_API_KEY, paymentLinkData);}
// Usageconst event = { id: 'EVENT-123', name: 'Tech Conference 2024', date: '2024-03-15T09:00:00Z', ticketPrice: 299.99, ticketType: 'Early Bird', venue: 'Convention Center'};
const attendee = { id: 'ATTENDEE-456', name: 'Sarah Johnson'};
const paymentLink = await createEventRegistrationPaymentLink(event, attendee);console.log('Event registration payment link:', paymentLink.paymentLinkUrl);Webhook Integration
Section titled “Webhook Integration”Payment Success Handler
Section titled “Payment Success Handler”Handle successful payments with webhooks:
async function handlePaymentSuccess(payload) { const eventId = payload.eventId; const orderId = payload.metadata.orderId; const customerEmail = payload.customer.customerEmail; const amount = payload.transaction.amount;
try { // Check if already processed if (await isEventProcessed(eventId)) { console.log(`Event ${eventId} already processed`); return; }
// Process payment atomically await db.transaction(async (trx) => { // Update order status await trx('orders') .where('id', orderId) .update({ status: 'paid', paid_at: payload.transaction.paidAt, payment_id: payload.transaction.externalPaymentId });
// Send confirmation email await sendConfirmationEmail(customerEmail, { orderId: orderId, amount: amount, concept: payload.transaction.concept });
// Trigger fulfillment await triggerFulfillment(orderId);
// Mark event as processed await trx('webhook_events').insert({ event_id: eventId, event_type: 'payment.success', status: 'processed', processed_at: new Date() }); });
console.log(`Payment processed successfully for order ${orderId}`);
} catch (error) { console.error(`Error processing payment for order ${orderId}:`, error); throw error; }}
// Webhook endpointapp.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => { try { // Verify signature if (!verifySignature(req)) { return res.status(401).json({ error: 'Invalid signature' }); }
const payload = JSON.parse(req.body);
if (payload.type === 'payment.success') { handlePaymentSuccess(payload); }
res.status(200).json({ received: true });
} catch (error) { console.error('Webhook processing error:', error); res.status(500).json({ error: 'Processing failed' }); }});Subscription Renewal Handler
Section titled “Subscription Renewal Handler”Handle subscription renewal payments:
async function handleSubscriptionRenewal(payload) { const eventId = payload.eventId; const subscriptionId = payload.metadata.subscriptionId; const customerId = payload.metadata.customerId;
try { // Check if already processed if (await isEventProcessed(eventId)) { console.log(`Event ${eventId} already processed`); return; }
// Process subscription renewal await db.transaction(async (trx) => { // Update subscription status await trx('subscriptions') .where('id', subscriptionId) .update({ status: 'active', last_payment_date: payload.transaction.paidAt, next_billing_date: calculateNextBillingDate(payload.metadata.billingCycle) });
// Send renewal confirmation await sendRenewalConfirmation(customerId, { subscriptionId: subscriptionId, amount: payload.transaction.amount, billingCycle: payload.metadata.billingCycle });
// Mark event as processed await trx('webhook_events').insert({ event_id: eventId, event_type: 'payment.success', status: 'processed', processed_at: new Date() }); });
console.log(`Subscription renewal processed for ${subscriptionId}`);
} catch (error) { console.error(`Error processing subscription renewal for ${subscriptionId}:`, error); throw error; }}
function calculateNextBillingDate(billingCycle) { const nextDate = new Date();
switch (billingCycle) { case 'monthly': nextDate.setMonth(nextDate.getMonth() + 1); break; case 'yearly': nextDate.setFullYear(nextDate.getFullYear() + 1); break; default: throw new Error(`Unknown billing cycle: ${billingCycle}`); }
return nextDate;}Analytics and Reporting
Section titled “Analytics and Reporting”Payment Analytics
Section titled “Payment Analytics”Generate payment analytics and reports:
async function generatePaymentAnalytics(startDate, endDate) { try { // Get all payment links const allLinks = await getAllPaymentLinks(process.env.ZELTA_API_KEY);
// Filter by date range const filteredLinks = allLinks.filter(link => { const createdAt = new Date(link.createdAt); return createdAt >= startDate && createdAt <= endDate; });
// Calculate analytics const analytics = { period: { startDate: startDate, endDate: endDate }, totals: { totalPayments: filteredLinks.length, completedPayments: filteredLinks.filter(link => link.status === 'completed').length, pendingPayments: filteredLinks.filter(link => link.status === 'pending').length, cancelledPayments: filteredLinks.filter(link => link.status === 'cancelled').length, expiredPayments: filteredLinks.filter(link => link.status === 'expired').length }, revenue: { totalAmount: filteredLinks .filter(link => link.status === 'completed') .reduce((sum, link) => sum + link.amount, 0), averageAmount: 0, highestAmount: 0, lowestAmount: Infinity }, trends: { dailyPayments: {}, weeklyPayments: {}, monthlyPayments: {} }, categories: {} };
// Calculate revenue metrics const completedPayments = filteredLinks.filter(link => link.status === 'completed'); if (completedPayments.length > 0) { analytics.revenue.averageAmount = analytics.revenue.totalAmount / completedPayments.length; analytics.revenue.highestAmount = Math.max(...completedPayments.map(link => link.amount)); analytics.revenue.lowestAmount = Math.min(...completedPayments.map(link => link.amount)); }
// Calculate trends filteredLinks.forEach(link => { const date = new Date(link.createdAt); const dayKey = date.toISOString().split('T')[0]; const weekKey = getWeekKey(date); const monthKey = date.toISOString().substring(0, 7);
analytics.trends.dailyPayments[dayKey] = (analytics.trends.dailyPayments[dayKey] || 0) + 1; analytics.trends.weeklyPayments[weekKey] = (analytics.trends.weeklyPayments[weekKey] || 0) + 1; analytics.trends.monthlyPayments[monthKey] = (analytics.trends.monthlyPayments[monthKey] || 0) + 1; });
// Calculate categories filteredLinks.forEach(link => { const category = link.metadata?.category || 'uncategorized'; if (!analytics.categories[category]) { analytics.categories[category] = { count: 0, totalAmount: 0, completedAmount: 0 }; }
analytics.categories[category].count++; analytics.categories[category].totalAmount += link.amount;
if (link.status === 'completed') { analytics.categories[category].completedAmount += link.amount; } });
return analytics;
} catch (error) { console.error('Error generating payment analytics:', error); throw error; }}
function getWeekKey(date) { const year = date.getFullYear(); const week = Math.ceil(((date - new Date(year, 0, 1)) / 86400000 + 1) / 7); return `${year}-W${week.toString().padStart(2, '0')}`;}
// Usageconst startDate = new Date('2024-01-01');const endDate = new Date('2024-01-31');const analytics = await generatePaymentAnalytics(startDate, endDate);console.log('Payment analytics:', analytics);Customer Payment History
Section titled “Customer Payment History”Get payment history for specific customers:
async function getCustomerPaymentHistory(customerId) { try { // Get all payment links const allLinks = await getAllPaymentLinks(process.env.ZELTA_API_KEY);
// Filter by customer ID const customerPayments = allLinks.filter(link => link.metadata?.customerId === customerId );
// Get detailed information for each payment const detailedPayments = await Promise.all( customerPayments.map(async (link) => { const hashUrl = link.paymentLinkUrl.split('/').pop(); return await getPaymentLink(process.env.ZELTA_API_KEY, hashUrl); }) );
// Sort by creation date (newest first) detailedPayments.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt));
// Calculate customer metrics const metrics = { totalPayments: detailedPayments.length, completedPayments: detailedPayments.filter(p => p.status === 'completed').length, pendingPayments: detailedPayments.filter(p => p.status === 'pending').length, cancelledPayments: detailedPayments.filter(p => p.status === 'cancelled').length, expiredPayments: detailedPayments.filter(p => p.status === 'expired').length, totalAmount: detailedPayments .filter(p => p.status === 'completed') .reduce((sum, p) => sum + p.amount, 0), averageAmount: 0, firstPayment: detailedPayments[detailedPayments.length - 1], lastPayment: detailedPayments[0] };
if (metrics.completedPayments > 0) { metrics.averageAmount = metrics.totalAmount / metrics.completedPayments; }
return { customerId: customerId, payments: detailedPayments, metrics: metrics };
} catch (error) { console.error('Error getting customer payment history:', error); throw error; }}
// Usageconst customerHistory = await getCustomerPaymentHistory('CUST-123');console.log('Customer payment history:', customerHistory);Best Practices
Section titled “Best Practices”1. Error Handling
Section titled “1. Error Handling”Always implement proper error handling:
async function createPaymentLinkSafely(data) { try { // Validate input if (!data.concept || !data.amount || !data.customerName) { throw new Error('Missing required fields'); }
if (data.amount < 100 || data.amount > 200000) { throw new Error('Amount must be between $1.00 and $2,000.00'); }
return await createPaymentLink(process.env.ZELTA_API_KEY, data);
} catch (error) { console.error('Error creating payment link:', error); throw error; }}2. Rate Limiting
Section titled “2. Rate Limiting”Implement rate limiting for high-volume operations:
class RateLimiter { constructor(limit = 60, window = 60000) { // 60 requests per minute this.limit = limit; this.window = window; this.requests = []; }
async checkLimit() { const now = Date.now();
// Remove old requests this.requests = this.requests.filter(time => now - time < this.window);
if (this.requests.length >= this.limit) { const oldestRequest = Math.min(...this.requests); const waitTime = this.window - (now - oldestRequest); await new Promise(resolve => setTimeout(resolve, waitTime)); }
this.requests.push(now); }}
const rateLimiter = new RateLimiter();
async function createPaymentLinkWithRateLimit(data) { await rateLimiter.checkLimit(); return await createPaymentLink(process.env.ZELTA_API_KEY, data);}3. Caching
Section titled “3. Caching”Cache frequently accessed data:
const paymentLinkCache = new Map();
async function getCachedPaymentLink(hashUrl, ttl = 300000) { // 5 minutes const cached = paymentLinkCache.get(hashUrl);
if (cached && Date.now() - cached.timestamp < ttl) { return cached.data; }
const paymentLink = await getPaymentLink(process.env.ZELTA_API_KEY, hashUrl);
paymentLinkCache.set(hashUrl, { data: paymentLink, timestamp: Date.now() });
return paymentLink;}4. Logging
Section titled “4. Logging”Implement comprehensive logging:
function logPaymentLinkOperation(operation, data, result) { console.log('Payment Link Operation:', { operation: operation, timestamp: new Date().toISOString(), data: data, result: result, success: !!result });}
async function createPaymentLinkWithLogging(data) { try { const result = await createPaymentLink(process.env.ZELTA_API_KEY, data); logPaymentLinkOperation('create', data, result); return result; } catch (error) { logPaymentLinkOperation('create', data, { error: error.message }); throw error; }}Testing
Section titled “Testing”Unit Tests
Section titled “Unit Tests”Test individual functions:
describe('Payment Link Creation', () => { test('should create payment link with valid data', async () => { const data = { concept: 'Test Payment', amount: 1000, customerName: 'Test Customer', isTest: true };
const result = await createPaymentLink('test-api-key', data);
expect(result).toBeDefined(); expect(result.paymentLinkUrl).toContain('pay.zelta.dev'); expect(result.amount).toBe(1000); });
test('should throw error for invalid amount', async () => { const data = { concept: 'Test Payment', amount: 50, // Below minimum customerName: 'Test Customer', isTest: true };
await expect(createPaymentLink('test-api-key', data)) .rejects.toThrow('Amount must be at least $1.00'); });});Integration Tests
Section titled “Integration Tests”Test complete workflows:
describe('E-commerce Integration', () => { test('should complete order payment workflow', async () => { // Create product payment link const product = { id: 'PROD-123', name: 'Test Product', price: 99.99 };
const customer = { id: 'CUST-456', name: 'Test Customer' };
const paymentLink = await createProductPaymentLink(product, customer);
// Simulate payment completion const webhookPayload = { eventId: 'evt_test_123', type: 'payment.success', transaction: { amount: 9999, paidAt: new Date().toISOString() }, customer: { customerEmail: 'test@example.com' }, metadata: { productId: product.id, customerId: customer.id } };
await handlePaymentSuccess(webhookPayload);
// Verify order status const orderStatus = await trackOrderPaymentStatus('ORD-123'); expect(orderStatus.isPaid).toBe(true); });});Related Documentation
Section titled “Related Documentation”- Quick Start - Get started with Zelta Pay API
- Authentication - Learn about API key authentication
- Webhooks - Set up real-time payment notifications
- API Reference - Complete API documentation