TL;DR
The iPay API enables developers to integrate payment processing, invoicing, and financial transactions programmatically. It uses OAuth 2.0 and API key authentication, RESTful endpoints for payments, refunds, transactions, and reconciliation, with PCI DSS compliance requirements and industry-standard rate limits. This guide covers authentication setup, payment processing, webhook integration, security compliance, and production deployment strategies.
Introduction
Digital payment processing handles over $8 trillion annually worldwide. For developers building e-commerce platforms, SaaS applications, or marketplace solutions, payment API integration isn’t optional—it’s essential for accepting customer payments securely and compliantly.
Here’s the reality: businesses lose 5-10% of revenue to failed payments, manual reconciliation, and payment fraud. A solid payment API integration automates payment processing, reduces failures with smart retry logic, enables automatic reconciliation, and implements fraud detection.
This guide walks through the complete payment API integration process. You’ll learn authentication setup, payment processing, refund management, webhook handling, PCI DSS compliance, security best practices, and production deployment strategies. By the end, you’ll have a production-ready payment integration.
Note: This guide covers general payment API integration patterns applicable to iPay and similar payment processors. Specific endpoint URLs and authentication details may vary—always refer to official iPay documentation for implementation details.
What Is the iPay API?
Payment APIs like iPay provide RESTful interfaces for processing financial transactions. The API handles:
- Payment authorization and capture
- Refunds and chargebacks
- Transaction history and reporting
- Customer tokenization (vault)
- Subscription and recurring billing
- Invoice generation and management
- Reconciliation and settlement
- Fraud detection and prevention
Key Features
| Feature | Description |
|---|---|
| RESTful API | JSON-based endpoints |
| OAuth 2.0 + API Keys | Secure authentication |
| Webhooks | Real-time payment notifications |
| Tokenization | Secure card storage |
| 3D Secure | SCA compliance |
| PCI DSS | Level 1 compliance required |
| Multi-Currency | 100+ currencies supported |
| Fraud Tools | Risk scoring, velocity checks |
Payment Flow Overview
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Customer │───▶│ Merchant │───▶│ Payment │
│ (Browser) │ │ (Server) │ │ Gateway │
└─────────────┘ └─────────────┘ └─────────────┘
│ │ │
│ 1. Enter Card │ │
│───────────────────▶│ │
│ │ │
│ 2. Tokenize │ │
│───────────────────▶│ 3. Create Intent │
│ │───────────────────▶│
│ │ │
│ │ 4. Confirm Payment│
│ │───────────────────▶│
│ │ │
│ │ 5. Result │
│ │◀───────────────────│
│ │ │
│ 6. Receipt │ │
│◀───────────────────│ │
API Environment
| Environment | URL | Use Case |
|---|---|---|
| Sandbox | https://sandbox.ipay.com/api |
Development, testing |
| Production | https://api.ipay.com/api |
Live transactions |
Getting Started: Authentication Setup
Step 1: Create iPay Account
Before accessing the API:
- Visit iPay merchant registration
- Complete business verification (KYB)
- Submit required documents:
- Business registration
- Bank account details
- Government ID
- Wait for approval (1-3 business days)
Step 2: Get API Credentials
Generate API credentials:
- Log in to iPay Merchant Dashboard
- Navigate to Settings > API Keys
- Create new API key
- Copy credentials securely
# .env file (NEVER commit to git)
IPAY_API_KEY="live_xxxxxxxxxxxxxxxxxxxx"
IPAY_API_SECRET="secret_xxxxxxxxxxxxxxxxxxxx"
IPAY_WEBHOOK_SECRET="whsec_xxxxxxxxxxxxxxxxxxxx"
Security note: Use separate keys for sandbox and production.
Step 3: Understand Authentication Methods
iPay supports multiple authentication methods:
| Method | Best For | Security Level |
|---|---|---|
| Basic Auth | Server-to-server | High |
| OAuth 2.0 | Multi-tenant apps | Higher |
| JWT | Microservices | High |
Step 4: Make Authenticated API Calls
Create reusable API client:
const IPAY_BASE_URL = process.env.IPAY_SANDBOX
? 'https://sandbox.ipay.com/api'
: 'https://api.ipay.com/api';
const ipayRequest = async (endpoint, options = {}) => {
const apiKey = process.env.IPAY_API_KEY;
const apiSecret = process.env.IPAY_API_SECRET;
// Basic authentication (Base64 encoded)
const authHeader = Buffer.from(`${apiKey}:${apiSecret}`).toString('base64');
const response = await fetch(`${IPAY_BASE_URL}${endpoint}`, {
...options,
headers: {
'Authorization': `Basic ${authHeader}`,
'Content-Type': 'application/json',
'Idempotency-Key': options.idempotencyKey || generateIdempotencyKey(),
...options.headers
}
});
if (!response.ok) {
const error = await response.json();
throw new Error(`iPay API Error: ${error.message}`);
}
return response.json();
};
function generateIdempotencyKey() {
return `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}
// Usage
const account = await ipayRequest('/account');
console.log(`Merchant: ${account.business_name}`);
Payment Processing
Creating a Payment Intent
Initialize payment:
const createPayment = async (paymentData) => {
const payment = {
amount: paymentData.amount, // In smallest currency unit (cents)
currency: paymentData.currency || 'USD',
customer: paymentData.customerId,
payment_method: paymentData.paymentMethodId,
confirm: true,
description: paymentData.description,
metadata: {
orderId: paymentData.orderId,
customerId: paymentData.customerId
},
capture_method: paymentData.captureMethod || 'automatic', // 'automatic' or 'manual'
statement_descriptor: paymentData.statementDescriptor || 'MYCOMPANY'
};
const response = await ipayRequest('/payments', {
method: 'POST',
body: JSON.stringify(payment),
idempotencyKey: paymentData.idempotencyKey
});
return response;
};
// Usage
const payment = await createPayment({
amount: 2999, // $29.99
currency: 'USD',
customerId: 'cus_12345',
paymentMethodId: 'pm_67890',
description: 'Order #ORD-001',
orderId: 'ORD-001',
statementDescriptor: 'MYCOMPANY INC'
});
console.log(`Payment status: ${payment.status}`);
console.log(`Payment ID: ${payment.id}`);
Payment Status Flow
requires_payment_method → requires_confirmation → requires_action
→ processing → requires_capture → succeeded
→ failed
→ canceled
Payment Methods
| Method | Type | Use Case |
|---|---|---|
card |
Credit/Debit | Standard payments |
bank_transfer |
ACH, SEPA | Low-fee transfers |
digital_wallet |
Apple Pay, Google Pay | Mobile checkout |
buy_now_pay_later |
Klarna, Afterpay | Installment payments |
Tokenizing Card Details
Securely store card for future use:
const tokenizeCard = async (cardData) => {
// NEVER send raw card data to your server
// Use client-side tokenization instead
// Client-side (browser/mobile)
const response = await fetch(`${IPAY_BASE_URL}/tokens`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${CLIENT_PUBLISHABLE_KEY}`
},
body: JSON.stringify({
card: {
number: cardData.number,
exp_month: cardData.expMonth,
exp_year: cardData.expYear,
cvc: cardData.cvc
}
})
});
const token = await response.json();
return token; // Send token.id to your server
};
// Server-side: Use token to create payment method
const createPaymentMethod = async (tokenId, customerId) => {
const response = await ipayRequest('/payment_methods', {
method: 'POST',
body: JSON.stringify({
type: 'card',
token: tokenId,
customer: customerId
})
});
return response;
};
3D Secure Authentication
Implement SCA compliance:
const createPaymentWith3DS = async (paymentData) => {
const payment = await createPayment({
...paymentData,
confirmation_token: true // Return client secret for 3DS
});
if (payment.status === 'requires_action') {
// Client must complete 3DS challenge
return {
requiresAction: true,
clientSecret: payment.client_secret,
nextAction: payment.next_action
};
}
return { success: true, payment };
};
// Client-side: Handle 3DS challenge
// Use iPay.js or mobile SDK to present authentication challenge
Refund Management
Processing Full Refund
Refund entire payment:
const refundPayment = async (paymentId, reason = null) => {
const refund = {
payment: paymentId,
reason: reason || 'requested_by_customer'
};
const response = await ipayRequest('/refunds', {
method: 'POST',
body: JSON.stringify(refund),
idempotencyKey: `refund_${paymentId}_${Date.now()}`
});
return response;
};
// Usage
const refund = await refundPayment('pay_12345', 'duplicate');
console.log(`Refund status: ${refund.status}`);
console.log(`Refund ID: ${refund.id}`);
Processing Partial Refund
Refund portion of payment:
const partialRefund = async (paymentId, amount, reason = null) => {
const refund = {
payment: paymentId,
amount: amount, // In smallest currency unit
reason: reason || 'requested_by_customer'
};
const response = await ipayRequest('/refunds', {
method: 'POST',
body: JSON.stringify(refund),
idempotencyKey: `refund_${paymentId}_${amount}_${Date.now()}`
});
return response;
};
// Usage - Refund $15.00 of $29.99 payment
const refund = await partialRefund('pay_12345', 1500, 'partial_ship');
console.log(`Refunded: $${refund.amount / 100}`);
Refund Reasons
| Reason Code | Description |
|---|---|
duplicate |
Duplicate charge |
fraudulent |
Fraudulent transaction |
requested_by_customer |
Customer request |
order_canceled |
Order cancellation |
product_not_received |
Item not delivered |
product_not_as_described |
Item differs from description |
Customer Management
Creating a Customer
Store customer for recurring payments:
const createCustomer = async (customerData) => {
const customer = {
email: customerData.email,
name: customerData.name,
phone: customerData.phone,
metadata: {
internalId: customerData.internalId,
tier: customerData.tier
}
};
const response = await ipayRequest('/customers', {
method: 'POST',
body: JSON.stringify(customer)
});
return response;
};
// Usage
const customer = await createCustomer({
email: 'customer@example.com',
name: 'John Doe',
phone: '+1-555-0123',
internalId: 'USR-12345',
tier: 'premium'
});
console.log(`Customer created: ${customer.id}`);
Attaching Payment Method to Customer
Save card for future use:
const attachPaymentMethod = async (paymentMethodId, customerId) => {
const response = await ipayRequest(`/payment_methods/${paymentMethodId}/attach`, {
method: 'POST',
body: JSON.stringify({
customer: customerId
})
});
return response;
};
// Usage
await attachPaymentMethod('pm_67890', 'cus_12345');
Listing Customer Payment Methods
Get saved cards:
const getCustomerPaymentMethods = async (customerId) => {
const response = await ipayRequest(`/customers/${customerId}/payment_methods`);
return response;
};
// Usage
const methods = await getCustomerPaymentMethods('cus_12345');
methods.data.forEach(method => {
console.log(`${method.card.brand} ending in ${method.card.last4}`);
console.log(`Expires: ${method.card.exp_month}/${method.card.exp_year}`);
});
Webhooks
Configuring Webhooks
Set up webhook endpoints:
- Log in to iPay Dashboard
- Navigate to Developers > Webhooks
- Click Add Endpoint
- Enter your HTTPS URL
- Select events to subscribe
Webhook Events
| Event | Trigger |
|---|---|
payment.succeeded |
Payment completed |
payment.failed |
Payment declined |
payment.refunded |
Refund processed |
payment.disputed |
Chargeback filed |
customer.created |
New customer |
customer.subscription.updated |
Subscription changed |
Handling Webhooks
const express = require('express');
const crypto = require('crypto');
const app = express();
app.post('/webhooks/ipay', express.raw({ type: 'application/json' }), async (req, res) => {
const signature = req.headers['ipay-signature'];
const payload = req.body;
// Verify webhook signature
const isValid = verifyWebhookSignature(payload, signature, process.env.IPAY_WEBHOOK_SECRET);
if (!isValid) {
console.error('Invalid webhook signature');
return res.status(401).send('Unauthorized');
}
const event = JSON.parse(payload.toString());
// Route to appropriate handler
switch (event.type) {
case 'payment.succeeded':
await handlePaymentSucceeded(event.data);
break;
case 'payment.failed':
await handlePaymentFailed(event.data);
break;
case 'payment.refunded':
await handlePaymentRefunded(event.data);
break;
case 'payment.disputed':
await handlePaymentDisputed(event.data);
break;
default:
console.log('Unhandled event type:', event.type);
}
// Acknowledge receipt
res.status(200).send('OK');
});
function verifyWebhookSignature(payload, signature, secret) {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature, 'hex'),
Buffer.from(expectedSignature, 'hex')
);
}
async function handlePaymentSucceeded(data) {
console.log(`Payment succeeded: ${data.id}`);
// Update order status
await db.orders.update(data.metadata.orderId, {
status: 'paid',
paymentId: data.id,
paidAt: new Date()
});
// Send confirmation email
await sendOrderConfirmation(data.metadata.orderId);
}
async function handlePaymentFailed(data) {
console.log(`Payment failed: ${data.id} - ${data.failure_code}`);
// Notify customer
await sendPaymentFailedEmail(data.customer, data.failure_message);
// Retry logic or mark order as failed
await db.orders.update(data.metadata.orderId, {
status: 'payment_failed',
failureReason: data.failure_message
});
}
Security and Compliance
PCI DSS Requirements
Payment integrations must comply with PCI DSS:
| Requirement | Implementation |
|---|---|
| Secure Network | Use HTTPS, firewalls, secure configurations |
| Cardholder Data Protection | Never store CVV, encrypt PAN |
| Vulnerability Management | Regular security updates, anti-virus |
| Access Control | Least privilege, MFA, unique IDs |
| Monitoring | Logging, intrusion detection |
| Security Policy | Documented policies, regular training |
Security Best Practices
// 1. Use tokenization - NEVER handle raw card data
const token = await tokenizeCard(cardData); // Client-side
// 2. Implement idempotency for all payment operations
const idempotencyKey = `pay_${orderId}_${Date.now()}`;
// 3. Validate amounts server-side
if (req.body.amount !== calculatedAmount) {
throw new Error('Amount mismatch - possible tampering');
}
// 4. Log all payment operations (without sensitive data)
logger.info('Payment attempted', {
orderId,
amount,
currency,
customerId,
timestamp: new Date().toISOString()
// NEVER log: card numbers, CVV, full payment method details
});
// 5. Use environment variables for secrets
const apiKey = process.env.IPAY_API_KEY; // Not hardcoded
// 6. Implement rate limiting on payment endpoints
const paymentLimiter = rateLimit({
windowMs: 60000,
max: 10 // 10 payment attempts per minute
});
Production Deployment Checklist
Before processing live payments:
- [ ] Complete PCI DSS Self-Assessment Questionnaire
- [ ] Use HTTPS for all endpoints
- [ ] Store API keys in secure secret management
- [ ] Implement webhook signature verification
- [ ] Add idempotency for all payment operations
- [ ] Set up comprehensive logging (no sensitive data)
- [ ] Configure fraud detection rules
- [ ] Test refund and dispute flows
- [ ] Create runbook for payment failures
- [ ] Set up monitoring and alerting
- [ ] Implement backup payment processor
Real-World Use Cases
E-commerce Checkout
An online retailer integrates payments:
- Challenge: Manual payment processing, high abandonment
- Solution: One-page checkout with tokenized cards
- Result: 35% conversion increase, instant payments
SaaS Subscription Billing
A software company automates billing:
- Challenge: Manual invoice generation and collection
- Solution: Recurring payments with automatic retry
- Result: 95% on-time payment, 80% admin time savings
Marketplace Escrow
A platform handles multi-party payments:
- Challenge: Complex split payments between vendors
- Solution: Payment intents with transfer scheduling
- Result: Automated vendor payouts, reduced fraud
Conclusion
Payment API integration requires careful attention to security, compliance, and error handling. Key takeaways:
- Never handle raw card data—use tokenization
- Implement idempotency for all payment operations
- Verify webhook signatures to prevent fraud
- Comply with PCI DSS requirements
- Test thoroughly in sandbox before production
- Apidog streamlines API testing and team collaboration
FAQ Section
How do I authenticate with iPay API?
Use Basic authentication with API key and secret, or OAuth 2.0 for multi-tenant applications.
Can I store customer card details?
Yes, but you must be PCI DSS compliant. Use tokenization to store cards securely in iPay’s vault.
How do I handle failed payments?
Implement retry logic with exponential backoff, notify customers, and provide alternative payment methods.
What is idempotency and why is it important?
Idempotency ensures duplicate requests with same key produce same result, preventing duplicate charges.
How do I test payments without charging cards?
Use sandbox mode with test card numbers provided in iPay documentation.
What are webhook signatures?
Cryptographic signatures that verify webhooks came from iPay, not a malicious actor.



