packages/twenty-apps/internal/twenty-fireflies/README.md
Sync Fireflies call transcripts and AI summaries onto
the matching CalendarEvent in your Twenty CRM — searchable, in context, and
ready for AI agents and workflows to act on. Plus on-demand workflow tools to
sync, list, and search Fireflies calls from the AI chat or workflow builder.
meeting.transcribed
webhook; once Fireflies finishes its AI summary, it fires a separate
meeting.summarized webhook.CalendarEvent in Twenty and writes the content
into either the Transcript or Summary field on that event.Alongside the webhook, three Workflow tools let you trigger Fireflies actions from the AI chat or as steps inside a workflow, without waiting for Fireflies to push.
The matcher tries two provider-ID strategies in priority order and stops at the first hit:
calendar_id / cal_id is
matched against CalendarChannelEventAssociation.eventExternalId. Covers
events synced into Twenty from Google Calendar (including individual
instances of recurring events, where Fireflies returns the per-instance
id with timestamp on cal_id).calendar_id is matched against
CalendarEvent.iCalUid. Covers events synced from Outlook / CalDAV,
where Fireflies returns the RFC 5545 iCalUID directly.Both identifiers are populated by Twenty's calendar drivers on every synced CalendarEvent, so any meeting that's been pulled in via Google / Outlook / CalDAV calendar sync will match exactly. The matcher does not fall back to fuzzy URL matching — if the transcript can't be tied to a synced calendar event, the call is treated as an orphan and skipped (see Limitations below). This avoids silently writing transcripts to the wrong event.
Two new fields on the standard CalendarEvent object:
Plus three workflow tools — see Workflow tools below.
Once the API key is configured, three tools become available in the workflow builder and the AI chat — covering the cases the webhook can't:
01HXYZ... onto its
CalendarEvent now". As a workflow step: provide transcriptId. Runs the
same pipeline as the webhook (fetch transcript + AI summary, find matching
CalendarEvent, write Transcript + Summary fields) on demand. Use cases:
backfilling historical calls that happened before the app was
installed; recovering from a missed webhook (e.g. the calendar event
hadn't synced yet when Fireflies pushed); or triggering a sync from a
workflow instead of waiting for Fireflies. Output includes
calendarEventId, updatedFields, and a per-field outcome breakdown so
partial successes are visible.participantEmail (and
optional limit, max 50). Returns recent Fireflies calls — newest first —
where that email was an attendee, with title, date, duration, host, and
transcript URL. The natural first step in workflows triggered on
Person.created — "find what we've talked about with this contact".keyword (and optional limit, max 50).
Matches the keyword against both meeting titles and the words actually
spoken in meetings. Returns the same call-summary shape as the
participant tool. Best for AI-chat-driven research.The list-by-participant and search tools return the same compact call shape:
id, title, date, durationMinutes, participants, hostEmail,
transcriptUrl, meetingLink. To then sync any of those calls onto its
CalendarEvent, pass the id from a list result into Sync Fireflies Call.
Heads up: if you see "Fireflies is not configured" on the first webhook, your Twenty admin needs to follow the Self-hosting setup section.
What this connector intentionally does not support in v1:
| Symptom | Likely cause | Fix |
|---|---|---|
Webhook returns Fireflies is not configured | FIREFLIES_API_KEY not set | Admin: paste the API key in Settings → Applications → Fireflies → Settings |
Webhook returns Invalid webhook signature | FIREFLIES_WEBHOOK_SECRET mismatch between Fireflies and Twenty | Re-copy the signing secret from the Fireflies webhook configuration and paste it into the Twenty app settings |
Webhook returns skipped: No CalendarEvent matched the transcript by external ID or iCalUid | The meeting was never on a synced calendar in Twenty, or the workspace has no Google/Outlook/CalDAV calendar connection set up | Connect the relevant calendar provider in Settings → Accounts so the calendar event lands in Twenty with eventExternalId and iCalUid populated. Manually-created CalendarEvents are intentionally not matched in v1 |
| Transcript appears empty | Fireflies returned no sentences (call too short, audio failed) | Check the call in the Fireflies dashboard; nothing this app can do |
| Summary appears empty | Fireflies hasn't summarized the call yet, or the call was too short to summarize | Fireflies sends meeting.summarized separately from meeting.transcribed (typically a minute or two later); ensure that event is subscribed to in your Webhooks V2 config |
| Summary is populated but Transcript isn't (or vice versa) | Only one of the two Fireflies events is subscribed to | Subscribe to both meeting.transcribed and meeting.summarized in your Fireflies Webhooks V2 configuration |
Fireflies API errors with 401 | API key wrong, rotated, or revoked | Generate a new key in Fireflies → Integrations → Fireflies API → Regenerate, then update FIREFLIES_API_KEY |
Sync Fireflies Call reports No fields were updated | The Fireflies call's calendar_id / cal_id doesn't match any CalendarEvent's iCalUid or eventExternalId (orphan call), or the per-field outcomes show transient Fireflies API failures | Check the fieldOutcomes array in the result — skipped means orphan call (same limitation as the webhook); error means Fireflies-side failure (retry, or inspect the error message) |
List / Search tools return count: 0 for a contact you've definitely talked to | Email mismatch — Fireflies stores the address as the participant joined the meeting with, which may differ from the contact's primary address in Twenty (aliases, plus-addressing, work vs. personal) | Try the contact's other known email addresses; cross-check the participants list on a known matching call |
This section is for Twenty server admins. If you're on Twenty Cloud, skip this — the credentials may already be configured.
This integration targets Fireflies Webhooks V2
(snake_case payload, granular event subscriptions). The legacy V1 webhook
format (meetingId / eventType: "Transcription completed") is not
supported.
https://<your-twenty-domain>/webhook/fireflies. Twenty resolves the
target workspace from the request's Host header, so the URL must match
the workspace's public domain — localhost is not valid in the
Fireflies UI. For local development, expose your dev server with a
tunnel like ngrok http 3000 and paste the HTTPS forwarding URL here,
or skip the Fireflies UI entirely and POST a signed payload directly to
your local endpoint (see Local webhook testing
in the developer section below).openssl rand -hex 32). Save it; you'll paste it into Twenty next.meeting.transcribed — fires when the transcript is ready and
writes it to the Transcript field.meeting.summarized — fires once Fireflies finishes its AI summary
and writes it to the Summary field.
Subscribing to only one is fine if you don't want the other field
populated; the app dispatches per event.FIREFLIES_API_KEY row.FIREFLIES_WEBHOOK_SECRET row.After saving, the next time Fireflies finishes processing a recording, the transcript will land on the matching CalendarEvent within a few seconds; the summary follows once Fireflies finishes the AI summarization step (typically a minute or two later — Fireflies sends two separate webhooks).
transcript / summary fields on CalendarEvent instead of a new object?Storing the transcript and AI summary as rich-text fields directly on the
existing CalendarEvent:
If later integrations (Gong, Otter, Zoom AI, etc.) make one pair of fields too restrictive — for example, needing to distinguish which tool produced the transcript — we'll promote the fields to a platform-level concept rather than keep extending this app.
If you're working on this app rather than installing the published version:
cd packages/twenty-apps/internal/twenty-fireflies
# Day-to-day development (publish + install + watch in one):
yarn twenty dev
# Run unit tests:
yarn test
# Lint:
yarn lint
twenty dev is recommended for iteration — it publishes to your local Twenty
server, installs the app, and watches for changes in one command.
The Fireflies GraphQL API is called directly via fetch — no fireflies SDK
dependency. See src/logic-functions/utils/fireflies-api-request.ts for the
auth + error-handling wrapper that all queries go through.
Fireflies' Webhooks V2 UI only accepts a publicly reachable HTTPS URL, so
pointing it at http://localhost:* directly is not possible. Two paths:
End-to-end via tunnel. Run a tunnel that fronts your local server with
a public HTTPS URL (ngrok http 3000, cloudflared tunnel, etc.), paste
the HTTPS forwarding URL into the Fireflies webhook UI as the Webhook
URL, and exercise the integration by ending a real Fireflies meeting.
Backend-only via signed curl. Skip the Fireflies UI entirely and POST
a signed payload straight to the local endpoint. The signature must be
HMAC-SHA256 over the raw request body, keyed by your
FIREFLIES_WEBHOOK_SECRET, prefixed with sha256=:
export FIREFLIES_WEBHOOK_SECRET='<the secret you set in Twenty app settings>'
BODY='{"event":"meeting.transcribed","meeting_id":"<a-real-fireflies-transcript-id>"}'
SIG=$(printf '%s' "$BODY" \
| openssl dgst -sha256 -hmac "$FIREFLIES_WEBHOOK_SECRET" \
| awk '{print $NF}')
curl -X POST http://localhost:3000/webhook/fireflies \
-H 'Content-Type: application/json' \
-H "x-hub-signature: sha256=$SIG" \
--data-binary "$BODY"
--data-binary (not --data) is important: it preserves the bytes
verbatim so the HMAC the server computes matches the one openssl
computed above. Twenty resolves the workspace from the Host header, so
the default dev workspace (mapped to localhost:3000 in a standard
yarn start setup) receives the request.
To match a real CalendarEvent, the transcript ID you pass must belong to
a Fireflies call whose calendar_id / cal_id matches an existing
CalendarEvent.iCalUid or CalendarChannelEventAssociation.eventExternalId
in your local Twenty workspace. The easiest local seed is to manually
insert a row with one of those identifiers and use a Fireflies transcript
whose calendar fields point at it.