Skip to main content

Webhooks

Webhooks allow Cashless to notify your server when a bill's payment status changes, eliminating the need to poll the API.

Setup

Contact Cashless support to configure a webhook URL for your merchant account. Your endpoint should:

  1. Accept POST requests with a JSON body
  2. Return a 200 status code to acknowledge receipt
  3. Process the payment update (e.g., mark order as paid)

Webhook payload

When a bill is paid, Cashless sends a POST request to your webhook URL:

{
"bill": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"mobile": "0712345678",
"amount": 5000.0,
"status": "FULLY_PAID",
"reference": "ORDER-001"
}
}

Example handler

// Express.js webhook handler
app.post('/webhooks/cashless', (req, res) => {
const { bill } = req.body;

if (bill.status === 'FULLY_PAID') {
// Update your order status
markOrderAsPaid(bill.reference);
}

res.sendStatus(200);
});

Best practices

  • Always verify: After receiving a webhook, call GET /bills/{id} to verify the payment status independently. Do not trust the webhook payload alone.
  • Idempotency: Your handler may receive duplicate webhooks. Ensure processing the same bill twice is safe.
  • Respond quickly: Return 200 within a few seconds. Do heavy processing asynchronously.
  • Fallback: Use polling as a fallback in case webhooks fail to deliver.

Webhook + polling pattern

For maximum reliability, combine webhooks with polling:

// 1. Create bill and start background polling
const bill = await api.issue(params);
startPolling(bill.id);

// 2. Also handle webhooks for faster notification
app.post('/webhooks/cashless', async (req, res) => {
const { bill } = req.body;
// Verify via API
const verified = await api.get(bill.id);
if (verified.status.name === 'FULLY_PAID') {
stopPolling(bill.id);
markOrderAsPaid(bill.reference);
}
res.sendStatus(200);
});