API Integration Best Practices for Payment Systems
Building secure, reliable payment integrations requires careful attention to best practices. This guide covers everything you need to know.
Authentication & Security
API Key Management
Never expose API keys in client-side code:
javascript
// ❌ DON'T: Client-side API key exposure
const response = await fetch('/api/pay', {
headers: {
'Authorization': 'Bearer sk_live_xxx' // EXPOSED!
}
});
// ✅ DO: Server-side API calls
// pages/api/create-payment.ts
export default async function handler(req, res) {
const payment = await lumexpay.payments.create({
amount: req.body.amount,
currency: 'USD'
});
res.json({ clientSecret: payment.clientSecret });
}Webhook Verification
Always verify webhook signatures:
typescript
import { headers } from 'next/headers';
import { lumexpay } from '@/lib/lumexpay';
export async function POST(req: Request) {
const body = await req.text();
const signature = headers().get('lumexpay-signature');
try {
const event = lumexpay.webhooks.verify(
body,
signature,
process.env.WEBHOOK_SECRET
);
// Handle verified event
switch (event.type) {
case 'payment.completed':
await handlePaymentComplete(event.data);
break;
case 'payment.failed':
await handlePaymentFailed(event.data);
break;
}
return Response.json({ received: true });
} catch (err) {
return Response.json({ error: 'Invalid signature' }, { status: 400 });
}
}Error Handling
Implement Proper Error Handling
typescript
interface PaymentError {
code: string;
message: string;
decline_code?: string;
param?: string;
}
async function createPayment(amount: number) {
try {
const payment = await lumexpay.payments.create({ amount });
return { success: true, payment };
} catch (error) {
if (error.code === 'card_declined') {
return {
success: false,
error: 'Your card was declined. Please try another card.',
recoverable: true
};
}
if (error.code === 'insufficient_funds') {
return {
success: false,
error: 'Insufficient funds. Please try a different payment method.',
recoverable: true
};
}
// Log unexpected errors
console.error('Payment error:', error);
return {
success: false,
error: 'An unexpected error occurred.',
recoverable: false
};
}
}Idempotency
Prevent Duplicate Charges
Always use idempotency keys for payment creation:
typescript
const idempotencyKey = `order_${orderId}_${Date.now()}`;
const payment = await lumexpay.payments.create({
amount: 2000,
currency: 'USD',
metadata: { orderId }
}, {
idempotencyKey
});Testing
Use Test Mode Effectively
typescript
// Test card numbers
const testCards = {
success: '4242424242424242',
decline: '4000000000000002',
insufficientFunds: '4000000000009995',
expired: '4000000000000069',
processingError: '4000000000000119'
};
// Test with different scenarios
describe('Payment Integration', () => {
it('handles successful payment', async () => {
const result = await processPayment(testCards.success);
expect(result.status).toBe('succeeded');
});
it('handles card decline gracefully', async () => {
const result = await processPayment(testCards.decline);
expect(result.error).toBeDefined();
expect(result.recoverable).toBe(true);
});
});Performance Optimization
Connection Pooling
typescript
// Initialize client once
const lumexpay = new LumexpayClient({
apiKey: process.env.LUMEXPAY_SECRET_KEY,
maxNetworkRetries: 2,
timeout: 30000
});
export { lumexpay };Async Operations
Use webhooks instead of polling:
typescript
// ❌ DON'T: Poll for status
while (payment.status === 'processing') {
await sleep(1000);
payment = await lumexpay.payments.retrieve(paymentId);
}
// ✅ DO: Use webhooks
// The webhook will notify you when status changesCheck out our API documentation for more detailed integration guides.
#API#integration#security#webhooks#best practices
Alex Chen
Senior Developer Advocate
Writing about payments, fintech, and the future of global commerce. Follow for insights on industry trends and technical deep-dives.


