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 | too_many_requests |
shareMeeting | 10 per hour (up to 50 emails each) | too_many_requests |
deleteTranscript | 10 per minute | too_many_requests |
uploadAudio | Varies by plan | too_many_requests |
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();
}
baseDelay = * .(, attempt);
jitter = .() * ;
delay = .(baseDelay + jitter, );
.();
( (r, delay));
}
();
}
Step 3: Request Queue for Batch Operations
import PQueue from "p-queue";
const firefliesQueue = new PQueue({
concurrency: 1,
interval: 1100,
intervalCap: 1,
});
async function queuedQuery<T>(query: string, variables?: Record<string, any>): Promise<T> {
return firefliesQueue.add(() => firefliesQueryWithRetry<T>(query, variables));
}
async function batchFetchTranscripts(ids: string[]) {
const results = [];
for (const id of ids) {
const data = await queuedQuery(`
query GetTranscript($id: String!) {
transcript(id: $id) {
id title date duration
summary { overview action_items }
}
}
`, { id });
results.push(data);
}
return results;
}
Step 4: Free/Pro Plan Daily Budget Tracker
class DailyBudgetTracker {
private count = 0;
private resetDate = new Date().toDateString();
private readonly dailyLimit: number;
constructor(plan: "free" | "pro" | "business") {
this.dailyLimit = plan === "business" ? Infinity : 50;
}
canRequest(): boolean {
this.resetIfNewDay();
return this.count < this.dailyLimit;
}
record(): void {
this.resetIfNewDay();
this.count++;
}
remaining(): number {
this.resetIfNewDay();
return Math.max(0, this.dailyLimit - this.count);
}
private (): {
today = ().();
(today !== .) {
. = ;
. = today;
}
}
}
budget = ();
(!budget.()) {
.();
}
Error Handling
| Scenario | Detection | Action |
|---|
| 429 response | code: "too_many_requests" | Exponential backoff |
| Daily limit hit (Free/Pro) | Track request count | Wait until next day |
addToLiveMeeting throttle | 3 per 20 min | Queue with 7-min spacing |
| Burst of webhook events | Many transcripts at once | Queue transcript fetches |
Output
- Rate-limit-aware GraphQL client with automatic retry
- Request queue preventing burst-induced throttling
- Daily budget tracker for Free/Pro plans
Resources
Next Steps
For security configuration, see fireflies-security-basics.