Skip to main content

Handling Kuda Business API Webhooks

Configure webhook notifications, receive transaction and bill events, and process them safely.

Written by Nosa O

Webhooks let your app receive updates about transactions and bill payments without polling continuously.

Use webhooks together with transaction status queries. A webhook is a notification; your app should still be able to confirm important outcomes with the relevant TSQ service.

Configure your webhook URL

  1. Sign in to the Kuda Business dashboard.

  2. Go to Business API settings.

  3. Open Webhooks.

  4. Enter your public notification URL.

  5. Add webhook authentication details.

  6. Save the configuration.

Do not use your Kuda Business login password as the webhook password.

Webhook handler rules

Your webhook endpoint should:

  • accept JSON requests

  • authenticate the request using your configured webhook credentials

  • store the payload immediately

  • respond with HTTP 200 OK within 10 seconds

  • process business logic asynchronously where possible

  • be safe to receive duplicate notifications

If your server does not respond successfully, Kuda may queue and retry delivery.

Example webhook handler

import express from "express";const router = express.Router();router.post("/webhooks/kuda", async (req, res) => {
  const payload = req.body;  await saveWebhookPayload({
    eventType: payload.eventType,
    payload,
    receivedAt: new Date().toISOString()
  });  res.sendStatus(200);  queueWebhookProcessing(payload);
});export default router;

Transaction notification

Transaction notifications can be sent for incoming and outgoing transactions.

Example:

{
  "eventType": "Transaction.Notification",
  "amount": 36000,
  "transactionDate": "2023-12-08T00:00:00",
  "transactionReference": "231208609730",
  "accountName": "Sample Business",
  "accountNumber": "2050000000",
  "narrations": "Incoming transfer",
  "transactionType": "Credit",
  "senderName": "Sample Sender",
  "senderAccountNumber": "3000000000",
  "recipientName": "Sample Business",
  "instrumentNumber": "ITR-123",
  "sessionID": null,
  "clientRequestRef": "client-ref-001",
  "transactionScope": "inward"
}

Important fields:

Field

Meaning

eventType

Event type, such as Transaction.Notification.

amount

Amount in kobo.

transactionReference

Kuda transaction reference.

accountNumber

Account affected by the transaction.

transactionType

Credit, Debit, or Reversal.

instrumentNumber

Internal transaction instrument/reference.

clientRequestRef

Optional client reference.

transactionScope

Direction or context, such as inward or outward.

Bill payment notification

Bill notifications can include bill request and response references plus PIN or token details.

{
  "eventType": "Bill.Transaction",
  "BillRequestRef": "BILL20260603001",
  "BillResponseReference": "mtn12345",
  "Pin": {
    "Number": "123456789012",
    "Serial": "SERIAL123456",
    "Instructions": "Use this token on the biller platform."
  },
  "BillerName": "MTN NG VTU",
  "KudaAccountNumber": "2000000000",
  "TransactionAmount": "10000",
  "CustomerIdentifier": "07030000000",
  "BillType": "airtime"
}

Bill payment webhooks can depend on external biller or aggregator services. If a bill webhook is delayed, use BILL_TSQ to confirm the final status.

Idempotency

Your webhook processor should handle duplicates safely.

Use stable identifiers such as:

  • eventType

  • transactionReference

  • instrumentNumber

  • BillRequestRef

  • BillResponseReference

  • clientRequestRef

Store processed event identifiers so duplicate deliveries do not double-credit orders or trigger duplicate fulfillment.

Webhooks and TSQ

Use the matching status-query service when a webhook is missing, delayed, or unclear:

Flow

Status-query service

Single transfer

TRANSACTION_STATUS_QUERY

Bulk payment

BULK_PAYMENT_TSQ

Bill payment

BILL_TSQ

Dynamic account collections

DYNAMIC_COLLECTION_ACCOUNT_TSQ

Common mistakes

  • Doing heavy processing before sending 200 OK.

  • Not storing the raw webhook payload.

  • Assuming webhook delivery will be instant.

  • Not handling duplicate notifications.

  • Treating instrumentNumber as a bank account number.

  • Depending only on webhooks without TSQ fallback.

Did this answer your question?