Payment Gateway API Documentation
Complete integration guide for our Payment Gateway API supporting secure payment processing with full 3D Secure authentication.
Key Features
- Full 3D Secure (3DS) authentication support
- Automatic payment method selection
- Flexible address handling
- Real-time transaction status
- Secure API authentication
- Multi-currency support
Authentication
All API requests must include your API credentials in the request headers:
X-Api-Key: your_api_key_here
X-Api-Secret: your_api_secret_here
Content-Type: application/json
Payment Processing
Our gateway automatically handles payment method selection and routing based on your account configuration. You don't need to specify payment providers - the system will use the optimal method for each transaction.
Feature | Support | Description |
---|---|---|
Credit Cards | ✅ All Major Cards | Visa, Mastercard, American Express, Discover |
3D Secure | ✅ Full 3DS2 | Automatic fraud protection and authentication |
Multi-Currency | ✅ Global Support | USD, EUR, GBP, CAD, AUD, JPY, SGD and more |
Tokenization | ✅ Secure Storage | PCI-compliant card tokenization |
Address Handling
Proper billing address information is crucial for payment processing and 3DS authentication. The API supports flexible address formats:
Single String Format (Recommended)
{
"billing_address": "123 Main Street, New York, NY, 10001, US"
}
Individual Components Format
{
"address_line": "123 Main Street",
"city": "New York",
"state": "NY",
"postal_code": "10001",
"country": "US"
}
Address Requirements
Component | Required | Description |
---|---|---|
Street Address | Required | Full street address including number and street name |
City | Required | City or locality name |
State/Province | Optional | State, province, or administrative area |
Postal Code | Optional | ZIP/postal code (recommended for better approval rates) |
Country | Required | 2-letter ISO country code (US, GB, CA, etc.) |
Initialize Payment
Create a new payment transaction. The system automatically selects the optimal payment method based on your account configuration.
Endpoint:
POST https://gateway.pesogate.com/api/v1/payments/initialize
Parameters:
Parameter | Type | Required | Description |
---|---|---|---|
order_id | string | Required | Your unique order identifier |
amount | decimal | Required | Payment amount (e.g., 100.50) |
currency | string | Required | 3-letter currency code (USD, EUR, GBP) |
card_number | string | Required* | Card number (16-19 digits) |
exp_month | string | Required* | Expiration month (01-12) |
exp_year | string | Required* | Expiration year (YY or YYYY) |
cvv | string | Required* | Card verification value (3-4 digits) |
payment_source_token | string | Optional** | Previously tokenized payment source |
customer_name | string | Optional | Cardholder name |
customer_email | string | Optional | Customer email address |
billing_address | string | Required | Complete billing address (see Address Handling section) |
return_url | string | Required | URL for successful payment redirect |
cancel_url | string | Required | URL for cancelled/failed payment redirect |
* Required when using direct card payment
** Use payment_source_token OR card details, not both
Example Request:
curl -X POST "https://gateway.pesogate.com/api/v1/payments/initialize" \
-H "Content-Type: application/json" \
-H "X-Api-Key: your_api_key" \
-H "X-Api-Secret: your_api_secret" \
-d '{
"order_id": "ORDER123456",
"amount": 100.50,
"currency": "USD",
"card_number": "4111111111111111",
"exp_month": "12",
"exp_year": "25",
"cvv": "123",
"customer_name": "John Doe",
"customer_email": "john.doe@example.com",
"billing_address": "123 Main Street, New York, NY, 10001, US",
"return_url": "https://your-website.com/payment/success",
"cancel_url": "https://your-website.com/payment/cancel"
}'
Response Types:
1. Standard Redirect Response:
{
"success": true,
"action": "redirect",
"message": "Transaction initialized successfully",
"redirect_url": "https://checkout.gateway.com/pay/abc123def456",
"transaction_reference": "550e8400-e29b-41d4-a716-446655440000"
}
2. 3DS Challenge Response:
{
"success": true,
"action": "render_3ds_fullscreen",
"html_content": "<html>...3DS challenge form...</html>",
"message": "Secure authentication required",
"transaction_reference": "550e8400-e29b-41d4-a716-446655440000"
}
3. Error Response:
{
"success": false,
"message": "Validation failed",
"errors": {
"billing_address": ["Street address is required"],
"card_number": ["Invalid card number"]
},
"error_code": "VALIDATION_ERROR"
}
3DS Challenge Implementation
When the API returns action: "render_3ds_fullscreen"
, you must render the 3DS
authentication challenge. Here's how to implement it properly:
PHP Implementation
<?php
function handlePaymentResponse($apiResponse) {
$result = json_decode($apiResponse, true);
if ($result['success'] && isset($result['action'])) {
switch ($result['action']) {
case 'render_3ds_fullscreen':
render3DSChallenge($result['html_content'], $result['transaction_reference']);
break;
case 'redirect':
header("Location: " . $result['redirect_url']);
exit;
}
} else {
// Handle error
handlePaymentError($result);
}
}
function render3DSChallenge($htmlContent, $transactionRef) {
// Store transaction reference for callback handling
$_SESSION['transaction_reference'] = $transactionRef;
// Clean and validate HTML content
$cleanHtml = html_entity_decode($htmlContent, ENT_QUOTES | ENT_HTML5, 'UTF-8');
echo '<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Secure Payment Authentication</title>
<style>
body {
margin: 0;
padding: 20px;
font-family: Arial, sans-serif;
background: #f5f5f5;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
.auth-container {
background: white;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
padding: 20px;
max-width: 500px;
width: 100%;
}
.auth-frame {
width: 100%;
min-height: 400px;
border: none;
border-radius: 4px;
}
.loading {
text-align: center;
color: #666;
padding: 20px;
}
</style>
</head>
<body>
<div class="auth-container">
<div class="loading" id="loading">
<p>Loading secure authentication...</p>
</div>
<iframe
id="auth-frame"
class="auth-frame"
style="display: none;"
sandbox="allow-forms allow-scripts allow-same-origin allow-top-navigation"
onload="document.getElementById(\'loading\').style.display=\'none\'; this.style.display=\'block\';"
></iframe>
</div>
<script>
const iframe = document.getElementById("auth-frame");
const htmlContent = ' . json_encode($cleanHtml) . ';
// Create blob URL for secure content loading
const blob = new Blob([htmlContent], { type: "text/html" });
const url = URL.createObjectURL(blob);
iframe.src = url;
// Clean up blob URL after loading
iframe.onload = function() {
setTimeout(() => URL.revokeObjectURL(url), 1000);
};
</script>
</body>
</html>';
exit;
}
?>
JavaScript/AJAX Implementation
async function initializePayment(paymentData) {
try {
const response = await fetch('/api/v1/payments/initialize', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Api-Key': 'your_api_key',
'X-Api-Secret': 'your_api_secret'
},
body: JSON.stringify(paymentData)
});
const result = await response.json();
if (result.success) {
switch (result.action) {
case 'render_3ds_fullscreen':
render3DSModal(result.html_content, result.transaction_reference);
break;
case 'redirect':
window.location.href = result.redirect_url;
break;
}
} else {
handlePaymentError(result);
}
} catch (error) {
console.error('Payment initialization failed:', error);
showErrorMessage('Network error occurred. Please try again.');
}
}
function render3DSModal(htmlContent, transactionRef) {
// Create modal overlay
const modal = document.createElement('div');
modal.id = 'threeds-modal';
modal.style.cssText = `
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.8);
display: flex;
justify-content: center;
align-items: center;
z-index: 10000;
`;
// Create container
const container = document.createElement('div');
container.style.cssText = `
background: white;
border-radius: 8px;
padding: 20px;
max-width: 500px;
width: 90%;
max-height: 80vh;
overflow: hidden;
position: relative;
`;
// Create close button
const closeBtn = document.createElement('button');
closeBtn.innerHTML = '×';
closeBtn.style.cssText = `
position: absolute;
top: 10px;
right: 15px;
background: none;
border: none;
font-size: 24px;
cursor: pointer;
color: #666;
`;
closeBtn.onclick = () => {
document.body.removeChild(modal);
// Optionally redirect to cancel URL
window.location.href = paymentData.cancel_url;
};
// Create iframe for 3DS challenge
const iframe = document.createElement('iframe');
iframe.style.cssText = `
width: 100%;
height: 400px;
border: none;
border-radius: 4px;
`;
iframe.sandbox = 'allow-forms allow-scripts allow-same-origin allow-top-navigation';
// Store transaction reference for callback handling
sessionStorage.setItem('transaction_reference', transactionRef);
// Inject HTML content securely
const blob = new Blob([htmlContent], { type: 'text/html' });
const url = URL.createObjectURL(blob);
iframe.src = url;
container.appendChild(closeBtn);
container.appendChild(iframe);
modal.appendChild(container);
document.body.appendChild(modal);
// Clean up after iframe loads
iframe.onload = () => {
setTimeout(() => URL.revokeObjectURL(url), 1000);
};
// Listen for completion messages (optional)
window.addEventListener('message', function(event) {
if (event.data.type === '3ds_complete') {
document.body.removeChild(modal);
// Check transaction status or redirect
checkTransactionStatus(transactionRef);
}
});
}
- Always use iframe sandbox attributes for security
- Implement proper loading states for better UX
- Store transaction reference for status checking
- Provide clear error handling and retry options
- Test with both challenge and frictionless flows
Check Transaction Status
Retrieve the current status and details of a transaction.
Endpoint:
GET https://gateway.pesogate.com/api/v1/payments/{reference}/status
Example Request:
curl -X GET "https://gateway.pesogate.com/api/v1/payments/550e8400-e29b-41d4-a716-446655440000/status" \
-H "X-Api-Key: your_api_key" \
-H "X-Api-Secret: your_api_secret"
Response:
{
"success": true,
"message": "Transaction status retrieved",
"data": {
"reference": "550e8400-e29b-41d4-a716-446655440000",
"order_id": "ORDER123456",
"status": "completed",
"amount": 100.50,
"currency": "USD",
"payment_method": "card",
"card_type": "visa",
"card_last_four": "1111",
"customer_email": "john.doe@example.com",
"created_at": "2023-12-01T10:30:00Z",
"completed_at": "2023-12-01T10:31:45Z",
"3ds_authenticated": true
}
}
Transaction Statuses
Status | Description | Next Steps |
---|---|---|
initialized |
Transaction created, pending processing | Wait for completion or check again |
processing |
Payment is being processed | Wait for completion |
completed |
Payment successfully completed | Fulfill order/service |
failed |
Payment failed or was declined | Retry with different card or method |
cancelled |
Payment was cancelled by user | Offer alternative payment method |
refunded |
Payment has been refunded | Update order status accordingly |
Refund Transaction
Process a full or partial refund for a completed transaction.
Endpoint:
POST https://gateway.pesogate.com/api/v1/payments/{reference}/refund
Parameters:
Parameter | Type | Required | Description |
---|---|---|---|
amount | decimal | Optional | Refund amount (defaults to full amount) |
reason | string | Optional | Reason for refund |
Example Request:
curl -X POST "https://gateway.pesogate.com/api/v1/payments/550e8400-e29b-41d4-a716-446655440000/refund" \
-H "Content-Type: application/json" \
-H "X-Api-Key: your_api_key" \
-H "X-Api-Secret: your_api_secret" \
-d '{
"amount": 50.25,
"reason": "Partial refund - item returned"
}'
Response:
{
"success": true,
"message": "Refund processed successfully",
"data": {
"refund_id": "ref_550e8400-e29b-41d4-a716-446655440000",
"original_reference": "550e8400-e29b-41d4-a716-446655440000",
"refund_amount": 50.25,
"currency": "USD",
"status": "completed",
"processed_at": "2023-12-01T15:30:00Z"
}
}
Error Handling
The API uses standard HTTP status codes and provides detailed error information in the response body.
Common Error Codes
HTTP Status | Error Code | Description |
---|---|---|
400 | BAD_REQUEST | Invalid request format or parameters |
401 | UNAUTHORIZED | Invalid or missing API credentials |
422 | VALIDATION_ERROR | Request validation failed |
429 | RATE_LIMIT_EXCEEDED | Too many requests - rate limit exceeded |
500 | INTERNAL_ERROR | Internal server error |
3DS Specific Errors
{
"success": false,
"message": "Authentication required",
"error_code": "3DS_AUTH_REQUIRED",
"details": {
"reason": "Card authentication required by issuer",
"recommended_action": "complete_3ds_challenge"
}
}
Address Validation Errors
{
"success": false,
"message": "Address validation failed",
"error_code": "ADDRESS_VALIDATION_ERROR",
"errors": {
"billing_address": [
"Street address is required",
"Country must be a valid 2-letter code"
]
}
}
Testing Your Integration
Test your integration using real credit cards with small amounts in the live environment. This ensures accurate testing of the complete payment flow including 3DS authentication and all security features.
Live Environment Testing Benefits
- Test actual 3DS authentication flows as implemented by card issuers
- Verify real-world payment processing scenarios
- Ensure compatibility with all payment networks
- Test actual fraud detection and security measures
- Validate address verification and CVV checking
- Experience the complete customer payment journey
Testing Best Practices
Recommended Test Amounts
- $1.00 USD - Basic payment flow testing
- $2.00 USD - 3DS challenge testing
- $5.00 USD - Refund functionality testing
- €1.00 EUR - Multi-currency testing
- £1.00 GBP - International payment testing
These small amounts minimize costs while providing comprehensive testing coverage.
Testing Scenarios
Test Scenario | Amount | Card Type | Expected Outcome |
---|---|---|---|
Basic Payment | $1.00 | Your personal card | Successful payment or 3DS challenge |
3DS Authentication | $2.00 | Personal card | 3DS challenge flow |
International Card | $1.00 | Non-domestic card | Cross-border processing |
Different Currency | €1.00 | EUR-enabled card | Multi-currency handling |
Refund Testing | $5.00 | Personal card | Full and partial refunds |
Test Billing Addresses
// Valid US Address
"billing_address": "123 Main Street, New York, NY, 10001, US"
// Valid UK Address
"billing_address": "10 Downing Street, London, SW1A 2AA, GB"
// Valid Canadian Address
"billing_address": "100 Wellington Street, Ottawa, ON, K1A 0A2, CA"
// Valid Australian Address
"billing_address": "1 Martin Place, Sydney, NSW, 2000, AU"
Testing Checklist
Before Going Live
Testing Tips
- Use valid billing addresses that match your card's registered address
- Test with cards from different banks and countries when possible
- Verify that declined payments are handled gracefully
- Test the complete customer journey from payment to receipt
- Document any issues and retest after fixes
- Keep transaction receipts for reconciliation
Complete Code Examples
Complete PHP Integration
<?php
class PaymentGateway {
private $apiKey;
private $apiSecret;
private $baseUrl;
public function __construct($apiKey, $apiSecret) {
$this->apiKey = $apiKey;
$this->apiSecret = $apiSecret;
$this->baseUrl = 'https://api.yourgateway.com/v1';
}
public function initializePayment($paymentData) {
$url = $this->baseUrl . '/payments/initialize';
$headers = [
'Content-Type: application/json',
'X-Api-Key: ' . $this->apiKey,
'X-Api-Secret: ' . $this->apiSecret
];
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($paymentData));
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode !== 200) {
throw new Exception('API request failed with HTTP code: ' . $httpCode);
}
return json_decode($response, true);
}
public function checkTransactionStatus($reference) {
$url = $this->baseUrl . '/payments/' . $reference . '/status';
$headers = [
'X-Api-Key: ' . $this->apiKey,
'X-Api-Secret: ' . $this->apiSecret
];
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
$response = curl_exec($ch);
curl_close($ch);
return json_decode($response, true);
}
}
// Usage example for live testing
try {
$gateway = new PaymentGateway('your_api_key', 'your_api_secret');
$paymentData = [
'order_id' => 'TEST-ORDER-' . time(),
'amount' => 1.00, // Test with small real amounts
'currency' => 'USD',
'card_number' => '4111111111111111', // Use your own card for testing
'exp_month' => '12',
'exp_year' => '25',
'cvv' => '123',
'customer_name' => 'John Doe',
'customer_email' => 'john.doe@example.com',
'billing_address' => '123 Main Street, New York, NY, 10001, US',
'return_url' => 'https://your-website.com/success',
'cancel_url' => 'https://your-website.com/cancel'
];
$result = $gateway->initializePayment($paymentData);
if ($result['success']) {
switch ($result['action']) {
case 'render_3ds_fullscreen':
// Handle 3DS challenge
render3DSChallenge($result['html_content']);
break;
case 'redirect':
// Redirect to hosted checkout
header('Location: ' . $result['redirect_url']);
exit;
}
} else {
echo 'Payment failed: ' . $result['message'];
}
} catch (Exception $e) {
echo 'Error: ' . $e->getMessage();
}
function render3DSChallenge($htmlContent) {
// Implementation as shown in 3DS section above
// ...
}
?>
HTML Payment Form Example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Secure Payment Gateway</title>
<style>
.payment-form {
max-width: 500px;
margin: 50px auto;
padding: 30px;
border: 1px solid #ddd;
border-radius: 8px;
font-family: Arial, sans-serif;
}
.form-group {
margin-bottom: 20px;
}
.form-group label {
display: block;
margin-bottom: 5px;
font-weight: bold;
color: #333;
}
.form-group input, .form-group select {
width: 100%;
padding: 10px;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
}
.form-row {
display: flex;
gap: 15px;
}
.form-row .form-group {
flex: 1;
}
.submit-btn {
background: #007cba;
color: white;
padding: 12px 30px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
width: 100%;
}
.submit-btn:hover {
background: #005a87;
}
.submit-btn:disabled {
background: #ccc;
cursor: not-allowed;
}
.required {
color: #e74c3c;
}
.help-text {
font-size: 12px;
color: #666;
margin-top: 5px;
}
</style>
</head>
<body>
<form id="payment-form" class="payment-form">
<h2>Secure Payment</h2>
<div class="form-group">
<label>Amount <span class="required">*</span></label>
<input type="number" name="amount" step="0.01" min="0.01" required value="1.00">
<div class="help-text">Test with small real amounts for best results</div>
</div>
<div class="form-group">
<label>Currency <span class="required">*</span></label>
<select name="currency" required>
<option value="USD">USD - US Dollar</option>
<option value="EUR">EUR - Euro</option>
<option value="GBP">GBP - British Pound</option>
</select>
</div>
<div class="form-group">
<label>Card Number <span class="required">*</span></label>
<input type="text" name="card_number" required maxlength="19"
placeholder="1234 5678 9012 3456"
oninput="this.value = this.value.replace(/[^0-9]/g, '').replace(/(.{4})/g, '$1 ').trim()">
</div>
<div class="form-row">
<div class="form-group">
<label>Month <span class="required">*</span></label>
<select name="exp_month" required>
<option value="">MM</option>
<option value="01">01</option>
<option value="02">02</option>
<option value="03">03</option>
<option value="04">04</option>
<option value="05">05</option>
<option value="06">06</option>
<option value="07">07</option>
<option value="08">08</option>
<option value="09">09</option>
<option value="10">10</option>
<option value="11">11</option>
<option value="12">12</option>
</select>
</div>
<div class="form-group">
<label>Year <span class="required">*</span></label>
<select name="exp_year" required>
<option value="">YYYY</option>
<option value="25">2025</option>
<option value="26">2026</option>
<option value="27">2027</option>
<option value="28">2028</option>
<option value="29">2029</option>
<option value="30">2030</option>
</select>
</div>
<div class="form-group">
<label>CVV <span class="required">*</span></label>
<input type="text" name="cvv" required maxlength="4" placeholder="123"
oninput="this.value = this.value.replace(/[^0-9]/g, '')">
</div>
</div>
<div class="form-group">
<label>Cardholder Name <span class="required">*</span></label>
<input type="text" name="customer_name" required placeholder="John Doe">
</div>
<div class="form-group">
<label>Email Address</label>
<input type="email" name="customer_email" placeholder="john.doe@example.com">
<div class="help-text">Optional: For transaction receipts</div>
</div>
<div class="form-group">
<label>Billing Address <span class="required">*</span></label>
<input type="text" name="billing_address" required
placeholder="123 Main Street, New York, NY, 10001, US">
<div class="help-text">Format: Street, City, State, Postal Code, Country</div>
</div>
<button type="submit" class="submit-btn" id="submit-btn">
Process Secure Payment
</button>
<div class="help-text" style="text-align: center; margin-top: 15px;">
Your payment is processed securely with bank-level encryption
</div>
</form>
<script>
// Add your payment gateway JavaScript here
// Implementation details in the JavaScript examples above
</script>
</body>
</html>
Integration Checklist
Before Going Live:
Support and Resources
Need help with your integration? Here are your support options: