Skip to main content

Webhook Events

Intro

Every Khaime webhook event uses dot-notation grouping — {object}.{action} — across seven families: payments, subscriptions, wallet, settlements, disputes, merchant accounts, and physical order fulfillment. This page is the full reference for every event type and its payload shape.

Context

All events share the same envelope structure described in the overview — only the data field changes shape between event types. If you haven’t read the Webhooks Overview yet, start there for the envelope, headers, and delivery model; this page assumes you already have a handler receiving and verifying requests (see Signature Verification). Several event families are linked to each other: a successful payment.succeeded also fires a companion wallet.credited; an order.refunded also fires a payment.refunded for the underlying charge. Where that happens, it’s called out in the event’s description below.

Hows

Event taxonomy

payment.*

subscription.*

wallet.*

settlement.*

dispute.*

account.*

order.* (physical products only)


Event payloads

payment.succeeded

Fired when a payment is completed successfully.
A successful payment also fires a companion wallet.credited event for the merchant’s wallet.

payment.failed

Fired when a payment attempt fails. Same structure as payment.succeeded with status: "failed" and paid_at: null.

payment.refunded

Fired when a full or partial refund is processed.

payment.disputed

Fired when a customer opens a chargeback or dispute. Same payment structure with status: "disputed". A dispute.created event fires alongside it with the full dispute record.

subscription.created

Fired when a new subscription is initiated.

subscription.renewed

Fired when a recurring charge succeeds. Includes latest_payment_id and amounts with the renewal payment breakdown.

subscription.payment_failed

Fired when a renewal charge fails. Subscription status changes to past_due.

subscription.cancelled

Fired when a subscription is cancelled (immediately or at period end). Includes cancellation_reason if provided.

subscription.expired

Fired when the subscription period ends without renewal.

subscription.trial_started

Fired when a trial period begins. Subscription status is trialing and the trial object is present.

subscription.trial_ending

Fired 3 days before a trial ends — a grace notification to prompt conversion.

subscription.trial_ended

Fired when the trial period ends (whether the subscription converted to paid or expired).

wallet.credited

Fired when the merchant wallet is credited (e.g., after a successful sale).

wallet.debited

Fired when the merchant wallet is debited (refund issued, dispute hold placed, or payout). Same structure as wallet.credited with type: "debit".

settlement.initiated

Fired when a payout or withdrawal is requested.

settlement.completed

Fired when funds are confirmed delivered to the merchant’s bank.
Cross-currency settlement example (USD wallet to NGN bank account):

settlement.processing

Fired when the gateway confirms the payout is being processed.

settlement.failed

Fired when a payout fails at the gateway level. Includes failure_reason.

dispute.created

Fired when a dispute is opened on a payment.
The dispute hold (hold_amount) is placed on the merchant wallet as a companion wallet.debited event with reason: "dispute_hold".

dispute.evidence_due

Fired when the evidence deadline is approaching.

dispute.won

Fired when the dispute is resolved in the merchant’s favour. Held funds are released — a companion wallet.credited event fires with reason: "dispute_released".

dispute.lost

Fired when the dispute is resolved against the merchant.

account.updated

Fired when a merchant’s payment account or KYC verification status changes — onboarding progress, a capability being enabled or disabled, approval, or revocation.
If the merchant is a sub-merchant under a marketplace, this event is delivered to both the merchant’s own webhook URL and the marketplace operator’s, so the operator stays in sync with its sub-merchants’ account status without polling.

order.created

Fired when a physical product order is placed and paid.

order.shipped

Fired when a shipping label is generated and tracking is available. Includes shipping.tracking_number, shipping.carrier, and shipping.shipped_at.

order.delivered

Fired when delivery is confirmed. Includes shipping.delivered_at.

order.refunded

Fired on an order-level refund. Also fires a payment.refunded event for the associated payment.

Whys

Events use {object}.{action} naming (rather than one event per specific state) so you can pattern-match on the object family in a switch statement while still discriminating on the specific transition — a client that only cares about money movement can key off everything under payment.* and wallet.* without enumerating every action. Companion events (a payment firing a wallet credit, a dispute firing a wallet debit) are separate deliveries rather than nested fields on one payload, because they can fail, retry, and get acknowledged independently — a wallet ledger update and a payment status change are different concerns for most integrations, and coupling them into a single delivery would mean a partial handler failure on one concern blocks the other.

Why nots

This page documents payload shape, not delivery guarantees or verification — see Webhooks Overview for the envelope/retry model and Signature Verification before you trust any payload here. It also isn’t a change log: new event types can be added at any time without a version bump (see API Versioning), so a production handler should default unknown event_type values to a no-op rather than erroring. Field values documented as illustrative (gateway names, dispute reasons, provider identifiers) are not closed enums unless explicitly stated — treat unrecognized string values as “handle gracefully,” not “reject.”