wallet.top_up
Fires when a top-up payment clears and credits are added to the workspace wallet.
wallet.top_up fires when a top-up payment is confirmed by M-Pesa and the credit is applied to the workspace wallet. Use this event to refresh balance displays and clear any low-balance alerts in your own systems.
This event is subscribable via workspace webhooks (POST /v1/webhooks).
{
"kind": "wallet.top_up",
"event_id": "01900000-0000-7000-8000-000000000001",
"workspace_id": "01900000-0000-7000-8000-000000000002",
"occurred_at": "2026-06-27T10:00:00.000Z",
"data": {
"topup_id": "01900000-0000-7000-8000-000000000003",
"amount_minor": 50000,
"currency": "KES",
"new_balance_minor": 150000,
"provider": "mpesa",
"provider_reference": "LGR5KZN81B"
}
}Every webhook delivery includes the following request headers:
| Header | Description |
|---|---|
X-Sautikit-Signature | HMAC-SHA256 of the raw body, hex-encoded. Verify with your subscription secret. |
X-Sautikit-Idempotency-Key | Unique delivery ID for deduplication. |
X-Sautikit-Event | Literal event kind: wallet.top_up. |
event_id or the X-Sautikit-Idempotency-Key header.dead_letter.import { createHmac } from "node:crypto";
export async function POST(req) {
const sig = req.headers["x-sautikit-signature"];
const body = await req.text();
const expected = createHmac("sha256", process.env.WEBHOOK_SECRET)
.update(body)
.digest("hex");
if (sig !== expected) return new Response("Forbidden", { status: 403 });
const event = JSON.parse(body);
if (event.kind === "wallet.top_up") {
const { amount_minor, currency, new_balance_minor } = event.data;
console.log(`Wallet topped up: ${amount_minor / 100} ${currency}, new balance: ${new_balance_minor / 100}`);
// clear low-balance alert, update UI...
}
return new Response("OK", { status: 200 });
}events: ["wallet.top_up"].wallet.low_balance to build a balance management workflow.