Skip to content

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.

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);
}
// Usage
const 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);

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);
}
// Usage
const 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);

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;
}
}
// Usage
const orderStatus = await trackOrderPaymentStatus('ORD-123');
console.log('Order payment status:', orderStatus);

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);
}
// Usage
const 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);

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;
}
}
// Usage
const subscriptionData = await trackSubscriptionRenewals('CUST-123');
console.log('Subscription data:', subscriptionData);

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);
}
// Usage
const 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);

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);
}
// Usage
const 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);

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 endpoint
app.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' });
}
});

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;
}

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')}`;
}
// Usage
const startDate = new Date('2024-01-01');
const endDate = new Date('2024-01-31');
const analytics = await generatePaymentAnalytics(startDate, endDate);
console.log('Payment analytics:', analytics);

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;
}
}
// Usage
const customerHistory = await getCustomerPaymentHistory('CUST-123');
console.log('Customer payment history:', customerHistory);

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;
}
}

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);
}

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;
}

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;
}
}

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');
});
});

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);
});
});