Skip to main content

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

1

Create Account

2

Get Approved

Upload required documents in Account Details (usually approved within 24h)
3

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:
ParameterDescription
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 NumberCVVExpiryResult
4111111111111111Any 3 digitsAny future date✅ Approved
4000000000000002Any 3 digitsAny future date❌ Declined
4000000000000069Any 3 digitsAny future date⏳ Pending

Possible Webhook Statuses

StatusDescription
COMPLETEDPayment successful
PENDINGAwaiting confirmation (e.g., bank transfer)
REJECTEDPayment failed, declined, or expired

Complete Example

Full end-to-end implementation:
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
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
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