Documentation Index
Fetch the complete documentation index at: https://developers.bloobank.com/llms.txt
Use this file to discover all available pages before exploring further.
Proposed scheme. The signature format below follows industry conventions (Stripe, GitHub). Concrete header names and the HMAC secret rotation flow will be confirmed with the BlooBank platform team before this scheme exits “Proposed” status.
The scheme
HMAC-SHA256 over a deterministic signed payload, transmitted in theX-Bloobank-Signature header.
The signed payload
| Field | Source |
|---|---|
{timestamp} | The value of the X-Bloobank-Timestamp header (Unix epoch in milliseconds). |
{rawBody} | The exact raw bytes of the request body. |
. is the literal ASCII period separator. The whole string is UTF-8 encoded.
The signature header
X-Bloobank-Signature carries one or more signatures, comma-separated, each prefixed with a version label:
| Element | Meaning |
|---|---|
t=... | Unix epoch in milliseconds — mirrors X-Bloobank-Timestamp. |
v1=... | HMAC-SHA256 hex digest, signed with the webhook secret. |
v2=... for migration; your verifier should accept any version it understands and reject the delivery if none match.
The webhook secret
The webhook signing secret is generated by BlooBank when you configure an endpoint. It is a high-entropy random string (≥ 32 bytes, base64-encoded) shown once in the Dashboard. Copy it into your secret manager and never expose it. Each endpoint configuration has its own secret. Rotating the secret produces a new value while the old one is briefly accepted in parallel — see Rotation below.Verification — the algorithm
Read the headers and raw body
Capture
X-Bloobank-Timestamp, X-Bloobank-Signature, and the raw bytes of the request body — do not re-parse and re-serialize.Parse the signature header
Split by
,, then by = for each part. Extract the t= timestamp and every vN= signature.Verify the timestamp
The header timestamp must be within ±5 minutes of your server’s current time. Reject older deliveries — they are stale (probably replays).
Constant-time compare
Compare each
vN from the header to your expected using a constant-time comparison function (crypto.timingSafeEqual in Node, hmac.compare_digest in Python, etc.). If any matches, the signature is valid.Code
Rotation
Webhook secrets should be rotated periodically. The flow:Request rotation in the Dashboard
Generates a new secret. Both old and new secrets are valid for a configurable overlap window (default 24 hours).
During the overlap, BlooBank signs with both
Deliveries during the window carry two
v1=... signatures — one signed with the old secret, one with the new. Your verifier accepts either.What can go wrong
| Failure | Cause | Action |
|---|---|---|
| Signature mismatch | Body re-parsed and re-serialized between read and verify. | Pass the raw bytes to the verifier. Do not let middleware decode the JSON before you verify. |
| Timestamp drift | Server clock more than ±5 minutes off. | Enable NTP. |
| Stale replay attack | Attacker captures a delivery and resends hours later. | The ±5-minute timestamp check rejects this. |
| Constant-time bypass | Using == or string.equals. | Always use the platform’s constant-time compare. |
| Secret leaked in logs | Including the secret in error messages. | Never log the secret; log only the result (ok/fail). |
Next
Retry & delivery
The delivery contract.
Best practices
Idempotency, ordering, deduplication.
Payment events
Event catalog.