Fireflies' web app downloads transcripts one meeting at a time, and on the Free plan downloads are locked. The official GraphQL API has no such lock: with an API key you can list every meeting and pull each transcript. This guide covers the two queries you need, the paging and rate limits, and a free script that saves each meeting as Markdown.
Disclosure: MinuteHaul is our paid exporter for Fireflies (beta) and tl;dv. The script below is free and doesn't need it. Facts here are from Fireflies' API docs, checked Oct 26, 2026.
Authorization: Bearer YOUR_KEY with POST https://api.fireflies.ai/graphql.# list meetings, max 50 per call; page with skip
query($limit:Int,$skip:Int){ transcripts(limit:$limit, skip:$skip){ id title date duration } }
# one meeting's transcript
query($id:String!){ transcript(id:$id){ sentences{ speaker_name text start_time end_time } summary{ overview action_items keywords } } }
The transcripts query also takes fromDate/toDate (ISO 8601), keyword, mine, organizers and participants filters if you only want part of the archive (Fireflies transcripts query).
| Plan | Per minute | Per day |
|---|---|---|
| Free | 30 | 500 |
| Pro | 60 | 5,000 |
| Business | 60 per paid seat, pooled (up to 1,200) | No daily cap |
| Enterprise | 60 per paid seat, pooled (up to 2,400) | No daily cap |
Per Fireflies' limits page: a Free user's first API request starts a 14-day trial at Pro limits; the daily quota resets at midnight UTC; on a 429, wait the seconds in Retry-After, because requests sent during a block still count toward the next window. A full export costs one request per 50 meetings listed plus one per transcript, so on Free after the trial, an archive of more than about 490 meetings takes more than one day.
Saves each meeting as YYYY-MM-DD-title-id.md with speaker names and timestamps. Run with FIREFLIES_API_KEY=your_key node fireflies-export.mjs ./out.
// fireflies-export.mjs: save every Fireflies transcript as Markdown.
// Usage: FIREFLIES_API_KEY=xxx node fireflies-export.mjs ./out
import { mkdir, writeFile } from "node:fs/promises";
import { join } from "node:path";
const KEY = process.env.FIREFLIES_API_KEY;
const OUT = process.argv[2] || "./fireflies-export";
if (!KEY) { console.error("Set FIREFLIES_API_KEY"); process.exit(1); }
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
async function gql(query, variables) {
for (;;) {
const res = await fetch("https://api.fireflies.ai/graphql", {
method: "POST",
headers: { "Content-Type": "application/json", Authorization: `Bearer ${KEY}` },
body: JSON.stringify({ query, variables }),
});
if (res.status === 429) { console.log("429, waiting 60s"); await sleep(60_000); continue; }
const json = await res.json();
if (json.errors) throw new Error(JSON.stringify(json.errors));
await sleep(1_100); // ~55 requests/minute, under Pro's 60
return json.data;
}
}
const LIST = `query($limit:Int,$skip:Int){transcripts(limit:$limit,skip:$skip){id title date duration}}`;
const ONE = `query($id:String!){transcript(id:$id){sentences{speaker_name text start_time}}}`;
const slug = (s) => (s || "untitled").toLowerCase().replace(/[^a-z0-9]+/g, "-").slice(0, 60);
const ts = (sec) => new Date(sec * 1000).toISOString().slice(11, 19);
await mkdir(OUT, { recursive: true });
let skip = 0, saved = 0;
for (;;) {
const { transcripts } = await gql(LIST, { limit: 50, skip });
if (!transcripts?.length) break;
for (const t of transcripts) {
const { transcript } = await gql(ONE, { id: t.id });
const day = new Date(Number(t.date)).toISOString().slice(0, 10);
const lines = (transcript?.sentences || []).map(
(s) => `**${s.speaker_name || "Speaker"}** [${ts(s.start_time)}]: ${s.text}`
);
const md = `# ${t.title}\n\nDate: ${day}\n\n${lines.join("\n\n")}\n`;
await writeFile(join(OUT, `${day}-${slug(t.title)}-${t.id}.md`), md);
console.log(`saved ${++saved}: ${t.title}`);
}
skip += 50;
}
console.log(`Done: ${saved} transcripts in ${OUT}`);
On Free past the trial, raise the 1,100 ms sleep to about 2,100 ms. Add summary{overview action_items} to the transcript query to keep Fireflies' AI notes.
Pick Fireflies in the MinuteHaul web exporter (beta). It runs this same loop from your browser with Fireflies' official API, paces itself under the limits, backs off on 429s, works on the Free plan, and gives you one ZIP with a Markdown file per meeting plus an index. Your 10 most recent meetings are free. Buy unlimited: $19 one-time with a 14-day money-back guarantee.
Where do I get a Fireflies API key? In the Fireflies web app, open Integrations, then Fireflies API, and copy the key. Send it as a Bearer token in the Authorization header to https://api.fireflies.ai/graphql.
How many transcripts can one query return? The transcripts query returns at most 50 per call. Use the skip argument to page through the rest, then fetch each meeting's sentences with the transcript query.
What are the Fireflies API rate limits? Per Fireflies' docs: Free 30 requests a minute and 500 a day, Pro 60 a minute and 5,000 a day, Business and Enterprise 60 a minute per paid seat pooled across the team with no daily cap. A Free user's first API request starts a 14-day trial at Pro limits. The daily quota resets at midnight UTC.
What should I do on a 429? Wait the number of seconds in the Retry-After header before retrying. Fireflies' docs say requests sent during a block still count toward the next window, so retrying in a tight loop can keep you blocked.
Last checked: Oct 26, 2026. Fireflies' API and plans change; verify against Fireflies' docs before relying on details here.