Skip to main content

Overview

Cash payments allow customers without bank accounts or cards to pay at physical locations like convenience stores, pharmacies, and payment centers.

Coverage

10,000+ locations

Processing

Up to 72 hours

No Bank Needed

Perfect for unbanked

How It Works

The cash payment flow is simple: you create a payment request, we generate a voucher, the customer pays in cash at a physical location, and you receive a confirmation webhook.
88Pay integration flow diagram
1

Create Payment Request

Your system calls our API to create a cash payment transaction
2

Receive Voucher

API returns a voucher URL and payment code with barcode
3

Display to Customer

Show or email the voucher to your customer
4

Customer Pays

Customer visits a physical location and pays cash
5

Receive Confirmation

We send a webhook to your server when payment is confirmed

Creating a Cash Payment

API Request

curl -X POST "https://api-sandbox.88pay.io/api/transactions/charges" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "x-session-id: YOUR_SESSION" \
  -H "Content-Type: application/json" \
  -d '{
    "flow": "PAYIN",
    "method_code": "CASH",
    "method_category": "CASH",
    "amount": 50000,
    "currency": "COP",
    "country": "COL",
    "description": "Order #12345",
    "customer_id": "user_001",
    "notification_url": "https://yoursite.com/webhook"
  }'

API Response

{
  "status": "Success",
  "code": 200,
  "data": {
    "voucher_url": "https://vouchers.88pay.io/ABC123.pdf",
    "payment_code": "88PAY123456789",
    "reference": "IP9BD7CJES6",
    "expires_at": "2025-01-24T23:59:59Z",
    "amount": 50000,
    "currency": "COP"
  }
}
No return_url needed - the customer doesn’t leave your site. Display the voucher inline or send it via email.

Displaying the Voucher

You have two main options for presenting the payment voucher to your customer:

Option 1: Inline Display

Show the voucher directly on your confirmation page. This is ideal for desktop users or when you want to keep the customer on your site.
<div className="voucher">
  <h2>Complete Your Payment</h2>
  
  <div className="payment-code">
    <p>Payment Code:</p>
    <h1>{data.payment_code}</h1>
  </div>
  
  <img src={generateBarcode(data.payment_code)} alt="Barcode" />
  
  <p>Amount: {formatCurrency(data.amount, data.currency)}</p>
  <p>Valid until: {formatDate(data.expires_at)}</p>
  
  <a href={data.voucher_url} download>
    Download PDF Voucher
  </a>
  
  <div className="instructions">
    <h3>How to Pay:</h3>
    <ol>
      <li>Visit any authorized location</li>
      <li>Show this code to the cashier</li>
      <li>Pay {formatCurrency(data.amount, data.currency)} in cash</li>
      <li>Keep your receipt</li>
    </ol>
  </div>
</div>

Option 2: Email Voucher

Send the voucher via email. This is essential for mobile users and ensures customers don’t lose the voucher.
await sendEmail({
  to: customer.email,
  subject: 'Complete Your Payment',
  template: 'cash-voucher',
  data: {
    customer_name: customer.name,
    payment_code: data.payment_code,
    amount: data.amount,
    currency: data.currency,
    expires_at: data.expires_at,
    voucher_pdf: data.voucher_url,
    instructions: getInstructionsForCountry(data.country)
  }
});
Best practice: Use both methods. Display the voucher on-screen AND send it via email to maximize payment completion rates.

Customer Payment Process

Once the customer has the voucher, here’s what happens:
1

Customer Receives Voucher

The voucher includes:
  • Payment code (as barcode and numbers)
  • Exact amount to pay
  • Expiry date
  • Step-by-step instructions
2

Customer Visits Location

Customer goes to any authorized payment location (convenience store, pharmacy, payment center)
3

Present Payment Code

Customer shows the barcode (cashier scans) or provides the numeric code (cashier enters manually)
4

Pay Cash

Customer pays the exact amount in cash and receives a receipt
5

Payment Confirmed

Payment is confirmed within minutes to hours, and a webhook is sent to your server

Handling Webhooks

You’ll receive webhooks at different stages of the payment lifecycle:
{
  "transaction_status": "PENDING",
  "transaction_reference": "IP9BD7CJES6",
  "transaction_payment_method": "CASH"
}
Meaning: Voucher generated, awaiting paymentAction: Wait for customer to pay. Consider sending reminders as expiry approaches.

Voucher Expiration

Cash vouchers expire 7 days after generation by default.
After expiration:
  • Voucher becomes invalid
  • Payment cannot be accepted
  • Webhook sent with status REJECTED
  • Customer must request a new voucher

Managing Expiration

Send proactive reminders to improve conversion:
// Monitor approaching expiration
const expiryDate = new Date(data.expires_at);
const now = new Date();
const hoursLeft = (expiryDate - now) / (1000 * 60 * 60);

if (hoursLeft < 24 && hoursLeft > 0) {
  await sendEmail({
    to: customer.email,
    subject: 'Payment Expires Soon',
    message: `Your voucher expires in ${Math.floor(hoursLeft)} hours. Pay now to complete your order.`
  });
}

Handling Expired Vouchers

app.post('/webhook', (req, res) => {
  if (req.body.transaction_status === 'REJECTED' 
      && req.body.reason === 'expired') {
    
    // Offer to generate new voucher
    await sendEmail({
      to: customer.email,
      subject: 'Voucher Expired - Generate New One',
      action_url: `/orders/${orderId}/regenerate-voucher`
    });
  }
  
  res.status(200).json({ received: true });
});

Testing in Sandbox

In the sandbox environment, cash payments are simulated for easy testing:
1

Generate Voucher

Call the API - voucher is created instantly
2

Auto-Completion

Payment automatically completes after 2 minutes
3

Webhook Delivery

COMPLETED webhook is sent automatically
// Test flow
const payment = await createCashPayment(testData);
console.log('Voucher generated:', payment.voucher_url);

// Wait 2 minutes
await sleep(120000);

// Webhook should be received with COMPLETED status

Best Practices

Customers may close their browser or navigate away. Email ensures they can access the voucher later.
await sendEmail({
  to: customer.email,
  subject: 'Payment Instructions',
  attachments: [
    {
      filename: 'voucher.pdf',
      path: data.voucher_url
    }
  ]
});
Proactive reminders significantly increase completion rates.
// Schedule reminder 24 hours before expiry
scheduleJob(
  new Date(data.expires_at - 86400000),
  () => sendExpiryReminder(customer.email)
);
Show step-by-step payment instructions in the customer’s language. Include:
  • Where to pay (store names they recognize)
  • What to bring (voucher, ID if required)
  • Exact amount to pay
  • Expiry date and time
Some payment networks allow partial payments. Monitor webhooks for partial payment notifications and request the customer pay the remaining balance.
if (webhook.amount < expected_amount) {
  const remaining = expected_amount - webhook.amount;
  await notifyCustomer(`Please pay the remaining ${remaining}`);
}
Barcodes occasionally fail to scan. Always display the numeric code so cashiers can enter it manually.

Troubleshooting

Possible causes:
  • Webhook endpoint is down or unreachable
  • Payment is still processing (can take up to 72 hours)
  • Network connectivity issues
Solutions:
  • Query transaction status via API using the reference ID
  • Check webhook logs in your dashboard
  • Verify your webhook endpoint is accessible and returning 200 OK
  • Contact support with the transaction reference
Solutions:
  • Provide the numeric payment code for manual entry
  • Ensure PDF quality is high (300 DPI minimum)
  • Check that barcode format is compatible with the payment network
  • Customer can show the code on their phone screen
Common scenario: Customer paid less than the required amountSolutions:
  • Some networks accept partial payments - check webhook data
  • Customer must return to pay the remaining balance
  • Generate a new voucher for the difference
  • Update order status to reflect partial payment
Solutions:
  • Provide a location finder URL in the voucher
  • List the most common store chains in the area
  • Offer alternative payment methods if no locations nearby

Next Steps