> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kler.africa/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhooks

> Receiving real-time payment events from Kler.

When a payment is received on a Kler collection account, Kler fires a `POST` request to the `webhook_url` you set when creating the session.

## Event types

| Event                  | When it fires                              |
| ---------------------- | ------------------------------------------ |
| `transaction.received` | A payment has been recorded on the session |

More event types (e.g. `session.closed`, `terminal.offline`) will be added over time.

## Payload

```json theme={null}
{
  "event": "transaction.received",
  "session_id": "sess_...",
  "data": {
    "id": "txn_...",
    "amount": "5000.00",
    "currency": "NGN",
    "channel": "bank_transfer",
    "status": "successful",
    "sender_name": "Jane Doe",
    "sender_account": "0123456789",
    "sender_bank": "058",
    "narration": "Ticket purchase",
    "providus_ref": "PVS20250801XXXXXXX",
    "paid_at": "2025-08-01T18:32:00.000Z"
  }
}
```

## Channel values

| Value           | Meaning                     |
| --------------- | --------------------------- |
| `bank_transfer` | NIP / instant bank transfer |
| `pos`           | POS terminal                |
| `ussd`          | USSD payment                |
| `card`          | Web/card payment            |

## Handling webhooks

Your endpoint should:

1. Return a `200` response quickly — Kler does not wait for your processing to complete
2. Process the event asynchronously if needed
3. Be idempotent — the same `transaction.id` may be delivered more than once

```typescript theme={null}
app.post('/webhooks/kler', async (req, res) => {
  res.status(200).send({ received: true }) // respond immediately

  const { event, session_id, data } = req.body

  if (event === 'transaction.received') {
    await recordPayment(session_id, data)
  }
})
```

## Retries

If your endpoint does not return a `2xx` response, Kler will retry the webhook with exponential backoff up to 5 times.
