From fireflies-pack
Implements exponential backoff with jitter, retries, and queuing for Fireflies.ai GraphQL API rate limits. Handles 429 errors and too_many_requests for optimized throughput.
npx claudepluginhub jeremylongshore/claude-code-plugins-plus-skills --plugin fireflies-packThis skill is limited to using the following tools:
Handle Fireflies.ai GraphQL API rate limits with exponential backoff and request queuing. Fireflies enforces per-plan limits and per-operation limits.
Diagnose Fireflies.ai GraphQL API errors by code like auth_failed (401), too_many_requests (429), and invalid payloads, with root causes, fixes, and curl auth tests.
Implements Instantly.ai API rate limiting with exponential backoff, jitter, and request queuing in TypeScript. Handles 429 errors, retries, and concurrency for high-throughput integrations.
Handles Klaviyo API rate limits with Retry-After backoff, exponential retries, and queuing for 429 errors to optimize request throughput.
Share bugs, ideas, or general feedback.
Handle Fireflies.ai GraphQL API rate limits with exponential backoff and request queuing. Fireflies enforces per-plan limits and per-operation 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 |
| 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 |
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
);
}
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));
}
throw new Error("Unreachable");
}
import PQueue from "p-queue";
// Business plan: 60 req/min = 1 req/sec safe rate
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));
}
// Batch fetch transcripts without hitting rate limits
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;
}
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 resetIfNewDay(): void {
const today = new Date().toDateString();
if (today !== this.resetDate) {
this.count = 0;
this.resetDate = today;
}
}
}
const budget = new DailyBudgetTracker("pro");
if (!budget.canRequest()) {
console.log("Daily API limit reached. Try again tomorrow.");
}
| 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 |
For security configuration, see fireflies-security-basics.