Complete Fireflies integration skill pack with 24 skills covering meeting transcription, AI summaries, and conversation intelligence. Flagship tier vendor pack.
Installation
Open Claude Code and run this command:
/plugin install fireflies-pack@claude-code-plugins-plus
Use --global to install for all projects, or --project for current project only.
Skills (24)
Configure CI/CD pipelines for Fireflies.
Fireflies.ai CI Integration
Overview
Set up CI/CD pipelines for Fireflies.ai integrations: GraphQL query validation, mock-based unit tests, and optional live API integration tests with rate limit awareness.
Prerequisites
- GitHub repository with Actions enabled
- Fireflies.ai test API key (for integration tests)
- Vitest test suite configured
Instructions
Step 1: GitHub Actions Workflow
# .github/workflows/fireflies-tests.yml
name: Fireflies Integration Tests
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
unit-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
- run: npm ci
- run: npm test -- --coverage
- name: Upload coverage
uses: actions/upload-artifact@v4
with:
name: coverage
path: coverage/
integration-tests:
runs-on: ubuntu-latest
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
needs: unit-tests
environment: staging
env:
FIREFLIES_API_KEY: ${{ secrets.FIREFLIES_API_KEY_TEST }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
- run: npm ci
- name: Run integration tests
run: npm run test:integration
timeout-minutes: 5
Step 2: Store Secrets
set -euo pipefail
# Store test API key as GitHub secret
gh secret set FIREFLIES_API_KEY_TEST --body "your-test-api-key"
# For production deployments
gh secret set FIREFLIES_API_KEY_PROD --env production --body "your-prod-key"
gh secret set FIREFLIES_WEBHOOK_SECRET --env production --body "your-webhook-secret"
Step 3: Unit Tests with Mocks
// tests/fireflies-client.test.ts
import { describe, it, expect, vi, beforeEach } from "vitest";
// Mock fetch globally
const mockFetch = vi.fn();
vi.stubGlobal("fetch", mockFetch);
describe("Fireflies GraphQL Client", () => {
beforeEach(() => {
vi.clearAllMocks();
process.env.FIREFLIES_API_KEY = "test-key";
});
it("should send correct auth header", async () => {
mockFetch.mockResolvedValue({
json: () => Promise.resolve({ data: { user: { email: "test@co.com" } } }),
});
const { FirefliesClient } = await import("../src/lib/fireflies-client");
const client = new FirefliesClient("test-key");
await client.query("{ user { email } }");
expect(mockFetch).toHaveBeenCalledWith(
"https://api.fireflies.ai/graphql",
expDiagnose and fix Fireflies.
Fireflies.ai Common Errors
Overview
Quick reference for all Fireflies.ai GraphQL API error codes with root causes and fixes.
Error Response Format
All Fireflies errors follow this GraphQL error structure:
{
"errors": [{
"message": "Human-readable description",
"code": "error_code",
"friendly": true,
"extensions": {
"status": 400,
"helpUrls": ["https://docs.fireflies.ai/..."]
}
}]
}
Error Code Reference
auth_failed (401)
Message: Invalid or missing API key.
# Verify API key is set and valid
echo "Key set: ${FIREFLIES_API_KEY:+YES}"
# Test authentication
set -euo pipefail
curl -s -X POST https://api.fireflies.ai/graphql \
-H "Authorization: Bearer $FIREFLIES_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "{ user { email } }"}' | jq .
Fix: Regenerate API key at app.fireflies.ai > Integrations > Fireflies API.
toomanyrequests (429)
Message: Rate limit exceeded.
| Plan | Limit |
|---|---|
| Free / Pro | 50 requests per day |
| Business / Enterprise | 60 requests per minute |
Fix: Implement exponential backoff. See fireflies-rate-limits skill.
requireaicredits (402)
Message: AskFred operations require AI credits.
Fix: Visit Fireflies dashboard > Upgrade section to purchase AI credits. Budget for createAskFredThread and continueAskFredThread calls.
account_cancelled (403)
Message: Subscription inactive.
Fix: Renew your Fireflies subscription or switch to a different API key.
invalidlanguagecode (400)
Message: Unsupported language code in uploadAudio or addToLiveMeeting.
Fix: Use ISO 639-1 codes (e.g., en, es, de, fr, ja). Max 5 characters.
unsupported_platform (400)
Message: Meeting platform not recognized by addToLiveMeeting.
Fix: Fireflies supports Google Meet, Zoom, and Microsoft Teams. Verify the meeting_link is a valid URL for one of these platforms.
payloadtoosmall (400)
Message: Uploaded audio file is below 50KB minimum.
<Retrieve and process Fireflies.
Fireflies.ai Core Workflow A -- Transcript Retrieval & Processing
Overview
Primary workflow for Fireflies.ai: fetch meeting transcripts via GraphQL, process speaker-diarized sentences, extract action items and summaries, and route meeting intelligence downstream.
Prerequisites
- Completed
fireflies-install-authsetup FIREFLIESAPIKEYset with Business+ plan for full access- At least one completed meeting in Fireflies
Instructions
Step 1: Build the GraphQL Client
// lib/fireflies.ts
const FIREFLIES_API = "https://api.fireflies.ai/graphql";
export async function firefliesQuery<T = any>(
query: string,
variables?: Record<string, any>
): Promise<T> {
const res = await fetch(FIREFLIES_API, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.FIREFLIES_API_KEY}`,
},
body: JSON.stringify({ query, variables }),
});
const json = await res.json();
if (json.errors) {
const err = json.errors[0];
throw new Error(`Fireflies API error: ${err.message} (${err.code || "unknown"})`);
}
return json.data;
}
Step 2: List Transcripts with Filters
const LIST_TRANSCRIPTS = `
query ListTranscripts(
$limit: Int,
$mine: Boolean,
$fromDate: DateTime,
$toDate: DateTime,
$organizers: [String],
$participants: [String]
) {
transcripts(
limit: $limit
mine: $mine
fromDate: $fromDate
toDate: $toDate
organizers: $organizers
participants: $participants
) {
id title date duration
organizer_email participants
summary { overview action_items keywords }
}
}
`;
// Fetch this week's meetings for a specific organizer
const data = await firefliesQuery(LIST_TRANSCRIPTS, {
limit: 20,
fromDate: "2026-03-15T00:00:00Z",
organizers: ["alice@company.com"],
});
Step 3: Fetch Full Transcript with Sentences
const GET_TRANSCRIPT = `
query GetTranscript($id: String!) {
transcript(id: $id) {
id title date duration
organizer_email
speakers { id name }
sentences {
index
speaker_name
speaker_id
text
raw_text
start_time
end_time
ai_filters {
task
question
sentiment
pricing
metric
date_and_time
}
}
summary {
overview
short_summary
bullet_gist
action_items
keywords
outline
topics_discussed
}
meeting_attendees { displayName email }
meeting_attendance { name join_time leave_time }
analytics {
senSearch across Fireflies.
Fireflies.ai Core Workflow B -- Search, AskFred & Analytics
Overview
Secondary workflow: search across transcripts with keyword and date filters, use AskFred AI for natural language Q&A over meetings, and aggregate meeting analytics for reporting.
Prerequisites
- Completed
fireflies-install-authsetup - Familiarity with
fireflies-core-workflow-a - AI credits for AskFred queries (check Fireflies dashboard)
Instructions
Step 1: Search Transcripts by Keyword
const SEARCH_TRANSCRIPTS = `
query SearchMeetings(
$keyword: String,
$fromDate: DateTime,
$toDate: DateTime,
$participants: [String],
$limit: Int
) {
transcripts(
keyword: $keyword
fromDate: $fromDate
toDate: $toDate
participants: $participants
limit: $limit
) {
id title date duration
organizer_email
participants
summary { overview action_items keywords }
}
}
`;
// Search for "quarterly review" in the last 30 days
const results = await firefliesQuery(SEARCH_TRANSCRIPTS, {
keyword: "quarterly review",
fromDate: new Date(Date.now() - 30 * 86400000).toISOString(),
limit: 20,
});
console.log(`Found ${results.transcripts.length} matching meetings`);
for (const t of results.transcripts) {
console.log(` ${t.title} (${t.date}) - ${t.duration}min`);
}
Step 2: AskFred -- AI Q&A Over a Single Meeting
// Create a new AskFred thread tied to a transcript
const CREATE_THREAD = `
mutation CreateThread($input: CreateAskFredThreadInput!) {
createAskFredThread(input: $input) {
id
title
messages {
id
answer
suggested_queries
}
}
}
`;
const thread = await firefliesQuery(CREATE_THREAD, {
input: {
query: "What were the key decisions made in this meeting?",
transcript_id: "your-transcript-id",
},
});
console.log("Fred says:", thread.createAskFredThread.messages[0].answer);
console.log("Suggested follow-ups:", thread.createAskFredThread.messages[0].suggested_queries);
Step 3: AskFred -- Continue a Conversation
const CONTINUE_THREAD = `
mutation ContinueThread($thread_id: String!, $query: String!) {
continueAskFredThread(thread_id: $thread_id, query: $query) {
id
answer
suggested_queries
}
}
`;
const followUp = await firefliesQuery(CONTINUE_THREAD, {
thread_id: thread.createAskFredThread.id,
query: "Who is responsible for the action items?",
});
console.log("Follow-up:", followUp.continueAskFredThread.answer);
Step 4: AskFred -- Cross-Meeting Analysis
// Query across multiple meetings (no transcript_id = searches all)
coOptimize Fireflies.
Fireflies.ai Cost Tuning
Overview
Optimize Fireflies.ai subscription costs. Fireflies charges per-seat per month. The main levers: remove unused seats, configure selective recording, manage storage, and right-size your plan tier.
Pricing Reference
| Plan | Price | API Access | Key Features |
|---|---|---|---|
| Free | $0 | 50 req/day | 800 min storage, limited transcription |
| Pro | ~$18/seat/month | 50 req/day | 8,000 min/seat, AI summaries |
| Business | ~$29/seat/month | 60 req/min | Unlimited transcription, CRM, analytics |
| Enterprise | Custom | 60 req/min | SSO, Super Admin webhooks, custom |
Instructions
Step 1: Audit Seat Utilization via API
set -euo pipefail
# List all workspace users with their transcript counts
curl -s -X POST https://api.fireflies.ai/graphql \
-H "Authorization: Bearer $FIREFLIES_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "{ users { name email user_id num_transcripts minutes_consumed } }"}' \
| jq '.data.users | sort_by(.num_transcripts) | .[] | {name, email, transcripts: .num_transcripts, minutes: .minutes_consumed}'
// Automated utilization report
async function seatUtilizationReport() {
const data = await firefliesQuery(`{
users {
name email user_id
num_transcripts minutes_consumed
recent_meeting
}
}`);
const users = data.users;
const inactive = users.filter((u: any) => u.num_transcripts < 2);
const active = users.filter((u: any) => u.num_transcripts >= 2);
console.log(`Total seats: ${users.length}`);
console.log(`Active (2+ transcripts): ${active.length}`);
console.log(`Inactive (<2 transcripts): ${inactive.length}`);
console.log(`Potential savings: ${inactive.length} seats * $29/mo = $${inactive.length * 29}/mo`);
if (inactive.length > 0) {
console.log("\nInactive seats to review:");
for (const u of inactive) {
console.log(` ${u.email}: ${u.num_transcripts} transcripts, last meeting: ${u.recent_meeting || "never"}`);
}
}
return { total: users.length, active: active.length, inactive, savings: inactive.length * 29 };
}
Step 2: Configure Selective Recording
Instead of recording every meeting, configure auto-join rules in Fireflies Settings > Auto-Join:
# Recommended recording policy
record_always:
- External meetings (client/prospect calls)
- Meetings with 3+ participants
- Meetings with keywords: "review", "planning", "standup", "demo"
skip_recording:
- 1-on-1 informal chats
- Handle Fireflies.
Fireflies.ai Data Handling
Overview
Manage meeting transcript data: export in multiple formats (JSON, text, SRT), redact PII from transcripts and summaries, implement retention policies with automated cleanup, and handle GDPR/CCPA data subject requests.
Prerequisites
FIREFLIESAPIKEYconfigured- Understanding of transcript data structure (sentences, summary, analytics)
- Storage for processed transcripts
Instructions
Step 1: Fetch Transcript Data
const FIREFLIES_API = "https://api.fireflies.ai/graphql";
async function getFullTranscript(id: string) {
const res = await fetch(FIREFLIES_API, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.FIREFLIES_API_KEY}`,
},
body: JSON.stringify({
query: `
query($id: String!) {
transcript(id: $id) {
id title date duration
organizer_email
speakers { id name }
sentences { speaker_name text start_time end_time }
summary { overview action_items keywords short_summary }
meeting_attendees { displayName email }
}
}
`,
variables: { id },
}),
});
const json = await res.json();
if (json.errors) throw new Error(json.errors[0].message);
return json.data.transcript;
}
Step 2: Export in Multiple Formats
type ExportFormat = "json" | "text" | "srt" | "csv";
function exportTranscript(transcript: any, format: ExportFormat): string {
switch (format) {
case "json":
return JSON.stringify(transcript, null, 2);
case "text":
const lines = [
`# ${transcript.title}`,
`Date: ${transcript.date} | Duration: ${transcript.duration}min`,
`Speakers: ${transcript.speakers.map((s: any) => s.name).join(", ")}`,
"",
"## Summary",
transcript.summary?.overview || "(none)",
"",
"## Action Items",
...(transcript.summary?.action_items || []).map((a: string) => `- ${a}`),
"",
"## Transcript",
...transcript.sentences.map((s: any) =>
`[${fmtTime(s.start_time)}] ${s.speaker_name}: ${s.text}`
),
];
return lines.join("\n");
case "srt":
return transcript.sentences.map((s: any, i: number) =>
[
i + 1,
`${fmtSrt(s.start_time)} --> ${fmtSrt(s.end_time)}`,
`${s.speaker_name}: ${s.text}`,
"",
].join("\n")
).join("\n");
case "csv":
const header = "start_time,end_time,Collect Fireflies.
Fireflies.ai Debug Bundle
Current State
!node --version 2>/dev/null || echo 'N/A'
!python3 --version 2>/dev/null || echo 'N/A'
Overview
Collect all diagnostic information needed to resolve Fireflies.ai integration issues. Generates a redacted bundle safe for sharing with support.
Prerequisites
FIREFLIESAPIKEYenvironment variable setcurlandjqavailable- Permission to collect environment info
Instructions
Step 1: Create Debug Bundle Script
#!/bin/bash
set -euo pipefail
BUNDLE_DIR="fireflies-debug-$(date +%Y%m%d-%H%M%S)"
mkdir -p "$BUNDLE_DIR"
echo "=== Fireflies.ai Debug Bundle ===" > "$BUNDLE_DIR/summary.txt"
echo "Generated: $(date -u +%Y-%m-%dT%H:%M:%SZ)" >> "$BUNDLE_DIR/summary.txt"
echo "" >> "$BUNDLE_DIR/summary.txt"
# 1. Environment
echo "--- Environment ---" >> "$BUNDLE_DIR/summary.txt"
echo "Node: $(node --version 2>/dev/null || echo 'N/A')" >> "$BUNDLE_DIR/summary.txt"
echo "Python: $(python3 --version 2>/dev/null || echo 'N/A')" >> "$BUNDLE_DIR/summary.txt"
echo "OS: $(uname -s) $(uname -r)" >> "$BUNDLE_DIR/summary.txt"
echo "API Key: ${FIREFLIES_API_KEY:+SET (${#FIREFLIES_API_KEY} chars)}" >> "$BUNDLE_DIR/summary.txt"
echo "" >> "$BUNDLE_DIR/summary.txt"
# 2. API Connectivity
echo "--- API Connectivity ---" >> "$BUNDLE_DIR/summary.txt"
curl -s -o "$BUNDLE_DIR/api-response.json" -w "HTTP %{http_code} | %{time_total}s\n" \
-X POST https://api.fireflies.ai/graphql \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $FIREFLIES_API_KEY" \
-d '{"query": "{ user { name email is_admin } }"}' \
>> "$BUNDLE_DIR/summary.txt" 2>&1
# 3. User & Plan Info
echo "" >> "$BUNDLE_DIR/summary.txt"
echo "--- Account Info ---" >> "$BUNDLE_DIR/summary.txt"
curl -s -X POST https://api.fireflies.ai/graphql \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $FIREFLIES_API_KEY" \
-d '{"query": "{ user { name email is_admin num_transcripts minutes_consumed is_calendar_in_sync integrations } }"}' \
| jq '.data.user | {name, is_admin, transcripts: .num_transcripts, minutes: .minutes_consumed, calendar_sync: .is_calendar_in_sync}' \
>> "$BUNDLE_DIR/summary.txt" 2>/dev/null
# 4. Recent Transcripts (metadata only)
echo "" >> "$BUNDLE_DIR/summary.txt"
echo "---Deploy Fireflies.
Fireflies.ai Deploy Integration
Overview
Deploy Fireflies.ai integrations across platforms. Covers GraphQL client setup, webhook receiver deployment, and secret management for Vercel, Docker, and Google Cloud Run.
Prerequisites
- Fireflies.ai Business+ plan for API access
FIREFLIESAPIKEYandFIREFLIESWEBHOOKSECRETready- Platform CLI installed (vercel, docker, or gcloud)
Instructions
Step 1: Shared GraphQL Client
// lib/fireflies.ts
const FIREFLIES_API = "https://api.fireflies.ai/graphql";
export async function firefliesQuery(query: string, variables?: any) {
const res = await fetch(FIREFLIES_API, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.FIREFLIES_API_KEY}`,
},
body: JSON.stringify({ query, variables }),
});
const json = await res.json();
if (json.errors) throw new Error(json.errors[0].message);
return json.data;
}
Step 2: Webhook Receiver (Next.js / Vercel)
// app/api/webhooks/fireflies/route.ts
import crypto from "crypto";
export async function POST(req: Request) {
const rawBody = await req.text();
const signature = req.headers.get("x-hub-signature") || "";
// Verify HMAC-SHA256 signature
const expected = crypto
.createHmac("sha256", process.env.FIREFLIES_WEBHOOK_SECRET!)
.update(rawBody)
.digest("hex");
if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
return Response.json({ error: "Invalid signature" }, { status: 401 });
}
const event = JSON.parse(rawBody);
if (event.eventType === "Transcription completed") {
// Fetch transcript data
const data = await firefliesQuery(`
query($id: String!) {
transcript(id: $id) {
id title duration
speakers { name }
summary { overview action_items }
}
}
`, { id: event.meetingId });
// Process transcript (store, notify, create tasks)
console.log(`Processed: ${data.transcript.title}`);
}
return Response.json({ received: true });
}
Step 3: Deploy to Vercel
set -euo pipefail
# Add secrets
vercel env add FIREFLIES_API_KEY production
vercel env add FIREFLIES_WEBHOOK_SECRET production
# Deploy
vercel --prod
# Register webhook URL in Fireflies dashboard:
# https://your-app.vercel.app/api/webhooks/fireflies
Step 4: Deploy with Docker
FROM node:20-slim
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
EXPOSE 3000
CMD ["node", "dist/index.js"]
Configure Fireflies.
Fireflies.ai Enterprise RBAC
Overview
Manage workspace access control in Fireflies.ai using roles, channels, privacy levels, and the sharing API. Fireflies uses per-seat licensing with workspace roles and channel-based transcript organization.
Prerequisites
- Fireflies Business or Enterprise plan
- Workspace admin privileges (or API key from admin account)
- Understanding of your team structure
Workspace Roles
| Role | Capabilities |
|---|---|
| Admin | Full workspace control, manage members, access all transcripts |
| Member | Record meetings, view own + shared transcripts |
| Guest | View shared transcripts only (may not consume a seat) |
Instructions
Step 1: List Workspace Members
set -euo pipefail
curl -s -X POST https://api.fireflies.ai/graphql \
-H "Authorization: Bearer $FIREFLIES_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "{ users { name email user_id is_admin num_transcripts } }"}' \
| jq '.data.users[] | {name, email, admin: .is_admin, transcripts: .num_transcripts}'
Step 2: Set User Roles via API
// Promote or change a user's role
async function setUserRole(userId: string, role: string) {
return firefliesQuery(`
mutation($userId: String!, $role: String!) {
setUserRole(user_id: $userId, role: $role)
}
`, { userId, role });
}
// Usage: setUserRole("user-id-123", "admin")
Step 3: Organize Transcripts with Channels
// List all channels
const channels = await firefliesQuery(`{
channels {
id
title
is_private
created_by
members { user_id email name }
}
}`);
// Move transcripts to a channel
async function assignToChannel(transcriptIds: string[], channelId: string) {
return firefliesQuery(`
mutation($ids: [String!]!, $channelId: String!) {
updateMeetingChannel(transcript_ids: $ids, channel_id: $channelId)
}
`, { ids: transcriptIds, channelId });
}
Organize by department:
- Sales channel: All client/prospect calls
- Engineering channel: Sprint reviews, architecture discussions
- Leadership channel (private): Board meetings, strategy sessions
Step 4: Control Transcript Privacy
// Privacy levels (most restrictive to least)
type PrivacyLevel =
| "owner" // Only meeting organizer
| "participants" // Only meeting participants
| "teammatesandparticipants" // Workspace members + participants
| "teammates"Create a minimal working Fireflies.
Fireflies.ai Hello World
Overview
Minimal working examples demonstrating core Fireflies.ai GraphQL queries: list users, fetch transcripts, and read a meeting summary.
Prerequisites
- Completed
fireflies-install-authsetup FIREFLIESAPIKEYenvironment variable set- At least one meeting recorded in Fireflies
Instructions
Step 1: List Workspace Users
set -euo pipefail
curl -s -X POST https://api.fireflies.ai/graphql \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $FIREFLIES_API_KEY" \
-d '{"query": "{ users { name user_id email } }"}' | jq '.data.users'
Step 2: Fetch Recent Transcripts
const FIREFLIES_API = "https://api.fireflies.ai/graphql";
async function firefliesQuery(query: string, variables?: Record<string, any>) {
const res = await fetch(FIREFLIES_API, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.FIREFLIES_API_KEY}`,
},
body: JSON.stringify({ query, variables }),
});
const json = await res.json();
if (json.errors) throw new Error(json.errors[0].message);
return json.data;
}
// List 5 most recent transcripts
const data = await firefliesQuery(`
query RecentMeetings {
transcripts(limit: 5) {
id
title
date
duration
organizer_email
participants
}
}
`);
for (const t of data.transcripts) {
console.log(`${t.title} (${t.duration}min) - ${t.date}`);
console.log(` Organizer: ${t.organizer_email}`);
console.log(` Participants: ${t.participants?.join(", ")}`);
}
Step 3: Read a Single Transcript with Summary
async function getTranscriptSummary(id: string) {
return firefliesQuery(`
query GetTranscript($id: String!) {
transcript(id: $id) {
id
title
date
duration
organizer_email
speakers { id name }
summary {
overview
short_summary
action_items
keywords
}
}
}
`, { id });
}
const { transcript } = await getTranscriptSummary("your-transcript-id");
console.log(`Title: ${transcript.title}`);
console.log(`Summary: ${transcript.summary.overview}`);
console.log(`Action Items: ${transcript.summary.action_items?.join("\n - ")}`);
console.log(`Keywords: ${transcript.summary.keywords?.join(", ")}`);
Step 4: Python Hello World
import os, requests
API = "https://api.fireflies.ai/graphql"
HEADERS = {
"Content-Type": "application/json",
"Authorization": f"Bearer {os.Execute Fireflies.
Fireflies.ai Incident Runbook
Overview
Rapid incident response procedures for Fireflies.ai integration failures. Covers API outages, authentication problems, webhook issues, and rate limiting.
Severity Levels
| Level | Definition | Response Time | Examples |
|---|---|---|---|
| P1 | Integration fully broken | < 15 min | auth_failed on all requests |
| P2 | Degraded functionality | < 1 hour | Rate limiting, slow responses |
| P3 | Minor impact | < 4 hours | Webhook delays, missing summaries |
| P4 | No user impact | Next business day | Monitoring gaps |
Quick Triage (Run First)
set -euo pipefail
echo "=== Fireflies.ai Incident Triage ==="
echo ""
# 1. Can we reach the API?
echo "--- API Connectivity ---"
curl -s -o /dev/null -w "HTTP %{http_code} (%{time_total}s)\n" \
-X POST https://api.fireflies.ai/graphql \
-H "Authorization: Bearer $FIREFLIES_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "{ user { email } }"}'
# 2. What error are we getting?
echo ""
echo "--- API Response ---"
curl -s -X POST https://api.fireflies.ai/graphql \
-H "Authorization: Bearer $FIREFLIES_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "{ user { email is_admin } }"}' | jq .
# 3. Can we list transcripts?
echo ""
echo "--- Transcript Access ---"
curl -s -X POST https://api.fireflies.ai/graphql \
-H "Authorization: Bearer $FIREFLIES_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "{ transcripts(limit: 1) { id title date } }"}' | jq '.data.transcripts[0] // .errors[0]'
Decision Tree
API returning errors?
├─ YES: What error code?
│ ├─ auth_failed (401) → API key revoked or invalid
│ │ └─ Fix: Regenerate key at app.fireflies.ai > Integrations
│ ├─ too_many_requests (429) → Rate limited
│ │ └─ Fix: Enable backoff, check for runaway loops
│ ├─ account_cancelled (403) → Subscription expired
│ │ └─ Fix: Renew subscription, contact billing
│ └─ 5xx errors → Fireflies platform issue
│ └─ Fix: Enable fallback mode, wait for resolution
└─ NO: Webhook issues?
├─ Not receiving webhooks → Check dashboard registration
├─ Invalid signature → Webhook secret mismatch
└─ Processing failures → Check your webhook handler logs
Remediation by Error Type
auth_failed (401) -- P1
set -euo pipefail
# Verify API key format (should be non-empty)
echo "Key lengConfigure Fireflies.
Fireflies.ai Install & Auth
Overview
Set up Fireflies.ai GraphQL API authentication. Fireflies uses a single GraphQL endpoint at https://api.fireflies.ai/graphql with Bearer token auth. No SDK needed -- all interaction is via HTTP POST with GraphQL queries.
Prerequisites
- Fireflies.ai account (Pro or higher for API access)
- API key from app.fireflies.ai > Integrations > Fireflies API
- Node.js 18+ or Python 3.10+
- A GraphQL client library (optional but recommended)
Instructions
Step 1: Get Your API Key
- Log in at app.fireflies.ai
- Navigate to Integrations > Fireflies API
- Copy your API key (starts with a long alphanumeric string)
- Store it securely -- this key grants access to all your meeting data
Step 2: Configure Environment
set -euo pipefail
# Create .env file (NEVER commit to git)
echo 'FIREFLIES_API_KEY=your-api-key-here' >> .env
# Add to .gitignore
echo '.env' >> .gitignore
echo '.env.local' >> .gitignore
Step 3: Install GraphQL Client (Optional)
set -euo pipefail
# Node.js -- graphql-request is lightweight and typed
npm install graphql-request graphql
# Or use plain fetch -- no library needed
# Python -- use requests
pip install requests
Step 4: Verify Connection
// verify-fireflies.ts
const FIREFLIES_API = "https://api.fireflies.ai/graphql";
async function verifyConnection() {
const query = `{ user { name email is_admin } }`;
const response = await fetch(FIREFLIES_API, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.FIREFLIES_API_KEY}`,
},
body: JSON.stringify({ query }),
});
const result = await response.json();
if (result.errors) {
throw new Error(`Auth failed: ${result.errors[0].message}`);
}
const user = result.data.user;
console.log(`Connected as: ${user.name} (${user.email})`);
console.log(`Admin: ${user.is_admin}`);
return user;
}
verifyConnection().catch(console.error);
Step 5: Verify with cURL
set -euo pipefail
curl -s -X POST https://api.fireflies.ai/graphql \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $FIREFLIES_API_KEY" \
-d '{"query": "{ user { name email } }"}' | jq .
Python Verification
import os, requests
FIREFLIES_API = "https://api.fireflies.ai/graphql"
def verify_connection():
headers = {
"Content-Type": "application/json",
"Authorization": Configure local development workflow for Fireflies.
Fireflies.ai Local Dev Loop
Overview
Set up a fast local development workflow for Fireflies.ai integrations: project structure, mock data for offline development, test helpers, and API response recording for replay.
Prerequisites
- Completed
fireflies-install-authsetup - Node.js 18+ with npm/pnpm
- Vitest for testing
Instructions
Step 1: Project Structure
my-fireflies-app/
src/
lib/
fireflies-client.ts # GraphQL client (see fireflies-sdk-patterns)
transcript-service.ts # Business logic layer
types/
fireflies.ts # TypeScript interfaces
tests/
fixtures/
transcript.json # Recorded API responses
fireflies-client.test.ts
transcript-service.test.ts
.env.local # FIREFLIES_API_KEY (git-ignored)
.env.example # Template without secrets
Step 2: Record Real API Responses as Fixtures
// scripts/record-fixtures.ts
import { FirefliesClient } from "../src/lib/fireflies-client";
import { writeFileSync, mkdirSync } from "fs";
async function recordFixtures() {
const client = new FirefliesClient();
mkdirSync("tests/fixtures", { recursive: true });
// Record user
const user = await client.query(`{ user { name email user_id is_admin } }`);
writeFileSync("tests/fixtures/user.json", JSON.stringify(user, null, 2));
// Record transcript list
const list = await client.query(`{
transcripts(limit: 3) {
id title date duration organizer_email
summary { overview action_items keywords }
}
}`);
writeFileSync("tests/fixtures/transcripts.json", JSON.stringify(list, null, 2));
// Record single transcript with sentences
const id = list.transcripts[0]?.id;
if (id) {
const full = await client.query(`
query($id: String!) {
transcript(id: $id) {
id title date duration
speakers { id name }
sentences { speaker_name text start_time end_time }
summary { overview action_items keywords }
analytics {
sentiments { positive_pct negative_pct neutral_pct }
speakers { name duration word_count }
}
}
}
`, { id });
writeFileSync("tests/fixtures/transcript-full.json", JSON.stringify(full, null, 2));
}
console.log("Fixtures recorded in tests/fixtures/");
}
recordFixtures().catch(console.error);
Step 3: Mock Client for Tests
// tests/helpers/mock-fireflies.ts
import { readFileSync } from "fs";
export function createMockClient() {
const fixtures: Record<string, any> = {};
return {
loadFixture(name: string) {
fixtures[name] = JSON.parse(
readFileSync(`tests/fixtures/${name}.json`, "utf-8")
Migrate to Fireflies.
Fireflies.ai Migration Deep Dive
Current State
!npm list graphql graphql-request 2>/dev/null || echo 'No graphql packages'
Overview
Migrate to Fireflies.ai from other transcription platforms or custom recording systems. Covers historical recording import via uploadAudio, adapter pattern for gradual cutover, and data validation post-migration.
Migration Types
| Scenario | Approach | Timeline |
|---|---|---|
| Fresh start (no history) | Configure Fireflies bot, done | 1 day |
| Import recordings | Batch uploadAudio |
1-2 weeks |
| Switch from competitor | Parallel run + gradual cutover | 2-4 weeks |
| Enterprise rollout | Phased department-by-department | 1-2 months |
Instructions
Step 1: Pre-Migration Assessment
// Inventory your current meeting data
interface MigrationInventory {
totalRecordings: number;
totalHours: number;
formats: string[]; // mp3, mp4, wav, m4a, ogg
averageDuration: number; // minutes
dateRange: { oldest: string; newest: string };
platforms: string[]; // Zoom, Teams, etc.
}
// Fireflies supports: mp3, mp4, wav, m4a, ogg
// Size limits: 200MB audio, 100MB video (free), 1.5GB video (paid)
// Minimum: 50KB (can bypass with bypass_size_check: true)
Step 2: Batch Upload Historical Recordings
const FIREFLIES_API = "https://api.fireflies.ai/graphql";
interface UploadJob {
url: string; // Must be publicly accessible HTTPS URL
title: string;
attendees?: { displayName: string; email: string }[];
referenceId: string; // Your internal ID for tracking
}
async function batchUpload(jobs: UploadJob[]) {
const results: { id: string; status: string; error?: string }[] = [];
for (const job of jobs) {
try {
const res = await fetch(FIREFLIES_API, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.FIREFLIES_API_KEY}`,
},
body: JSON.stringify({
query: `
mutation($input: AudioUploadInput) {
uploadAudio(input: $input) {
success title message
}
}
`,
variables: {
input: {
url: job.url,
title: job.title,
attendees: job.attendees,
client_reference_id: job.referenceId,
webhook: process.env.WEBHOOK_URL,
},
},
}),
});
const json = await res.json();
if (json.errors) {
results.push({ id: job.referenceId, status: "error", error: json.errors[0].mesConfigure Fireflies.
Fireflies.ai Multi-Environment Setup
Overview
Configure Fireflies.ai with isolated API keys, webhook URLs, and settings per environment. Each environment gets its own Fireflies workspace or API key to prevent cross-environment data leakage.
Environment Strategy
| Environment | API Key | Webhook URL | Settings |
|---|---|---|---|
| Development | FIREFLIESAPIKEY_DEV |
localhost (ngrok) | Debug logs, no cache |
| Staging | FIREFLIESAPIKEY_STAGING |
staging.app.com/webhooks | Prod-like, short cache |
| Production | FIREFLIESAPIKEY_PROD |
app.com/webhooks | Hardened, long cache |
Instructions
Step 1: Environment Configuration Module
// config/fireflies.ts
interface FirefliesConfig {
apiKey: string;
apiUrl: string;
webhookSecret: string;
cache: { enabled: boolean; ttlSeconds: number };
debug: boolean;
timeout: number;
maxRetries: number;
}
const configs: Record<string, Partial<FirefliesConfig>> = {
development: {
apiKey: process.env.FIREFLIES_API_KEY_DEV || "",
webhookSecret: process.env.FIREFLIES_WEBHOOK_SECRET_DEV || "dev-secret-16char",
cache: { enabled: false, ttlSeconds: 60 },
debug: true,
timeout: 30000,
maxRetries: 1,
},
staging: {
apiKey: process.env.FIREFLIES_API_KEY_STAGING || "",
webhookSecret: process.env.FIREFLIES_WEBHOOK_SECRET_STAGING || "",
cache: { enabled: true, ttlSeconds: 300 },
debug: false,
timeout: 15000,
maxRetries: 3,
},
production: {
apiKey: process.env.FIREFLIES_API_KEY_PROD || "",
webhookSecret: process.env.FIREFLIES_WEBHOOK_SECRET_PROD || "",
cache: { enabled: true, ttlSeconds: 3600 },
debug: false,
timeout: 10000,
maxRetries: 5,
},
};
function detectEnvironment(): string {
if (process.env.NODE_ENV === "production") return "production";
if (process.env.NODE_ENV === "staging" || process.env.VERCEL_ENV === "preview") return "staging";
return "development";
}
export function getFirefliesConfig(): FirefliesConfig {
const env = detectEnvironment();
const config = configs[env];
if (!config?.apiKey) {
throw new Error(`FIREFLIES_API_KEY not configured for environment: ${env}`);
}
return {
apiUrl: "https://api.fireflies.ai/graphql",
...config,
} as FirefliesConfig;
}
Step 2: Environment-Aware Client
// lib/fireflies-client.ts
import { getFirefliesConfig } from "../config/fireflies";
export function createFirefliesClient() {
const config = getFirefliesConfig();
return Monitor Fireflies.
Fireflies.ai Observability
Overview
Monitor Fireflies.ai integration health: API connectivity, webhook delivery, transcript processing latency, and seat utilization. Built for Prometheus/Grafana but adaptable to any metrics system.
Prerequisites
- Fireflies Business+ plan (for full API access)
- Prometheus + Grafana (or equivalent metrics stack)
- Webhook endpoint deployed and receiving events
Instructions
Step 1: Instrument the GraphQL Client
// lib/fireflies-instrumented.ts
import { Counter, Histogram, Gauge } from "prom-client";
const apiRequests = new Counter({
name: "fireflies_api_requests_total",
help: "Total Fireflies API requests",
labelNames: ["operation", "status"],
});
const apiLatency = new Histogram({
name: "fireflies_api_latency_seconds",
help: "Fireflies API request latency",
labelNames: ["operation"],
buckets: [0.1, 0.25, 0.5, 1, 2, 5, 10],
});
const FIREFLIES_API = "https://api.fireflies.ai/graphql";
export async function firefliesQueryInstrumented(
operation: string,
query: string,
variables?: any
) {
const timer = apiLatency.startTimer({ operation });
try {
const res = await fetch(FIREFLIES_API, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.FIREFLIES_API_KEY}`,
},
body: JSON.stringify({ query, variables }),
});
const json = await res.json();
if (json.errors) {
apiRequests.inc({ operation, status: json.errors[0].code || "error" });
throw new Error(json.errors[0].message);
}
apiRequests.inc({ operation, status: "success" });
return json.data;
} catch (err) {
apiRequests.inc({ operation, status: "failure" });
throw err;
} finally {
timer();
}
}
Step 2: Webhook Event Metrics
const webhookEvents = new Counter({
name: "fireflies_webhook_events_total",
help: "Webhook events received",
labelNames: ["event_type", "status"],
});
const webhookProcessingTime = new Histogram({
name: "fireflies_webhook_processing_seconds",
help: "Time to process webhook events",
buckets: [0.1, 0.5, 1, 5, 10, 30],
});
const transcriptQueue = new Gauge({
name: "fireflies_transcript_queue_depth",
help: "Number of transcripts queued for processing",
});
export async function handleWebhookWithMetrics(event: any) {
const timer = webhookProcessingTime.startTimer();
transcriptQueue.inc();
try {
await processTranscriptReady(event.meetingId);
webhookEvents.inc({ event_type: event.eventType, status: "success" });
} catch (err) {
webhookEvOptimize Fireflies.
Fireflies.ai Performance Tuning
Overview
Optimize Fireflies.ai GraphQL API performance. The biggest wins: request only needed fields (transcripts with sentences can be very large), cache immutable transcripts, and batch operations within rate limits.
Prerequisites
FIREFLIESAPIKEYconfigured- Understanding of your access pattern (list vs detail, frequency)
- Optional: Redis or LRU cache library
Instructions
Step 1: Field Selection -- The Biggest Win
Transcript responses with sentences can be enormous. Always request the minimum fields needed.
// BAD: Fetching everything when you only need titles
const HEAVY = `{ transcripts(limit: 50) {
id title date duration sentences { text speaker_name start_time end_time }
summary { overview action_items keywords outline bullet_gist }
analytics { speakers { name duration word_count } }
} }`;
// GOOD: Light query for listing
const LIGHT = `{ transcripts(limit: 50) {
id title date duration organizer_email
} }`;
// GOOD: Full query only when drilling into a specific transcript
const DETAIL = `query($id: String!) { transcript(id: $id) {
id title
sentences { speaker_name text start_time end_time }
summary { overview action_items keywords }
} }`;
Step 2: Cache Transcripts (They Are Immutable)
Once a transcript is processed, its content never changes. Cache aggressively.
import { LRUCache } from "lru-cache";
const transcriptCache = new LRUCache<string, any>({
max: 500,
ttl: 1000 * 60 * 60, // 1 hour -- transcripts are immutable
});
async function getCachedTranscript(id: string) {
const cached = transcriptCache.get(id);
if (cached) return cached;
const data = await firefliesQuery(`
query($id: String!) {
transcript(id: $id) {
id title date duration
speakers { name }
sentences { speaker_name text start_time end_time }
summary { overview action_items keywords }
}
}
`, { id });
transcriptCache.set(id, data.transcript);
return data.transcript;
}
Step 3: Redis Cache for Multi-Instance Deployments
import Redis from "ioredis";
const redis = new Redis(process.env.REDIS_URL!);
const CACHE_TTL = 3600; // 1 hour in seconds
async function getTranscriptCached(id: string) {
const cacheKey = `fireflies:transcript:${id}`;
// Check cache
const cached = await redis.get(cacheKey);
if (cached) return JSON.parse(cached);
// Fetch from API
const data = await firefliesQuery(`
query($id: String!) {
transcript(id: $id) {
id title date duration
sentences { speaker_name text start_time end_time }
summary { overview action_items keywords }
}
}
`, { id });
// Cache the result
await redis.Execute Fireflies.
Fireflies.ai Production Checklist
Overview
Complete checklist for deploying Fireflies.ai integrations to production. Covers API key management, webhook setup, health checks, and monitoring.
Prerequisites
- Staging environment tested
- Production API key from Fireflies dashboard
- Webhook endpoint with HTTPS and signature verification
- Monitoring infrastructure ready
Pre-Deployment Checklist
API & Auth
- [ ] Production
FIREFLIESAPIKEYin secret manager (not env file) - [ ] API key has minimum required access
- [ ]
FIREFLIESWEBHOOKSECRETconfigured (16-32 chars) - [ ] Separate keys for dev/staging/prod environments
- [ ] Key rotation procedure documented
Code Quality
- [ ] All GraphQL queries tested against real API in staging
- [ ] Error handling for all Fireflies error codes (
authfailed,toomanyrequests,requireai_credits) - [ ] Rate limiting with exponential backoff implemented
- [ ] No hardcoded API keys or transcript IDs
- [ ] Webhook signature verification (HMAC-SHA256) enabled
Webhook Configuration
- [ ] Webhook URL registered in Fireflies dashboard (Settings > Developer settings)
- [ ] HTTPS endpoint with valid TLS certificate
- [ ]
x-hub-signatureheader verified on every request - [ ] Webhook handler responds with 200 immediately (process async)
- [ ] Dead-letter queue for failed webhook processing
Health Check Endpoint
// /api/health
export async function GET() {
const checks: Record<string, any> = {};
// Fireflies API connectivity
try {
const start = Date.now();
const res = await fetch("https://api.fireflies.ai/graphql", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.FIREFLIES_API_KEY}`,
},
body: JSON.stringify({ query: "{ user { email } }" }),
signal: AbortSignal.timeout(5000),
});
const json = await res.json();
checks.fireflies = {
status: json.errors ? "error" : "healthy",
latencyMs: Date.now() - start,
error: json.errors?.[0]?.code,
};
} catch (err) {
checks.fireflies = { status: "unreachable", error: (err as Error).message };
}
const allHealthy = Object.values(checks).every((c: any) => c.status === "healthy");
return Response.json(
{ status: allHealthy ? "healthy" : "degraded", checks },
{ status: allHealthy ? 200 : 503 }
);
}
Monitoring & Alerting
- [ ] Alert on Fireflies API errors (5xx, 401, 429)
- [ ] Track
Implement Fireflies.
Fireflies.ai Rate Limits
Overview
Handle Fireflies.ai GraphQL API rate limits with exponential backoff and request queuing. Fireflies enforces per-plan limits and per-operation limits.
Rate Limit Reference
Per-Plan Limits
| Plan | Limit | Scope |
|---|---|---|
| Free | 50 requests/day | Per API key |
| Pro | 50 requests/day | Per API key |
| Business | 60 requests/min | Per API key |
| Enterprise | 60 requests/min | Per API key |
Per-Operation Limits
| Operation | Limit | Error Code |
|---|---|---|
addToLiveMeeting |
3 per 20 minutes | toomanyrequests |
shareMeeting |
10 per hour (up to 50 emails each) | toomanyrequests |
deleteTranscript |
10 per minute | toomanyrequests |
uploadAudio |
Varies by plan | toomanyrequests |
Instructions
Step 1: Detect Rate Limits in Responses
interface FirefliesError {
message: string;
code: string;
extensions?: { status: number };
}
function isRateLimited(response: any): boolean {
return response.errors?.some(
(e: FirefliesError) =>
e.code === "too_many_requests" ||
e.extensions?.status === 429
);
}
Step 2: Exponential Backoff with Jitter
async function firefliesQueryWithRetry<T>(
query: string,
variables?: Record<string, any>,
maxRetries = 5
): Promise<T> {
const FIREFLIES_API = "https://api.fireflies.ai/graphql";
for (let attempt = 0; attempt <= maxRetries; attempt++) {
const res = await fetch(FIREFLIES_API, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.FIREFLIES_API_KEY}`,
},
body: JSON.stringify({ query, variables }),
});
const json = await res.json();
if (!isRateLimited(json)) {
if (json.errors) throw new Error(json.errors[0].message);
return json.data;
}
if (attempt === maxRetries) {
throw new Error(`Rate limited after ${maxRetries} retries`);
}
// Exponential backoff: 1s, 2s, 4s, 8s, 16s + jitter
const baseDelay = 1000 * Math.pow(2, attempt);
const jitter = Math.random() * 500;
const delay = Math.min(baseDelay + jitter, 32000);
console.log(`Rate limited. Retry ${attempt + 1}/${maxRetries} in ${delay.toFixed(0)}ms`);
await new Promise(r => setTimeout(r, delay));
}Design meeting intelligence architecture with Fireflies.
Fireflies.ai Reference Architecture
Overview
Production architecture for meeting intelligence using Fireflies.ai. Event-driven pipeline: meetings are recorded by the Fireflies bot, transcripts arrive via webhook, then are processed for action items, analytics, and CRM sync.
Architecture
┌──────────────────────────────────────────────────────┐
│ Meeting Sources │
│ Zoom │ Google Meet │ MS Teams │ Upload API │
└──────────┬───────────────────────────────┬───────────┘
│ Bot auto-joins │ uploadAudio
▼ ▼
┌──────────────────────────────────────────────────────┐
│ Fireflies.ai Platform │
│ Transcription → Speaker ID → AI Summary → Actions │
└───────────────────────┬──────────────────────────────┘
│ Webhook: "Transcription completed"
│ Payload: { meetingId, eventType }
▼
┌──────────────────────────────────────────────────────┐
│ Your Webhook Receiver │
│ 1. Verify x-hub-signature (HMAC-SHA256) │
│ 2. ACK 200 immediately │
│ 3. Queue for async processing │
└───────────────────────┬──────────────────────────────┘
│
┌────────────┼────────────┐
▼ ▼ ▼
┌──────────────┐ ┌────────┐ ┌──────────────┐
│ Transcript │ │ Action │ │ Analytics │
│ Storage │ │ Items │ │ Engine │
│ (DB/Search) │ │ (CRM) │ │ (Dashboards) │
└──────────────┘ └────────┘ └──────────────┘
Core Components
1. GraphQL Client Layer
// lib/fireflies.ts
const FIREFLIES_API = "https://api.fireflies.ai/graphql";
export async function firefliesQuery(query: string, variables?: any) {
const res = await fetch(FIREFLIES_API, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.FIREFLIES_API_KEY}`,
},
body: JSON.stringify({ query, variables }),
});
const json = await res.json();
if (json.errors) throw new Error(json.errors[0].message);
return json.data;
}
2. Webhook Processor
// services/webhook-processor.ts
import crypto from "crypto";
interface TranscriptEvent {
meetingId: string;
eventType: string;
clientReferenceId?: string;
}
export async function processWebhookEvent(event: TranscriptEvent) {
// Fetch full transcript
const { transcript } = await firefliesQuery(`
query($id: String!) {
transcript(id: $id) {
id title date duration
organizer_email
speakers { id name }
sentences {
speaker_name text start_time end_time
Apply production-ready Fireflies.
Fireflies.ai Client Patterns
Overview
Production-ready patterns for the Fireflies.ai GraphQL API. Fireflies has no official SDK -- all interaction is via HTTP POST to https://api.fireflies.ai/graphql. These patterns provide typed wrappers, error handling, caching, and multi-tenant support.
Prerequisites
FIREFLIESAPIKEYenvironment variable set- TypeScript 5+ or Python 3.10+
- Optional:
graphql-requestfor typed queries
Instructions
Step 1: Typed GraphQL Client (TypeScript)
// lib/fireflies-client.ts
const FIREFLIES_API = "https://api.fireflies.ai/graphql";
interface FirefliesError {
message: string;
code?: string;
extensions?: { status: number; helpUrls?: string[] };
}
interface FirefliesResponse<T> {
data?: T;
errors?: FirefliesError[];
}
export class FirefliesClient {
private apiKey: string;
private baseUrl: string;
constructor(apiKey?: string) {
this.apiKey = apiKey || process.env.FIREFLIES_API_KEY!;
this.baseUrl = FIREFLIES_API;
if (!this.apiKey) throw new Error("FIREFLIES_API_KEY is required");
}
async query<T = any>(gql: string, variables?: Record<string, any>): Promise<T> {
const res = await fetch(this.baseUrl, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${this.apiKey}`,
},
body: JSON.stringify({ query: gql, variables }),
});
const json: FirefliesResponse<T> = await res.json();
if (json.errors?.length) {
const err = json.errors[0];
const error = new Error(`Fireflies: ${err.message}`) as any;
error.code = err.code;
error.status = err.extensions?.status;
throw error;
}
return json.data!;
}
// Convenience methods for common queries
async getUser() {
return this.query<{ user: any }>(`{ user { name email user_id is_admin } }`);
}
async getTranscripts(limit = 20) {
return this.query<{ transcripts: any[] }>(`
query($limit: Int) {
transcripts(limit: $limit) {
id title date duration organizer_email participants
summary { overview action_items keywords }
}
}
`, { limit });
}
async getTranscript(id: string) {
return this.query<{ transcript: any }>(`
query($id: String!) {
transcript(id: $id) {
id title date duration
speakers { id name }
sentences { speaker_name text start_time end_time }
summary { overview action_items keywords short_summary }
analytics {
sentiments { positive_pct negative_pct neutral_pct }
speakers { name duration word_count questions }
}
}
}
`, { id });
}
}
Step 2: Singleton Pattern
Apply Fireflies.
Fireflies.ai Security Basics
Overview
Security essentials for Fireflies.ai: API key management, webhook HMAC-SHA256 signature verification, transcript access controls, and audit practices.
Prerequisites
- Fireflies.ai API key
- Understanding of environment variables
- HTTPS endpoint for webhooks (required by Fireflies)
Instructions
Step 1: Secure API Key Storage
# .env (NEVER commit)
FIREFLIES_API_KEY=your-api-key
FIREFLIES_WEBHOOK_SECRET=your-16-to-32-char-secret
# .gitignore
.env
.env.local
.env.*.local
Pre-commit hook to catch leaked keys:
#!/bin/bash
# .git/hooks/pre-commit
if git diff --cached --name-only | xargs grep -l 'FIREFLIES_API_KEY\s*=' 2>/dev/null; then
echo "ERROR: Potential API key in commit. Remove before committing."
exit 1
fi
Step 2: Webhook Signature Verification (HMAC-SHA256)
Fireflies signs webhook payloads with HMAC-SHA256. The signature arrives in the x-hub-signature header.
import crypto from "crypto";
function verifyFirefliesWebhook(
payload: string,
signature: string,
secret: string
): boolean {
const expected = crypto
.createHmac("sha256", secret)
.update(payload)
.digest("hex");
// Timing-safe comparison prevents timing attacks
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
// Express middleware
import express from "express";
const app = express();
app.post("/webhooks/fireflies",
express.raw({ type: "application/json" }),
(req, res) => {
const signature = req.headers["x-hub-signature"] as string;
const payload = req.body.toString();
if (!signature || !verifyFirefliesWebhook(payload, signature, process.env.FIREFLIES_WEBHOOK_SECRET!)) {
console.warn("Invalid webhook signature rejected");
return res.status(401).json({ error: "Invalid signature" });
}
const event = JSON.parse(payload);
console.log(`Verified webhook: ${event.eventType} for ${event.meetingId}`);
res.status(200).json({ received: true });
}
);
Step 3: Configure Webhook Secret
- Go to app.fireflies.ai/settings
- Select Developer settings tab
- Enter a 16-32 character secret or click Generate
- Store the secret in your environment as
FIREFLIESWEBHOOKSECRET
Step 4: Python Webhook Verification
import hmac, hashlib, json
from flask import Flask, request, jsonify
app = Flask(__name__)
def verify_signature(payload: bytes, signature: str, secret: str) -> bool:
expecteHandle Fireflies.
Fireflies.ai Upgrade & Migration
Current State
!npm list graphql graphql-request 2>/dev/null || echo 'No graphql packages'
Overview
Fireflies.ai uses a GraphQL API (no versioned SDK). Breaking changes come as field deprecations and new query parameter patterns. This skill covers all known deprecations and migration paths.
Known Deprecations
Transcript Query Parameter Changes
// DEPRECATED: Single organizer email string
const OLD = `{ transcripts(organizer_email: "alice@co.com") { id } }`;
// CURRENT: Array of organizer emails
const NEW = `{ transcripts(organizers: ["alice@co.com"]) { id } }`;
// DEPRECATED: Single participant email string
const OLD = `{ transcripts(participant_email: "bob@co.com") { id } }`;
// CURRENT: Array of participant emails
const NEW = `{ transcripts(participants: ["bob@co.com"]) { id } }`;
// DEPRECATED: title parameter for search
const OLD = `{ transcripts(title: "standup") { id } }`;
// CURRENT: keyword with scope
const NEW = `{ transcripts(keyword: "standup") { id } }`;
// DEPRECATED: date parameter (single date)
const OLD = `{ transcripts(date: "2026-03-01") { id } }`;
// CURRENT: fromDate/toDate range
const NEW = `{
transcripts(
fromDate: "2026-03-01T00:00:00Z"
toDate: "2026-03-31T23:59:59Z"
) { id }
}`;
Field-Level Deprecations
// DEPRECATED
transcript.host_email
// CURRENT
transcript.organizer_email
Migration Procedure
Step 1: Scan Codebase for Deprecated Patterns
set -euo pipefail
echo "=== Scanning for deprecated Fireflies patterns ==="
# Deprecated query parameters
grep -rn 'organizer_email:' --include='*.ts' --include='*.js' --include='*.py' . || echo "No organizer_email (good)"
grep -rn 'participant_email:' --include='*.ts' --include='*.js' --include='*.py' . || echo "No participant_email (good)"
grep -rn 'host_email' --include='*.ts' --include='*.js' --include='*.py' . || echo "No host_email (good)"
grep -rn 'transcripts(.*title:' --include='*.ts' --include='*.js' --include='*.py' . || echo "No title param (good)"
grep -rn 'transcripts(.*date:' --include='*.ts' --include='*.js' --include='*.py' . || echo "No date param (good)"
Step 2: Update Query Patterns
Create a migration helper:
// migrations/fireflies-deprecations.ts
/**
* Maps old query parameter namImplement Fireflies.
Fireflies.ai Webhooks & Events
Overview
Handle Fireflies.ai webhook events for real-time transcript notifications. Fireflies fires a webhook when a transcript finishes processing. The payload is signed with HMAC-SHA256 for verification.
Prerequisites
- Fireflies.ai Business or Enterprise plan
FIREFLIESAPIKEYandFIREFLIESWEBHOOKSECRETin environment- HTTPS endpoint accessible from the internet
Webhook Event Reference
Fireflies currently fires one event type:
| Event | eventType Value |
Trigger |
|---|---|---|
| Transcription completed | "Transcription completed" |
Transcript is fully processed and ready |
Payload Format
{
"meetingId": "ASxwZxCstx",
"eventType": "Transcription completed",
"clientReferenceId": "be582c46-4ac9-4565-9ba6-6ab4264496a8"
}
| Field | Type | Description |
|---|---|---|
meetingId |
String | Transcript ID -- use in transcript(id:) query |
eventType |
String | Always "Transcription completed" currently |
clientReferenceId |
ID | Your custom ID from uploadAudio (null if bot-recorded) |
Important Constraints
- Webhooks fire only for meetings you own (organizer_email matches your account)
- Super Admin webhooks (Enterprise only) fire for all team-owned meetings
Instructions
Step 1: Register Webhook in Dashboard
- Go to app.fireflies.ai/settings
- Select Developer settings tab
- Enter your HTTPS webhook URL
- Enter or generate a 16-32 character secret
- Save
Step 2: Build Webhook Receiver with Signature Verification
import express from "express";
import crypto from "crypto";
const app = express();
// IMPORTANT: Use raw body for HMAC verification
app.post("/webhooks/fireflies",
express.raw({ type: "application/json" }),
async (req, res) => {
const signature = req.headers["x-hub-signature"] as string;
const rawBody = req.body.toString();
// Verify HMAC-SHA256 signature
if (!signature || !verifySignature(rawBody, signature)) {
console.warn("Rejected webhook: invalid signature");
return res.status(401).json({ error: "Invalid signature" });
}
// Acknowledge immediately -- process async
res.status(200).json(Ready to use fireflies-pack?
Related Plugins
000-jeremy-content-consistency-validator
Read-only validator that generates comprehensive discrepancy reports comparing messaging consistency across ANY HTML-based website (WordPress, Hugo, Next.js, React, Vue, static HTML, etc.), GitHub repositories, and local documentation. Detects mixed messaging without making changes.
002-jeremy-yaml-master-agent
Intelligent YAML validation, generation, and transformation agent with schema inference, linting, and format conversion capabilities
003-jeremy-vertex-ai-media-master
Comprehensive Google Vertex AI multimodal mastery for Jeremy - video processing (6+ hours), audio generation, image creation with Gemini 2.0/2.5 and Imagen 4. Marketing campaign automation, content generation, and media asset production.
004-jeremy-google-cloud-agent-sdk
Google Cloud Agent Development Kit (ADK) and Agent Starter Pack mastery - build containerized multi-agent systems with production-ready templates, deploy to Cloud Run/GKE/Agent Engine, RAG agents, ReAct agents, and multi-agent orchestration.
agent-context-manager
Automatically detects and loads AGENTS.md files to provide agent-specific instructions
ai-commit-gen
AI-powered commit message generator - analyzes your git diff and creates conventional commit messages instantly