Use Blnk webhooks to reliably react to ledger events and keep your product in sync—without polling the API.
Global webhooks are available in version 0.8.4 and later. Signed deliveries require version 0.13.0 and later.
Blnk sends webhook events to your HTTP endpoints in real time. Your code reacts when a transaction is created, committed, voided, or when a reconciliation completes.This is critical in financial systems where timing matters. Polling risks gaps: you might miss a window between checks, or waste resources on empty requests.Webhooks push the exact event to you the moment it happens, so your balances, notifications, and downstream workflows stay accurate and in sync.
Instead of asking Blnk “did anything change?” on a timer, your app listens once and reacts when the ledger moves, keeping your product and tools like payments, notifications, etc. aligned.
Blnk signs outbound webhook requests so you can verify they came from your Blnk Core and were not tampered with.Both global webhooks and transaction hooks use the same signing scheme.
Header
Description
X-Blnk-Signature
Hex-encoded HMAC-SHA256 of the signed payload.
X-Blnk-Timestamp
Unix timestamp in seconds (string), used in the signed payload and for replay protection.
X-Hook-ID
The hook identifier (transaction hooks only).
X-Hook-Type
PRE_TRANSACTION or POST_TRANSACTION (transaction hooks only).
To verify a webhook:
1
Extract headers and raw body
Read X-Blnk-Signature and X-Blnk-Timestamp from the request. Reject requests missing either header.
Preserve the exact raw bytes of the request body before JSON parsing. Do not use a parsed or re-serialized body—any whitespace or encoding changes will cause verification to fail.
2
Build signed payload
Concatenate the timestamp and raw body:
signed = timestamp + "." + rawRequestBody
3
Compute expected signature
Compute HMAC-SHA256 using server.secret_key from your Blnk configuration, then hex-encode:
expected = hex( HMAC-SHA256(secret_key, signed) )
4
Compare signatures
Compare expected to X-Blnk-Signature using a constant-time comparison (e.g. crypto.timingSafeEqual in Node.js). If they match, the webhook is authentic.
For replay protection, also reject timestamps outside a small window (e.g. ±5 minutes).
import express from "express";import crypto from "crypto";const app = express();const SECRET = process.env.BLNK_SECRET; // must match server.secret_keyapp.use(express.json({ verify: (req, _, buf) => { req.rawBody = buf; } }));app.post("/webhook", (req, res) => { const sig = req.header("x-blnk-signature"); const ts = req.header("x-blnk-timestamp"); if (!sig || !ts) return res.sendStatus(400); const expected = crypto.createHmac("sha256", SECRET) .update(`${ts}.${req.rawBody}`) .digest("hex"); if (!crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) return res.sendStatus(401); res.sendStatus(200);});app.listen(3000);
We are very happy to help you make the most of Blnk, regardless of whether it is your first time or you are switching from another tool.To ask questions or discuss issues, please contact us or join our Discord community.