Guide to Fireflies Webhooks: Features and Best Practices
Fireflies webhooks notify your application when a meeting is transcribed or summarized, so you can pull the transcript, summary, and metadata into your own systems. If you're building on Fireflies, webhooks are how you react to meeting activity without polling.
This guide covers how Fireflies webhooks work, the events you'll handle, how to verify the X-Hub-Signature, the optional signing behavior, and the best practices for production.
What are Fireflies webhooks?
Fireflies webhooks are HTTP POSTs delivered to a URL you configure, sent when a meeting is transcribed (and for related events). Real deliveries use the V2 scheme, an X-Hub-Signature header with a sha256= prefix. (The older V1 scheme is deprecated, and its creation path is being removed from the dashboard; this guide covers V2, which is what you actually receive.)
Fireflies signs V2 deliveries with an X-Hub-Signature header: sha256= followed by a lowercase-hex HMAC-SHA256 of the request body, keyed with the secret you configure. Signing is optional: if you don't set a secret, deliveries arrive with no signature header at all.
Fireflies webhook features
| Feature | Details |
|---|---|
| Configuration | Dashboard Settings > Developer Settings, or per-upload webhook in the uploadAudio mutation |
| Signature header | X-Hub-Signature, formatted sha256=<hex> |
| Signature scheme | lowercase-hex HMAC-SHA256 over the body, keyed with the configured secret |
| Signing | Optional, no secret set means no signature header |
| Delivery id | x-webhook-delivery-id (on test and real deliveries) |
| Payload | snake_case: event, meeting_id |
| Events | meeting.transcribed, meeting.summarized, meeting.bot_joined |
| Acknowledgement | 2xx within 10 seconds |
| SDK | None |
Common events
Fireflies V2 event names are snake_case and dotted:
| Event | Fires when |
|---|---|
meeting.transcribed | A meeting's transcription finishes processing |
meeting.summarized | A meeting's summary is ready |
meeting.bot_joined | The notetaker bot joins a meeting |
The payload is compact JSON with event and meeting_id. On receipt, use meeting_id to fetch the transcript, summary, and details via the Fireflies GraphQL API. Branch on the dotted event name.
Setting up Fireflies webhooks
Configure the endpoint URL (and an optional signing secret) under Settings > Developer Settings in the Fireflies dashboard, or pass a webhook URL per upload in the uploadAudio GraphQL mutation.
Setting a secret is what turns signing on: with no secret, deliveries are unsigned; once you set one, the same event starts arriving with an X-Hub-Signature header. Set a secret so you can verify.
Securing Fireflies webhooks
Each signed delivery carries an X-Hub-Signature header: sha256= followed by a lowercase-hex HMAC-SHA256 of the request body, keyed with your configured secret. Recompute it over the raw body and compare in constant time. Fireflies sends compact JSON, and verifying against the raw body works, so capture the raw bytes before any JSON middleware parses them.
const crypto = require("crypto");
const SECRET = process.env.FIREFLIES_WEBHOOK_SECRET;
function verify(rawBody, signatureHeader) {
const expected = "sha256=" +
crypto.createHmac("sha256", SECRET).update(rawBody).digest("hex");
const a = Buffer.from(expected);
const b = Buffer.from(signatureHeader || "");
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
app.post("/webhook", express.raw({ type: "application/json" }), (req, res) => {
// If you've set a secret, require a valid signature (no header = unsigned)
if (!verify(req.body, req.headers["x-hub-signature"])) {
return res.sendStatus(401);
}
res.sendStatus(200); // acknowledge within 10s
const { event, meeting_id } = JSON.parse(req.body);
processQueue.add({
event,
meeting_id,
deliveryId: req.headers["x-webhook-delivery-id"], // dedupe on this
});
});
The same check in Python:
import hashlib
import hmac
import os
SECRET = os.environ["FIREFLIES_WEBHOOK_SECRET"].encode()
def verify(raw_body: bytes, signature_header: str) -> bool:
expected = "sha256=" + hmac.new(SECRET, raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature_header or "")
Fireflies webhook limitations and pain points
Signing is optional
The Problem: With no secret configured, deliveries carry no X-Hub-Signature header at all, so an endpoint that assumes a signature either can't verify or (worse) accepts anything. Setting a secret switches signing on.
Why It Happens: Fireflies makes the signing secret opt-in.
Workarounds:
- Set a secret, and reject deliveries without a valid
X-Hub-Signature; keep the endpoint URL secret and HTTPS-only.
How Hookdeck Can Help: Hookdeck gives you a dedicated ingestion URL and can enforce its own verification in front of your endpoint, so an unsigned Fireflies webhook isn't your only line of defense.
V1 is deprecated
The Problem: Older docs and examples describe a V1 scheme (x-hub-signature, bare hex, a "Transcription completed" event). Real deliveries are V2 (X-Hub-Signature, sha256= prefix, dotted snake_case events), and the V1 creation path is being removed from the dashboard. Building against V1 means the wrong header format and event names.
Why It Happens: Fireflies moved to V2 and is retiring V1.
Workarounds:
- Target V2: strip the
sha256=prefix when comparing, and branch onmeeting.transcribedand friends.
How Hookdeck Can Help: Hookdeck verifies the V2 signature at the edge, so your app receives pre-verified events without version-specific handling.
Thin payload requires an API fetch
The Problem: The payload carries only event and meeting_id, so you fetch the transcript and details from the GraphQL API for anything useful.
Why It Happens: Fireflies keeps the payload compact.
Workarounds:
- Acknowledge fast, then fetch the transcript via the API using
meeting_idoff a queue.
How Hookdeck Can Help: Hookdeck durably queues each event so your worker fetches transcripts at a controlled rate.
Duplicates and the 10-second window
The Problem: You must return a 2xx within 10 seconds, and the same event can arrive more than once, so slow processing risks the window and duplicates double-process.
Why It Happens: Fireflies caps the ack time, and delivery is at-least-once.
Workarounds:
- Acknowledge fast and process asynchronously; dedupe on
x-webhook-delivery-id(present on test and real deliveries).
How Hookdeck Can Help: Hookdeck acknowledges within the window, deduplicates on the delivery id, and durably queues events. See our guide to webhook idempotency.
Best practices
Set a secret and verify sha256= over the raw body
Configure a signing secret, compute sha256= + lowercase-hex HMAC-SHA256 over the raw body, and compare in constant time. Reject deliveries with no valid signature.
Target V2
Use the V2 X-Hub-Signature (sha256=) scheme and the dotted snake_case event names; V1 is deprecated.
Acknowledge within 10 seconds, fetch asynchronously
Return 200 immediately and fetch the transcript via the API using meeting_id off a queue. See why to process webhooks asynchronously.
Dedupe on the delivery id
Use x-webhook-delivery-id as an idempotency key so retries don't double-process.
Make Fireflies webhooks production-ready
Hookdeck verifies X-Hub-Signature, deduplicates, and durably queues every meeting event
Conclusion
Fireflies V2 webhooks fire on meeting.transcribed and related events, verified with an X-Hub-Signature (sha256= + lowercase hex) HMAC over the raw body with a secret you configure, signing is optional, so set a secret to get a signature at all. Target V2 (V1 is deprecated), verify against the raw body, acknowledge within 10 seconds, and dedupe on x-webhook-delivery-id.
Hookdeck verifies the signature, deduplicates, and durably queues every event at the edge, so your app only ever processes verified, unique meeting events.
Get started with Hookdeck for free and handle Fireflies webhooks reliably in minutes.