Register webhooks in the merchant platform (URL, secret, subscribed events). KutanaPay delivers POST requests to your HTTPS endpoint. This page describes the payload you receive.
Delivery envelope#
Every event uses the same top-level JSON shape:| Field | Type | Description |
|---|
version | string | Payload format version. Currently v1. |
event_type | string | Event name, e.g. checkout.paid. |
timestamp | string | ISO-8601 UTC when the event was emitted. |
idempotency_key | string | Unique per delivery. Store it to avoid processing twice. |
merchant_id | string | Your business id in KutanaPay. |
data | object | Event-specific fields (tables below). |
Verify X-Webhook-Signature with your webhook secret before using the body.
Recommended subscriptions (hosted checkout)#
For a typical hosted checkout integration, subscribe in the platform to:| Event | Why |
|---|
checkout.paid | Customer payment recorded. Often used to mark an order paid. |
checkout.approved | Bank-transfer checkout approved after review (when applicable). |
checkout.rejected | Bank-transfer checkout rejected. |
checkout.created | Optional audit trail when a checkout session is created. |
Use checkout.paid and/or checkout.approved depending on payment method; confirm fulfillment rules with your KutanaPay contact.Do not rely on events marked not subscribable yet until they appear in the platform event picker.
Checkout events#
Subscribable today (live in catalog)#
These can be selected when configuring a webhook in the platform.checkout.created#
Emitted when a checkout is created (from the merchant platform or programmatic API).Field in data | Type | Required | Description |
|---|
checkout_id | string | yes | Checkout id or payment reference. |
amount | number | yes | Amount in checkout currency. |
currency_code | string | yes | Currency code. |
status | string | yes | Checkout status at emit time. |
customer_email | string | no | Customer email when present. |
checkout.paid#
Emitted when customer payment is recorded for the checkout.Same fields as checkout.created, plus:Field in data | Type | Required | Description |
|---|
paid_at | string | no | When payment was recorded (ISO-8601). |
checkout.approved#
Emitted when a bank-transfer checkout is approved after review.Uses the same core checkout fields as checkout.created.checkout.rejected#
Emitted when a bank-transfer checkout is rejected.Uses the same core checkout fields as checkout.created.In catalog but not subscribable yet#
You may see these in documentation or future platform releases. They cannot be added to subscribed_events until marked available in the platform.| Event | Meaning |
|---|
checkout.expired | Checkout expired before payment (expiry job may emit; subscription coming later). |
checkout.completed | Terminal success state (reserved). |
checkout.failed | Payment attempt failed (reserved). |
Example: checkout.paid#
{
"version": "v1",
"event_type": "checkout.paid",
"timestamp": "2026-03-26T14:22:01.000000Z",
"idempotency_key": "8a7b6c5d-4e3f-2a1b-0c9d-8e7f6a5b4c3d",
"merchant_id": "7bb54443-6fc9-4a1d-ab46-d787ec90c87f",
"data": {
"checkout_id": "c4e8b1a2-9f3d-4e7a-b6c5-1d2e3f4a5b6c",
"amount": 150.0,
"currency_code": "GHS",
"status": "paid",
"customer_email": "ama.mensah@acmecustomer.com",
"paid_at": "2026-03-26T14:22:00.000000Z"
}
}
data may include additional checkout fields from your tenant schema; treat unknown keys as optional.
These exist in the event catalog for future or internal use. They are not subscribable yet unless the platform lists them. Hosted checkout integrators usually ignore them.| Event | Category | Summary |
|---|
deposit.received | Money | Funds credited to merchant wallet (reserved). |
payout.processed | Money | Payout completed (reserved). |
withdrawal.completed | Money | Withdrawal completed (reserved). |
settlement.completed | Money | Settlement batch completed (reserved). |
user.invited | Team | Team invite sent (reserved). |
user.joined | Team | Team member joined (reserved). |
test.event | System | Test delivery from the platform test action. |
Subscribing to events#
In the merchant platform, when you configure a webhook:Empty or “all events” (if offered): delivers every live catalog event your endpoint is allowed to receive.
Explicit list: only listed types are delivered, e.g. ["checkout.paid", "checkout.approved"].
Unknown or not-yet-live event names are rejected when saving webhook configuration.
Handler reminders#
1.
Verify signature on the raw body.
2.
Dedupe on idempotency_key.
3.
Return 2xx quickly; retry on 5xx only for transient errors.
4.
Fulfill orders idempotently
Modified at 2026-09-26 21:46:22