Skip to main content

Webhooks

Intro

Khaime sends an HTTP POST request to your webhook URL whenever a notable event happens on your account — a payment succeeds, a subscription renews, a payout settles, a dispute opens. Webhooks are the most reliable way to track transaction state; don’t rely solely on redirect callbacks, since a customer can close their browser before the redirect fires.

Context

Webhooks are configured per Partner API key (sandbox or live), so sandbox activity notifies your sandbox webhook URL and live activity notifies your live one. You set the URL and read the signing secret from the same place you manage API keys. This page is the entry point for the webhooks documentation. Once you understand the envelope and delivery model here, go to:

Hows

Setup

  1. Go to Khaime Dashboard → Settings → API
  2. Set your Webhook URL (e.g., https://yoursite.com/webhooks/khaime)
  3. Copy your Webhook Secret (whsec_...)
Or set the webhook URL programmatically:

Envelope structure

Every webhook delivery shares the same outer envelope regardless of event type:
The event_id is the idempotency key. You must store processed event_id values and skip duplicates — retries reuse the same event_id.

Webhook headers

Every webhook request includes these headers:

Delivery

Respond to webhooks within 5 seconds with a 200 status. Process the event asynchronously after acknowledging receipt — a slow handler that blocks on downstream work risks hitting the 10-second timeout and triggering a retry (and a duplicate delivery) for an event you actually already received.

Shared data types

These types appear across multiple event payloads.

MoneyAmount

All monetary values are in the smallest currency unit (cents for USD, kobo for NGN). Never floats.

MulticurrencyBreakdown

Present on payment and order events. Provides a full breakdown of amounts, fees, and currency conversion.
If the customer and merchant currencies are the same, conversion is omitted and customer_paid equals merchant_gross.

Customer

The id field is present only if the customer has a platform account.

Example handler

Whys

Webhooks exist because payment, subscription, and settlement state changes asynchronously and often outside the request/response cycle your customer is in — a bank transfer settles hours later, a dispute is opened by a card network days later, a subscription renews on a schedule with no customer present at all. A redirect callback only covers the moment right after checkout; it can’t tell you about anything that happens afterward. The envelope carries a stable event_id specifically so retries are safe to replay: delivery is at-least-once, not exactly-once, so your handler has to be idempotent rather than relying on the network to deliver each event exactly one time. Signing over the raw request body (rather than a parsed-and-reserialized one) means the check only depends on bytes you actually received, with no dependency on your JSON library preserving key order or whitespace.

Why nots

Webhooks are not a substitute for reconciliation. Delivery to your endpoint can fail — DNS issues, deploys, firewall rules — and after 3 attempts Khaime stops retrying. For payments created through the Charge API, treat the webhook as the primary signal but don’t assume silence means nothing happened; if you must be certain, check the record directly (see Best Practices). Khaime does not guarantee webhook delivery order across event types — a payment.succeeded and its companion wallet.credited are fired independently, so design handlers that don’t assume strict ordering between related events. Webhooks also don’t carry a response contract beyond the HTTP status code: whatever your endpoint returns in the body is logged for debugging but never parsed or acted on.