Skip to main content
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.
Every webhook delivery is signed. Verify the signature before processing the payload — an unverified webhook is an attack surface.

The scheme

HMAC-SHA256 over a deterministic signed payload, transmitted in the X-Bloobank-Signature header.

The signed payload

The . 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:
Future scheme versions may add 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

1

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.
2

Parse the signature header

Split by ,, then by = for each part. Extract the t= timestamp and every vN= signature.
3

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).
4

Compute the expected HMAC

expected = HMAC_SHA256_hex(secret, "{timestamp}.{rawBody}")
5

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.
6

Reject otherwise

Return 401 Unauthorized (without a body). Do not log the body, do not process the event.

Code

Rotation

Webhook secrets should be rotated periodically. The flow:
1

Request rotation in the Dashboard

Generates a new secret. Both old and new secrets are valid for a configurable overlap window (default 24 hours).
2

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.
3

Update your secret manager

Replace the old secret with the new one before the overlap window ends.
4

After the window expires, the old secret is invalidated

Only the new secret signs subsequent deliveries.
To support rotation client-side without downtime, your verifier should accept multiple secrets — try each, accept on first match. During steady-state operation, you hold one secret; during rotation, two.

What can go wrong

Next

Retry & delivery

The delivery contract.

Best practices

Idempotency, ordering, deduplication.

Payment events

Event catalog.