Integration Guide
This comprehensive guide covers different integration patterns and best practices for implementing InPayCheckout in your application.
Integration Patterns
1. Server-Side Integration
The most secure approach where payment processing happens on your server.
// Server-side payment processing
app.post('/api/payments', async (req, res) => {
try {
const { amount, currency, customer, paymentMethod } = req.body;
const payment = await inpaycheckout.payments.create({
amount,
currency,
customer,
payment_method: paymentMethod,
description: `Payment for order #${req.body.orderId}`
});
res.json({ success: true, paymentId: payment.id });
} catch (error) {
res.status(400).json({ error: error.message });
}
});
2. Client-Side Integration
For better user experience, collect payment details on the client and send to your server.
// Client-side form handling
const form = document.getElementById('payment-form');
form.addEventListener('submit', async (e) => {
e.preventDefault();
const formData = new FormData(form);
const paymentData = {
amount: formData.get('amount'),
currency: formData.get('currency'),
customer: {
email: formData.get('email'),
name: formData.get('name')
},
payment_method: {
type: 'card',
card: {
number: formData.get('cardNumber'),
exp_month: formData.get('expMonth'),
exp_year: formData.get('expYear'),
cvc: formData.get('cvc')
}
}
};
try {
const response = await fetch('/api/payments', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(paymentData)
});
const result = await response.json();
if (result.success) {
// Redirect to success page
window.location.href = '/payment-success';
} else {
// Show error message
showError(result.error);
}
} catch (error) {
showError('Payment failed. Please try again.');
}
});
3. Mobile App Integration
For mobile applications using React Native, Flutter, or native development.
React Native
import InPayCheckout from 'inpaycheckout-react-native';
const PaymentScreen = () => {
const processPayment = async () => {
try {
const payment = await InPayCheckout.createPayment({
amount: 2999,
currency: 'USD',
customer: {
email: 'customer@example.com'
}
});
console.log('Payment successful:', payment.id);
} catch (error) {
console.error('Payment failed:', error);
}
};
return (
<View>
<Button title="Pay Now" onPress={processPayment} />
</View>
);
};
Flutter
import 'package:inpaycheckout_flutter/inpaycheckout_flutter.dart';
class PaymentScreen extends StatefulWidget {
@override
_PaymentScreenState createState() => _PaymentScreenState();
}
class _PaymentScreenState extends State<PaymentScreen> {
Future<void> processPayment() async {
try {
final payment = await InPayCheckout.createPayment(
amount: 2999,
currency: 'USD',
customer: {
'email': 'customer@example.com',
},
);
print('Payment successful: ${payment.id}');
} catch (error) {
print('Payment failed: $error');
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ElevatedButton(
onPressed: processPayment,
child: Text('Pay Now'),
),
),
);
}
}
Payment Flows
1. One-Time Payment
Simple payment for a single purchase.
sequenceDiagram
participant C as Customer
participant F as Frontend
participant B as Backend
participant I as InPayCheckout
C->>F: Enter payment details
F->>B: Send payment request
B->>I: Create payment
I->>B: Return payment result
B->>F: Return success/error
F->>C: Show result
2. Subscription Payment
Recurring payments for subscriptions.
// Create subscription
const subscription = await inpaycheckout.subscriptions.create({
customer: 'cus_1234567890',
price: 'price_1234567890',
payment_method: 'pm_1234567890',
billing_cycle_anchor: Math.floor(Date.now() / 1000) + 30 * 24 * 60 * 60, // 30 days from now
});
// Handle subscription events via webhooks
app.post('/webhook', (req, res) => {
const event = req.body;
switch (event.type) {
case 'subscription.created':
// Handle new subscription
break;
case 'subscription.updated':
// Handle subscription changes
break;
case 'subscription.canceled':
// Handle subscription cancellation
break;
}
});
3. Marketplace Payments
For platforms that facilitate payments between multiple parties.
// Create connected account for seller
const account = await inpaycheckout.accounts.create({
type: 'express',
country: 'US',
email: 'seller@example.com'
});
// Create payment with application fee
const payment = await inpaycheckout.payments.create({
amount: 10000,
currency: 'USD',
customer: 'cus_1234567890',
payment_method: 'pm_1234567890',
application_fee_amount: 300, // 3% fee
transfer_data: {
destination: account.id
}
});
Security Best Practices
1. API Key Security
- Never expose secret keys in client-side code
- Use environment variables for API keys
- Rotate keys regularly
- Use different keys for different environments
// Good: Server-side only
const inpaycheckout = require('inpaycheckout')(process.env.INPAYCHECKOUT_SECRET_KEY);
// Bad: Never do this
const inpaycheckout = require('inpaycheckout')('sk_live_1234567890abcdef');
2. Webhook Security
Always verify webhook signatures to ensure requests are from InPayCheckout.
const crypto = require('crypto');
function verifyWebhookSignature(payload, signature, secret) {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(payload, 'utf8')
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature, 'hex'),
Buffer.from(expectedSignature, 'hex')
);
}
app.post('/webhook', express.raw({type: 'application/json'}), (req, res) => {
const signature = req.headers['inpaycheckout-signature'];
const payload = req.body;
if (!verifyWebhookSignature(payload, signature, process.env.WEBHOOK_SECRET)) {
return res.status(400).send('Invalid signature');
}
// Process webhook
const event = JSON.parse(payload);
// ... handle event
});
3. PCI Compliance
- Never store card details on your servers
- Use tokenization for sensitive data
- Implement proper access controls
- Regular security audits
Error Handling
1. API Errors
Handle different types of API errors appropriately.
try {
const payment = await inpaycheckout.payments.create(paymentData);
} catch (error) {
switch (error.type) {
case 'card_error':
// Card was declined
showError('Your card was declined. Please try a different card.');
break;
case 'validation_error':
// Invalid request parameters
showError('Please check your payment information.');
break;
case 'api_error':
// API error
showError('Payment service temporarily unavailable. Please try again.');
break;
default:
showError('An unexpected error occurred.');
}
}
2. Network Errors
Implement retry logic for network failures.
async function createPaymentWithRetry(paymentData, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await inpaycheckout.payments.create(paymentData);
} catch (error) {
if (error.type === 'api_error' && i < maxRetries - 1) {
// Wait before retry (exponential backoff)
await new Promise(resolve => setTimeout(resolve, Math.pow(2, i) * 1000));
continue;
}
throw error;
}
}
}
Testing
1. Unit Tests
Test your payment integration logic.
// Jest example
describe('Payment Service', () => {
it('should create payment successfully', async () => {
const mockPayment = {
id: 'pay_1234567890',
status: 'succeeded',
amount: 2999
};
// Mock the API call
jest.spyOn(inpaycheckout.payments, 'create').mockResolvedValue(mockPayment);
const result = await paymentService.createPayment({
amount: 2999,
currency: 'USD',
customer: { email: 'test@example.com' }
});
expect(result).toEqual(mockPayment);
});
});
2. Integration Tests
Test the complete payment flow.
describe('Payment Integration', () => {
it('should process payment end-to-end', async () => {
const response = await request(app)
.post('/api/payments')
.send({
amount: 2999,
currency: 'USD',
customer: { email: 'test@example.com' },
payment_method: {
type: 'card',
card: {
number: '4242424242424242',
exp_month: 12,
exp_year: 2025,
cvc: '123'
}
}
})
.expect(200);
expect(response.body.success).toBe(true);
expect(response.body.paymentId).toBeDefined();
});
});
Performance Optimization
1. Caching
Cache frequently accessed data like customer information.
const redis = require('redis');
const client = redis.createClient();
async function getCustomer(customerId) {
// Try cache first
const cached = await client.get(`customer:${customerId}`);
if (cached) {
return JSON.parse(cached);
}
// Fetch from API
const customer = await inpaycheckout.customers.retrieve(customerId);
// Cache for 1 hour
await client.setex(`customer:${customerId}`, 3600, JSON.stringify(customer));
return customer;
}
2. Async Processing
Process non-critical operations asynchronously.
// Process payment synchronously
const payment = await inpaycheckout.payments.create(paymentData);
// Send confirmation email asynchronously
setImmediate(() => {
emailService.sendConfirmation(payment.customer.email, payment.id);
});
// Update analytics asynchronously
setImmediate(() => {
analytics.track('payment_completed', {
paymentId: payment.id,
amount: payment.amount,
currency: payment.currency
});
});
Monitoring and Analytics
1. Payment Metrics
Track key payment metrics.
// Track payment success rate
const trackPaymentSuccess = (payment) => {
analytics.track('payment_success', {
payment_id: payment.id,
amount: payment.amount,
currency: payment.currency,
payment_method: payment.payment_method.type
});
};
// Track payment failures
const trackPaymentFailure = (error) => {
analytics.track('payment_failure', {
error_type: error.type,
error_code: error.code,
error_message: error.message
});
};
2. Real-time Monitoring
Set up alerts for payment issues.
// Webhook for monitoring
app.post('/webhook', (req, res) => {
const event = req.body;
if (event.type === 'payment.failed') {
// Send alert for failed payments
alerting.sendAlert({
type: 'payment_failed',
paymentId: event.data.id,
amount: event.data.amount,
error: event.data.failure_reason
});
}
});
Next Steps
- Webhooks Guide - Advanced webhook handling
- API Reference
- Resources - Addons and integration tools