Your First Transaction in 3 Steps
This guide walks you through creating a test payment using the Sandbox environment. You’ll learn the complete flow from authentication to receiving webhooks.
Sandbox mode: No real money involved. Perfect for testing and development.
Before You Start
Get Approved
Upload required documents in Account Details (usually approved within 24h)
Get Credentials
Navigate to Settings → API Credentials and copy:
API Key (starts with sk_test_)
Merchant ID (format: MCH-COL-XXX)
Keep your credentials secure. Never commit them to version control.
Step 1: Generate Token
Exchange your credentials for a short-lived access token.
curl -X POST "https://api-sandbox.88pay.io/api/auth/token" \
-H "x-api-key: YOUR_API_KEY" \
-H "x-merchant-id: YOUR_MERCHANT_ID"
Response:
{
"status" : "Success" ,
"code" : 200 ,
"message" : "Token generated successfully" ,
"data" : {
"access_token" : "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9..." ,
"expires_in" : 60 ,
"session_id" : "sess_53a2cfc4-441e-4554-b560-4e008784d98e"
}
}
Token expires in 60 seconds . Generate a new one for each operation or implement caching (see Authentication Guide ).
Step 2: Create Payment
Create a card payment using the token from Step 1.
curl -X POST "https://api-sandbox.88pay.io/api/transactions/charges" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "x-session-id: YOUR_SESSION_ID" \
-H "Content-Type: application/json" \
-d '{
"flow": "PAYIN",
"method_code": "CARDS",
"method_category": "CARD",
"amount": 50000,
"country": "COL",
"currency": "COP",
"description": "Test Purchase #001",
"customer_id": "customer_12345",
"notification_url": "https://yoursite.com/webhook",
"return_url": "https://yoursite.com/thank-you"
}'
Response:
{
"status" : "Success" ,
"code" : 200 ,
"message" : "Method processed" ,
"data" : {
"urlCheckout" : "https://link.88pay.io/GSW4WAR" ,
"reference" : "IP9BD7CJES6" ,
"customer_id" : "customer_12345" ,
"currency" : "COP" ,
"amount" : 50000
}
}
Key Parameters:
Parameter Description urlCheckoutRedirect your customer here to complete payment referenceUnique transaction ID for tracking notification_urlWhere we’ll send webhook notifications return_urlWhere we redirect customers after payment
Step 3: Complete Payment Flow
3.1 Redirect Customer
Send your customer to the checkout URL:
// Option 1: Full redirect
window . location . href = data . urlCheckout ;
// Option 2: Open in new tab
window . open ( data . urlCheckout , '_blank' );
// Option 3: Embed in iframe (not recommended for cards)
< iframe src = { data . urlCheckout } />
3.2 Handle Webhook
After payment completion, you’ll receive a POST request to your notification_url:
{
"transaction_date" : "2025-01-17 14:30:45" ,
"transaction_status" : "COMPLETED" ,
"transaction_id" : "sess_4e91a5c1-b7f2-4c64-91b1-3d204a5738b4" ,
"transaction_amount" : "50000" ,
"transaction_payment_method" : "CREDIT_CARD" ,
"transaction_country" : "COL" ,
"transaction_currency" : "COP" ,
"transaction_reference" : "IP9BD7CJES6" ,
"transaction_customer_id" : "customer_12345"
}
Webhook Handler Example:
app . post ( '/webhook' , express . json (), ( req , res ) => {
const { transaction_status , transaction_reference } = req . body ;
if ( transaction_status === 'COMPLETED' ) {
// Update order status in your database
console . log ( `Payment ${ transaction_reference } completed` );
}
// Always respond with 200 OK
res . status ( 200 ). json ({ received: true });
});
Critical: Your webhook endpoint MUST return 200 OK. Otherwise, we’ll retry the notification (up to 10 times with exponential backoff).
Testing Your Integration
Test Cards (Sandbox Only)
Card Number CVV Expiry Result 4111111111111111Any 3 digits Any future date ✅ Approved 4000000000000002Any 3 digits Any future date ❌ Declined 4000000000000069Any 3 digits Any future date ⏳ Pending
Possible Webhook Statuses
Status Description COMPLETEDPayment successful PENDINGAwaiting confirmation (e.g., bank transfer) REJECTEDPayment failed, declined, or expired
Complete Example
Full end-to-end implementation:
Complete Flow
Complete Flow
async function processPayment () {
try {
// 1. Generate Token
const tokenRes = await fetch ( 'https://api-sandbox.88pay.io/api/auth/token' , {
method: 'POST' ,
headers: {
'x-api-key' : process . env . EIGHTY_EIGHT_PAY_API_KEY ,
'x-merchant-id' : process . env . EIGHTY_EIGHT_PAY_MERCHANT_ID
}
});
const { data : { access_token , session_id } } = await tokenRes . json ();
// 2. Create Payment
const paymentRes = await fetch ( 'https://api-sandbox.88pay.io/api/transactions/charges' , {
method: 'POST' ,
headers: {
'Authorization' : `Bearer ${ access_token } ` ,
'x-session-id' : session_id ,
'Content-Type' : 'application/json'
},
body: JSON . stringify ({
flow: "PAYIN" ,
method_code: "CARDS" ,
method_category: "CARD" ,
amount: 50000 ,
country: "COL" ,
currency: "COP" ,
description: "Test Purchase #001" ,
customer_id: "customer_12345" ,
notification_url: "https://yoursite.com/webhook" ,
return_url: "https://yoursite.com/thank-you"
})
});
const payment = await paymentRes . json ();
// 3. Redirect to checkout
window . location . href = payment . data . urlCheckout ;
} catch ( error ) {
console . error ( 'Payment error:' , error );
// Handle error (show message to user, log to monitoring, etc.)
}
}
What’s Next?
Troubleshooting
Cause: Invalid credentials or expired tokenSolution:
Verify API Key and Merchant ID in dashboard
Check token hasn’t expired (60s lifetime)
Ensure both Authorization and x-session-id headers are present
Webhook not receiving notifications
Cause: Invalid URL or server not responding with 200 OKSolution:
Test webhook URL with tools like webhook.site
Ensure your server is publicly accessible (no localhost in production)
Return 200 OK immediately, process webhook async
Customer sees error on checkout page
Cause: Invalid parameters or insufficient merchant balanceSolution:
Verify all required fields are present
Check amount is within allowed limits
Ensure currency matches country (e.g., COP for Colombia)
Still Need Help? Join our Discord community for real-time support