Accept Payments
Learn how to integrate EPaySe payment processing into your application using the Redirect, Iframe, or Server-to-Server (S2S) integration methods.
Integration Methods
Redirect
Redirect customers to EPaySe's hosted checkout page. Simplest integration with no PCI scope.
Iframe
Embed the checkout form within your page using an iframe. Customers never leave your site.
Server-to-Server
Full control over the checkout UX. Requires PCI DSS SAQ D compliance for handling card data.
Payment Flow
Create Transaction
Your backend calls POST /api/v1/transaction/create with order details
Customer Checkout
Redirect to checkoutUrl or embed the iframe
Payment Processing
EPaySe processes payment through the selected PSP with fraud checks
Result Notification
Customer redirected to your redirectUrl + webhook sent asynchronously
1. Redirect Integration
The simplest way to accept payments. Create a transaction via API, then redirect your customer to the EPaySe hosted checkout page.
API Request
curl -X POST https://api.epayse.com/api/v1/transaction/create \
-H "Content-Type: application/json" \
-H "X-Api-Key-Id: your_api_key" \
-H "X-Signature: generated_hmac_signature" \
-H "X-Timestamp: 1700000000" \
-H "X-Nonce: unique_nonce_value" \
-d '{
"ref": "ORDER-2024-001",
"amount": 1000,
"currency": "USD",
"websiteUrl": "https://yoursite.com",
"redirectUrl": "https://yoursite.com/payment/success",
"cancelUrl": "https://yoursite.com/payment/cancel",
"description": "Payment for Order #001",
"customerDetails": {
"firstName": "John",
"lastName": "Doe",
"email": "[email protected]",
"country": "US",
"ip": "203.0.113.50",
"phoneCode": "US",
"phoneNumber": "5551234567"
}
}'Response
{
"status": "SUCCESS",
"message": "Transaction created successfully",
"data": {
"transactionId": "01kd096yg112e40pcyfwsahyev",
"checkoutUrl": "/checkout/01kd096yg112e40pcyfwsahyev?expires=1766325765&signature=c0108b47..."
}
}PHP Integration Example
<?php
$apiKey = 'your_api_key';
$secretKey = 'your_secret_key';
$timestamp = time();
$nonce = bin2hex(random_bytes(16));
$payload = json_encode([
'ref' => 'ORDER-' . uniqid(),
'amount' => 1000, // Amount in cents ($10.00)
'currency' => 'USD',
'websiteUrl' => 'https://yoursite.com',
'redirectUrl' => 'https://yoursite.com/payment/success',
'cancelUrl' => 'https://yoursite.com/payment/cancel',
'description' => 'Payment for Order #1234',
'customerDetails' => [
'firstName' => 'John',
'lastName' => 'Doe',
'email' => '[email protected]',
'country' => 'US',
'ip' => $_SERVER['REMOTE_ADDR'], // Always use real customer IP
'phoneCode' => 'US',
'phoneNumber' => '5551234567',
],
]);
// Generate HMAC-SHA256 signature
$signatureString = $timestamp . $nonce . $payload;
$signature = hash_hmac('sha256', $signatureString, $secretKey);
$ch = curl_init('https://api.epayse.com/api/v1/transaction/create');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $payload,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'X-Api-Key-Id: ' . $apiKey,
'X-Signature: ' . $signature,
'X-Timestamp: ' . $timestamp,
'X-Nonce: ' . $nonce,
],
CURLOPT_RETURNTRANSFER => true,
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
if ($response['status'] === 'SUCCESS') {
// Redirect customer to EPaySe checkout
header('Location: ' . $response['data']['checkoutUrl']);
exit;
}
// Handle error
echo 'Error: ' . ($response['message'] ?? 'Unknown error');Amount Format: The amount field is in cents for the standard API. For example, 1000 = $10.00 USD. The S2S API uses dollars (e.g., 100.00 = $100.00).
2. Required Parameters
Every transaction requires the following fields:
| Parameter | Type | Description |
|---|---|---|
ref | string | Unique merchant reference (max 250 chars). Acts as idempotency key. |
amount | integer | Amount in cents (min: 1, max: 150000 = $1,500.00) |
currency | string | ISO 4217 currency code (e.g., USD) |
websiteUrl | string | Your website URL (must be registered) |
redirectUrl | string | URL to redirect customer after payment |
cancelUrl | string | URL to redirect customer if they cancel |
description | string | Payment description shown to customer |
customerDetails | object | Customer information (firstName, lastName, email, country, ip, phoneCode, phoneNumber) |
Customer IP is Critical
customerDetails.ip, never your server's IP. This is essential for fraud detection and geographic risk scoring. 3. Iframe Integration
Embed the EPaySe checkout directly within your page. Customers complete payment without leaving your site.
Iframe Response
Use the create-with-iframe endpoint to get embeddable URLs:
{
"status": "SUCCESS",
"message": "Transaction created successfully",
"data": {
"transactionId": "01kd096yg112e40pcyfwsahyev",
"checkoutUrl": "/checkout/01kd096yg112e40pcyfwsahyev?expires=...",
"iframe": {
"fullCheckoutUrl": "https://gateway.epayse.com/checkout/01kd...?expires=...&signature=...",
"fullCheckoutEmbedCode": "<iframe src=\"https://gateway.epayse.com/checkout/...\" />",
"paymentMethods": [
{
"key": "credit_card",
"name": "Credit/Debit Card",
"url": "https://gateway.epayse.com/checkout-field/...",
"embedCode": "<iframe src=\"...\" />"
}
],
"expiresAt": "2024-01-15T15:00:00+00:00",
"configuration": { "width": "100%", "height": "900px" },
"postMessageEvents": [
"epayse:payment:success",
"epayse:payment:failed",
"epayse:payment:cancel",
"epayse:height:change"
]
}
}
}Listen for Iframe Events
Handle payment events from the embedded iframe using postMessage:
// Listen for EPaySe iframe events
window.addEventListener('message', function(event) {
// IMPORTANT: Verify origin for security
const ALLOWED_ORIGINS = [
'https://gateway.epayse.com', // Production
'https://sandbox.epayse.com' // Sandbox
];
if (!ALLOWED_ORIGINS.includes(event.origin)) {
return; // Ignore untrusted origins
}
const { type, data } = event.data;
switch(type) {
case 'epayse:payment:success':
console.log('Payment successful:', data.transactionId);
// Verify payment via webhook or API before fulfilling order
break;
case 'epayse:payment:failed':
console.error('Payment failed:', data.message);
// Show error message to customer
break;
case 'epayse:payment:cancel':
console.log('Payment cancelled:', data.transactionId);
// Redirect to cart or retry
break;
case 'epayse:height:change':
// Dynamically resize iframe
document.getElementById('epayse-checkout')
.style.height = data.height + 'px';
break;
}
});Security: Always verify the event.origin before processing iframe messages. Only trust messages from gateway.epayse.com (production) or sandbox.epayse.com (testing).
4. Payment Status Lifecycle
A transaction progresses through the following statuses:
| Status | Description |
|---|---|
INCOMPLETE | Transaction created, awaiting customer action |
PENDING | Payment submitted, processing at PSP |
AUTHENTICATING | 3D Secure authentication in progress |
SUCCESS | Payment completed successfully |
FAIL | Payment failed (max retries reached) |
CANCEL | Customer cancelled the payment |
EXPIRE | Checkout session expired |
5. Redirect URL Parameters
After payment, the customer is redirected to your redirectUrl with query parameters:
// Redirect URL query parameters after payment
// https://yoursite.com/payment/success?
// status=SUCCESS
// &ref=ORDER-2024-001
// &transactionId=01kd096yg112e40pcyfwsahyev
// &amount=1000
// &paidAmount=1000
// ¤cy=USD
// &message=Payment+successful
// &attemptCount=1
// &maxAttempts=3
// IMPORTANT: Always verify via webhook or API call
// Never trust redirect parameters alone for order fulfillment6. Verify Payment via Webhook
Always verify payment results using webhooks rather than relying on redirect parameters. Webhooks are sent asynchronously after the payment is processed.
<?php
// Receive and verify webhook notification
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_SIGNATURE'] ?? '';
$timestamp = $_SERVER['HTTP_X_TIMESTAMP'] ?? '';
$nonce = $_SERVER['HTTP_X_NONCE'] ?? '';
// Verify timestamp (reject if older than 5 minutes)
if (abs(time() - (int) $timestamp) > 300) {
http_response_code(401);
exit('Timestamp expired');
}
// Verify HMAC signature
$expected = hash_hmac('sha256', $timestamp . $nonce . $payload, $secretKey);
if (!hash_equals($expected, $signature)) {
http_response_code(401);
exit('Invalid signature');
}
$event = json_decode($payload, true);
switch ($event['event']) {
case 'transaction.success':
// Payment confirmed - fulfill the order
updateOrderStatus($event['data']['ref'], 'paid');
break;
case 'transaction.failed':
// Payment failed
updateOrderStatus($event['data']['ref'], 'failed');
break;
}
// Always return 200 to acknowledge receipt
http_response_code(200);
echo json_encode(['received' => true]);Best Practice
7. Testing
Use sandbox test cards to test your integration:
| Card Number | Result | Use Case |
|---|---|---|
4111 1111 1111 1111 | Success | Successful payment |
4000 0000 0000 0002 | Decline | Card declined |
4000 0000 0000 0119 | 3DS | 3D Secure required |
Use any future expiry date and any 3-digit CVV for testing.
8. Common Mistakes
Use your server IP instead of the customer's real IP address
Trust redirect URL parameters as proof of payment
Send amount as decimal in the standard API (use cents: 1000 not 10.00)
Always verify payment via webhooks before fulfilling orders
Use unique ref values for each transaction (idempotency key)
Verify iframe event.origin before processing PostMessage events
Next Steps
Explore related documentation to complete your integration.
