Skip to main content
Webhooks let Kulmi Pay push notifications to your server the moment something happens — a payment completes, a disbursement is processed, or a subscription billing cycle runs. Instead of polling the API for status updates, you register an HTTPS endpoint and Kulmi Pay delivers a JSON payload to it whenever a subscribed event occurs.

Set up a webhook

1

Add your endpoint in the dashboard

Go to Settings → Webhooks in your Kulmi Pay dashboard and click Add Webhook. Enter the full URL of the endpoint on your server that will receive events. The URL must use HTTPS — plain HTTP endpoints are rejected.
2

Set a challenge secret

Enter a secret string in the Challenge field. Kulmi Pay includes this value in every webhook request as an X-Challenge header so you can verify that the request genuinely came from Kulmi Pay. Store this secret securely and never expose it in client-side code.
3

Subscribe to events

Select which event types you want to receive. Each flag maps to a specific activity on your account:
Event flagDescription
collection_eventPayment invoice state changes (e.g. pending → complete)
send_money_eventDisbursement file state changes
reversal_eventChargebacks and reversals
wallet_transfer_eventIntra-wallet transfers
subscription_eventSubscription status and billing cycle changes
You can subscribe to one or more events on a single webhook endpoint, or use separate endpoints for different event types.
4

Handle incoming payloads

Your endpoint must accept POST requests with a JSON body. Respond with an HTTP 200 status code as quickly as possible — do any heavy processing asynchronously. Kulmi Pay considers any non-200 response a delivery failure.Every webhook payload follows this structure:
{
  "topic": "collection_event",
  "data": {
    "id": "inv_abc123",
    "state": "COMPLETE",
    "value": "1000.00",
    "currency": "KES",
    "provider": "M-PESA",
    "api_ref": "ORDER-001"
  }
}
The topic field identifies the event type. The data object contains the full resource that changed — an invoice, a payment file, a chargeback, or a subscription depending on the topic.

Verify the challenge secret

Before processing any webhook payload, confirm that the request came from Kulmi Pay by comparing the X-Challenge header against your stored secret.
const express = require('express');
const app = express();

app.use(express.json());

app.post('/webhooks/kulmipay', (req, res) => {
  const challenge = req.headers['x-challenge'];

  if (challenge !== process.env.KULMIPAY_WEBHOOK_SECRET) {
    return res.status(401).json({ error: 'Invalid challenge' });
  }

  const { topic, data } = req.body;

  // Process the event asynchronously
  handleWebhookEvent(topic, data);

  res.status(200).json({ received: true });
});

Retry behavior and failure handling

When your endpoint returns a non-200 response or is unreachable, Kulmi Pay marks the event as FAILED and increments the failure counter for that webhook. As the failure count rises, Kulmi Pay sends email warnings to your account’s support address.
Your webhook endpoint must use HTTPS with a valid, verifiable TLS certificate. Endpoints that cannot be verified are rejected. If your webhook accumulates too many consecutive failures, Kulmi Pay automatically disables it to prevent further delivery attempts. You will receive an email notification before this happens. To re-enable your webhook, fix the underlying issue and toggle it back on in the dashboard.
Failed events are not lost. You can replay any event from the Webhooks → Events log in your dashboard, or via the API. See Webhook event types for details on replaying events.