Guide to Fireblocks Webhooks: Features and Best Practices
Fireblocks webhooks notify your systems when digital-asset activity happens in your workspace: a transaction is created, its status changes, a vault or address is added, an approval is required. For any automation built on Fireblocks, such as crediting balances, updating ledgers, or triggering settlement, webhooks are how you react without polling the API.
This guide covers how Fireblocks webhooks work, the current v2 signature model (and where the deprecated v1 scheme now stands), how to subscribe to events, the retry and delivery behavior, and the best practices that keep a treasury or exchange integration reliable in production.
What are Fireblocks webhooks?
Fireblocks webhooks are HTTP POSTs sent to a URL you register, each carrying a JSON event describing something that changed in your workspace. Because Fireblocks sits on the critical path of moving funds, verifying that every delivery genuinely came from Fireblocks (and hasn't been tampered with) is non-negotiable.
Fireblocks does not follow the Standard Webhooks specification. It signs deliveries with its own scheme, and that scheme recently changed: webhooks v2 signs each delivery with a detached JWS you verify against Fireblocks' rotating public keys via a JWKS endpoint. The legacy v1 scheme used a static RSA public key.
Fireblocks webhook features
| Feature | Details |
|---|---|
| Configuration | Console (Developer Center) or the Webhooks v2 API |
| Event model | Subscribe per category / event type; dotted lowercase names |
| v2 signature header | Fireblocks-Webhook-Signature (detached JWS, RS512) |
| v2 key distribution | Regional JWKS endpoints, auto-rotated, Cache-Control: max-age=3600 |
| v1 signature header (legacy) | Fireblocks-Signature (RSA PKCS#1 v1.5 over SHA-512, static key) |
| Replay of events | Resend up to 30 days (v2) |
| Retry behavior | Retries on 5xx/429/408 with exponential backoff, up to 10 attempts |
| Verification target | Raw request body |
| SDKs | Manage webhooks, but ship no signature-verification helper |
The v1 to v2 signature transition
Fireblocks migrated webhook signing from a static RSA key (v1) to JWKS-distributed rotating keys (v2). During the migration, both the Fireblocks-Webhook-Signature (v2) and Fireblocks-Signature (v1) headers were sent on every delivery, and Fireblocks' documentation stated they would be sent together until March 20th, 2026. That date has passed.
The practical takeaway: build on v2 / JWKS and treat it as the current scheme. Don't write an integration that depends on the legacy Fireblocks-Signature header still being present. If you're maintaining an older integration that only checks v1, migrate it to JWKS-based verification and confirm the current header behavior in the Fireblocks Developer Center for your region before relying on it.
Common events
Fireblocks v2 event types are dotted, lowercase names grouped by category. Transaction events are the ones most integrations start with:
| Event | Fires when |
|---|---|
transaction.created | A new transaction is created in the workspace |
transaction.status.updated | A transaction moves to a new status (submitted, confirming, completed, failed, ...) |
Subscribe only to the categories and event types you need. The full v2 catalog (vault, address, and other resource events) is in the Fireblocks event reference.
Setting up Fireblocks webhooks
Configure webhooks in the Fireblocks Console under the Developer Center, or programmatically via the Webhooks v2 API. v2 adds an event catalog with subscriptions, so you opt in to specific categories or event types rather than receiving everything. It also lets you resend events for up to 30 days, which is useful for backfilling after an endpoint outage.
Your endpoint must return an HTTP 200 to acknowledge a delivery.
Securing Fireblocks webhooks
Verify the v2 detached JWS against JWKS
Each v2 delivery carries a Fireblocks-Webhook-Signature header: a detached JWS in the form header..signature (the payload segment is empty). To verify it, base64url-encode the raw request body, splice it into the middle to reconstruct a compact JWS, and verify with RS512 against the public key identified by the kid in the JWS header. A JWS library fetches and caches the right key from the JWKS endpoint for you.
import { createRemoteJWKSet, compactVerify } from "jose";
// Use the JWKS endpoint for your region:
// US prod: https://keys.fireblocks.io/.well-known/jwks.json
// EU: https://eu-keys.fireblocks.io/.well-known/jwks.json
// EU2: https://eu2-keys.fireblocks.io/.well-known/jwks.json
// Sandbox: https://sandbox-keys.fireblocks.io/.well-known/jwks.json
const JWKS = createRemoteJWKSet(
new URL("https://keys.fireblocks.io/.well-known/jwks.json")
);
async function verifyWebhook(rawBody, signatureHeader) {
try {
const [header, , sig] = signatureHeader.split("."); // detached JWS
const payload = Buffer.from(rawBody).toString("base64url");
const compact = `${header}.${payload}.${sig}`;
await compactVerify(compact, JWKS); // RS512, kid matched from JWKS
return true;
} catch {
return false;
}
}
app.post("/webhook", express.raw({ type: "application/json" }), async (req, res) => {
const signature = req.headers["fireblocks-webhook-signature"];
if (!signature || !(await verifyWebhook(req.body, signature))) {
return res.sendStatus(401);
}
const event = JSON.parse(req.body);
res.sendStatus(200); // acknowledge fast
processQueue.add(event); // process asynchronously
});
The same reconstruction in Python (using jwcrypto):
import base64
import requests
from jwcrypto import jwk, jws
JWKS_URL = "https://keys.fireblocks.io/.well-known/jwks.json"
_jwks = jwk.JWKSet.from_json(requests.get(JWKS_URL).text)
def verify_webhook(raw_body: bytes, signature_header: str) -> bool:
try:
header, _, sig = signature_header.split(".") # detached JWS
payload = base64.urlsafe_b64encode(raw_body).rstrip(b"=").decode()
token = jws.JWS()
token.deserialize(f"{header}.{payload}.{sig}")
token.verify(_jwks) # RS512, kid matched from JWKS
return True
except Exception:
return False
Cache the JWKS response (Fireblocks serves it with max-age=3600) so you're not fetching keys on every delivery, and let the library refresh when it sees an unknown kid.
The legacy v1 path
If you still need to verify the v1 Fireblocks-Signature header, it's a base64-encoded RSA PKCS#1 v1.5 signature over the SHA-512 hash of the raw body, checked against the static per-environment RSA public key published in the Fireblocks docs (separate keys for US, EU/EU2, and sandbox). This path is legacy; prefer JWKS.
Fireblocks webhook limitations and pain points
Two signature schemes during (and after) the migration
The Problem: For a long window Fireblocks sent both v1 and v2 signatures, and integrations written against either one behave differently now that the dual-send period has ended. A handler still keyed to Fireblocks-Signature alone is fragile.
Why It Happens: Fireblocks moved from a static RSA key to rotating JWKS keys and ran both in parallel to give integrators time to migrate.
Workarounds:
- Verify with v2 / JWKS and confirm the current header behavior for your region in the Developer Center.
- If you must support both, factor verification behind one interface so callers don't care which scheme ran.
How Hookdeck Can Help: Point Fireblocks at Hookdeck and verification happens at the edge, so your application receives pre-verified events and never has to track which signing scheme is currently in force.
JWKS key rotation
The Problem: v2 keys rotate automatically. An integration that fetches the JWKS once at boot and caches it forever will start failing verification the moment Fireblocks rotates to a kid it hasn't seen.
Why It Happens: Rotating keys is what makes asymmetric signing resilient, but it requires the consumer to refresh keys on cache miss.
Workarounds:
- Use a JWS library that fetches by
kidand refreshes on miss (as above). - Respect the
max-age=3600cache header rather than caching indefinitely.
How Hookdeck Can Help: Hookdeck tracks Fireblocks' rotating keys and verifies each delivery for you, so key rotation never surfaces as a verification outage in your app.
Delivery retries need idempotent handling
The Problem: Fireblocks retries failed deliveries (on 5xx, 429, and 408) with exponential backoff for up to 10 attempts, and resend lets you replay up to 30 days of events. Both mean your endpoint will see the same event more than once.
Why It Happens: Retries and resend prioritize eventual delivery over exactly-once semantics, which is the right trade-off for funds-moving events.
Workarounds:
- Make every side effect idempotent (unique constraints, upserts) keyed on the transaction or event ID.
- Track processed event IDs so a retry or resend is a no-op.
How Hookdeck Can Help: Hookdeck deduplicates deliveries at the edge and durably queues events, so retries and 30-day resends don't turn into double-processing downstream. See our guide to webhook idempotency.
Best practices
Build on v2 / JWKS
Treat JWKS-based verification as the current scheme and don't depend on the legacy Fireblocks-Signature header still being sent. Verify the detached JWS against the raw body, matching the kid to a JWKS key.
Verify against the raw body
Reconstruct the compact JWS from the exact bytes Fireblocks sent. Parsing and re-serializing the JSON first will change the payload and break verification.
Refresh JWKS on unknown key IDs
Cache keys per the max-age=3600 header, and let your library fetch fresh keys when it encounters a kid it doesn't have.
Acknowledge fast, process asynchronously
Return 200 quickly and hand the event to a queue. Slow handlers become retries, and retries become duplicates. See why to process webhooks asynchronously.
Process idempotently and use resend for recovery
Dedupe on the event or transaction ID so retries and 30-day resends are safe, and use resend to backfill after an outage rather than treating a missed webhook as unrecoverable.
Make Fireblocks webhooks production-ready
Hookdeck verifies the v2 JWKS signature, deduplicates, and durably queues every transaction event
Conclusion
Fireblocks webhooks put digital-asset activity on a push channel your automation can trust, but only if you verify every delivery correctly. The current model is a detached JWS signed with RS512 and verified against rotating keys from a regional JWKS endpoint; the older static-RSA v1 scheme was sent alongside it only until its March 2026 cutoff. On top of verification, you own deduplication for retries and 30-day resends, fast acknowledgement, and key-rotation handling.
For teams moving real value on Fireblocks, that operational surface is exactly where mistakes are expensive. Hookdeck verifies the JWKS signature, deduplicates, and durably queues every event at the edge, so your systems only ever act on verified, de-duplicated transaction events.
Get started with Hookdeck for free and handle Fireblocks webhooks reliably in minutes.