MavuntaMavunta
Building

Webhooks

Webhooks are how you safely confirm a payment. Register HTTPS endpoints in the console; Mavunta signs every event and retries failed deliveries with backoff. Return any 2xx to acknowledge.

Event types

payment_intent.paid            payment_intent.failed
payment_intent.expired         payment_intent.cancelled
payment_intent.underpaid       payment_intent.overpaid
payment_intent.refunded        payment_intent.requires_review
payment_intent.disputed        payment_intent.duplicate_payment

Verify the signature

Each request carries Mavunta-Signature (a hex HMAC), Mavunta-Timestamp, and Mavunta-Event-Id. Recompute the HMAC-SHA256 over `${timestamp}.${rawBody}` with your endpoint secret and compare in constant time. Mavunta-Event-Id is stable across retries — use it to deduplicate.

import { createHmac, timingSafeEqual } from 'node:crypto'

function verify(secret, timestamp, rawBody, signature) {
  const expected = createHmac('sha256', secret)
    .update(`${timestamp}.${rawBody}`).digest('hex')
  return timingSafeEqual(Buffer.from(expected, 'hex'), Buffer.from(signature, 'hex'))
}
Our SDKs do this for you: mavunta.webhooks.verify(...) checks the signature and timestamp and returns the parsed event. See SDKs.

Payload

{
  "id": "evt_live_...",
  "type": "payment_intent.paid",
  "api_version": "2026-06-01",
  "created_at": "2026-06-18T12:06:10Z",
  "data": {
    "id": "pi_...",
    "status": "paid",
    "amount": "2500",
    "currency": "KES",
    "payment_method": "mpesa",
    "settlement_currency": "USDT",
    "merchant_reference": "ORDER-1001"
  }
}

Test locally with the CLI

Forward live sandbox events to your local server, no public URL or deploy needed — the fastest way to build a webhook handler:

npm install -g @mavunta/cli
export MAVUNTA_SECRET_KEY=cwk_test_sk_...

mavunta listen --forward-to http://localhost:3000/webhooks/mavunta
# then, in another terminal:
mavunta trigger payment_intent.paid

listen prints a whsec_cli_…secret to verify the forwarded events with. Use the console's Sandbox tester to drive richer scenarios.

Retries and testing

A failed delivery is retried with exponential backoff for several attempts. Each endpoint has its own signing secret, which you can rotate or pause at any time (deploy the new secret first). Send a test event and inspect deliveries from the console's Sandbox tester and webhook manager.

You can also inspect and replay events over the API:

GET  /v1/webhook_events              # list events (webhooks:read)
GET  /v1/webhook_events/:id
POST /v1/webhook_events/:id/resend   # re-enqueue delivery (webhooks:write)