TL;DR
The iPay API allows developers to automate payment processing, invoicing, and financial transactions via RESTful endpoints. It supports OAuth 2.0 and API key authentication, includes endpoints for payments, refunds, and reconciliation, and enforces PCI DSS compliance and industry rate limits. This actionable guide covers authentication, payments, webhooks, security, and deployment for production-grade payment integration.
Introduction
Digital payments now exceed $8 trillion annually. If youβre building e-commerce, SaaS, or marketplace apps, integrating a payment API is mandatory for secure, compliant customer transactions.
Businesses lose 5-10% of revenue to failed payments, manual reconciliation, and fraud. A robust payment API automation reduces failures (with retry logic), automates reconciliation, and adds fraud detection.
This guide walks you through practical payment API integration: authentication, processing payments, handling refunds, working with webhooks, enforcing PCI DSS, and deploying to production. By the end, you'll have a blueprint for production-ready payment integration.
π‘Apidog simplifies payment API testing. Test payment endpoints in sandbox mode, validate webhook signatures, inspect transaction responses, and debug integration issues in one workspace. Import API specifications, mock responses, and share test scenarios with your team.
Note: This guide covers general payment API integration patterns for iPay and similar processors. Always consult official iPay docs for endpoint and authentication specifics.
What Is the iPay API?
iPay offers RESTful APIs for payment processing and financial operations. Key capabilities include:
- Payment authorization/capture
- Refunds and chargebacks
- Transaction history/reporting
- Customer tokenization (vault)
- Subscriptions and recurring billing
- Invoice management
- Reconciliation/settlement
- Fraud detection
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
- Register via iPay merchant portal.
- Complete KYB (business verification).
- Submit required docs:
- Business registration
- Bank account details
- Government ID
- Wait 1-3 business days for approval.
Step 2: Get API Credentials
- Log in to iPay Merchant Dashboard.
- Go to Settings > API Keys.
- Generate a new API key.
- Store credentials securely.
# .env file (NEVER commit to git)
IPAY_API_KEY="live_xxxxxxxxxxxxxxxxxxxx"
IPAY_API_SECRET="secret_xxxxxxxxxxxxxxxxxxxx"
IPAY_WEBHOOK_SECRET="whsec_xxxxxxxxxxxxxxxxxxxx"
Security: Use separate keys for sandbox and production.
Step 3: Understand 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 a 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;
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
const createPayment = async (paymentData) => {
const payment = {
amount: paymentData.amount, // in 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',
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
Always tokenize cards client-side:
const tokenizeCard = async (cardData) => {
// Client-side only
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 server
};
// Server-side: attach token
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:
const createPaymentWith3DS = async (paymentData) => {
const payment = await createPayment({
...paymentData,
confirmation_token: true // Return client secret for 3DS
});
if (payment.status === 'requires_action') {
return {
requiresAction: true,
clientSecret: payment.client_secret,
nextAction: payment.next_action
};
}
return { success: true, payment };
};
// Client-side: use iPay.js or SDK to complete challenge
Refund Management
Processing Full Refund
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
const partialRefund = async (paymentId, amount, reason = null) => {
const refund = {
payment: paymentId,
amount: amount, // cents
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 of $29.99
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
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
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
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
- Log in to iPay Dashboard.
- Go to Developers > Webhooks.
- Click Add Endpoint.
- Enter your HTTPS URL.
- Select events to subscribe to.
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());
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);
}
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}`);
await db.orders.update(data.metadata.orderId, {
status: 'paid',
paymentId: data.id,
paidAt: new Date()
});
await sendOrderConfirmation(data.metadata.orderId);
}
async function handlePaymentFailed(data) {
console.log(`Payment failed: ${data.id} - ${data.failure_code}`);
await sendPaymentFailedEmail(data.customer, data.failure_message);
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 going live:
- [ ] 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
- Challenge: Manual payment processing, high cart abandonment
- Solution: One-page checkout, tokenized cards
- Result: 35% higher conversion, instant payments
SaaS Subscription Billing
- Challenge: Manual invoicing, collections
- Solution: Recurring payments, automatic retries
- Result: 95% on-time payment, 80% admin time saved
Marketplace Escrow
- Challenge: Complex vendor split payments
- Solution: Payment intents with scheduled transfers
- Result: Automated payouts, reduced fraud
Conclusion
Integrate payment APIs with these best practices:
- Never handle raw card dataβuse tokenization
- Use idempotency for all payment operations
- Verify webhook signatures
- Enforce PCI DSS compliance
- Test thoroughly in sandbox before launch
- Apidog streamlines API testing and collaboration
FAQ Section
How do I authenticate with iPay API?
Use Basic authentication (API key + secret) or OAuth 2.0 for multi-tenant apps.
Can I store customer card details?
Yes, but only with PCI DSS compliance. Use tokenization and iPayβs vault.
How do I handle failed payments?
Implement retries with exponential backoff, notify customers, and offer alternate payment methods.
What is idempotency and why is it important?
Idempotency ensures duplicate requests with the same key produce the same result, preventing double charges.
How do I test payments without charging cards?
Use sandbox mode and test card numbers from iPay documentation.
What are webhook signatures?
Cryptographic signatures that prove webhooks are from iPay, not attackers.
Top comments (0)