agentsclimarketplace

Fireflies sdk patterns

Skill jeremylongshore/claude-code-plugins-plus-skills/plugins/saas-packs/fireflies-pack/skills/fireflies-sdk-patterns

'Apply production-ready Fireflies.ai GraphQL client patterns for TypeScript and Python.From its SKILL.md

Install
npx -y skills add jeremylongshore/claude-code-plugins-plus-skills --skill fireflies-sdk-patterns

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

What its file declares

Copied from the file, not written here

The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

7.3 KB, ~1.5k tokens by cl100k_base, as published. Nobody here has run it

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

  • FIREFLIES_API_KEY environment variable set
  • TypeScript 5+ or Python 3.10+
  • Optional: graphql-request for 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

// lib/fireflies.ts
let instance: FirefliesClient | null = null;

export function getFirefliesClient(): FirefliesClient {
  if (!instance) {
    instance = new FirefliesClient();
  }
  return instance;
}

Step 3: Multi-Tenant Factory

const tenantClients = new Map<string, FirefliesClient>();

export function getClientForTenant(tenantId: string): FirefliesClient {
  if (!tenantClients.has(tenantId)) {
    const apiKey = getTenantApiKey(tenantId); // from your secret store
    tenantClients.set(tenantId, new FirefliesClient(apiKey));
  }
  return tenantClients.get(tenantId)!;
}

Step 4: Response Validation with Zod

import { z } from "zod";

const TranscriptSchema = z.object({
  id: z.string(),
  title: z.string(),
  date: z.string(),
  duration: z.number(),
  speakers: z.array(z.object({ id: z.string(), name: z.string() })),
  summary: z.object({
    overview: z.string().nullable(),
    action_items: z.array(z.string()).nullable(),
    keywords: z.array(z.string()).nullable(),
  }).nullable(),
});

type Transcript = z.infer<typeof TranscriptSchema>;

async function getValidatedTranscript(id: string): Promise<Transcript> {
  const client = getFirefliesClient();
  const { transcript } = await client.getTranscript(id);
  return TranscriptSchema.parse(transcript);
}

Step 5: Python Client

import os
from typing import Any
import requests

class FirefliesClient:
    API_URL = "https://api.fireflies.ai/graphql"

    def __init__(self, api_key: str | None = None):
        self.api_key = api_key or os.environ["FIREFLIES_API_KEY"]

    def query(self, gql: str, variables: dict | None = None) -> dict[str, Any]:
        resp = requests.post(
            self.API_URL,
            json={"query": gql, "variables": variables},
            headers={
                "Content-Type": "application/json",
                "Authorization": f"Bearer {self.api_key}",
            },
        )
        data = resp.json()
        if "errors" in data:
            raise Exception(f"Fireflies: {data['errors'][0]['message']}")
        return data["data"]

    def get_transcripts(self, limit: int = 20) -> list[dict]:
        result = self.query("""
            query($limit: Int) {
                transcripts(limit: $limit) {
                    id title date duration organizer_email
                    summary { overview action_items keywords }
                }
            }
        """, {"limit": limit})
        return result["transcripts"]

    def get_transcript(self, transcript_id: str) -> dict:
        result = self.query("""
            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": transcript_id})
        return result["transcript"]

# Usage
client = FirefliesClient()
for t in client.get_transcripts(5):
    print(f"{t['title']} - {t['duration']}min")

Error Handling

PatternUse CaseBenefit
Typed client classAll API callsCentralized auth and error handling
SingletonSingle-tenant appsReuse connection, consistent config
FactoryMulti-tenant SaaSIsolated API keys per customer
Zod validationAPI responsesRuntime type safety, catches schema drift

Output

  • Type-safe GraphQL client with error codes
  • Singleton and factory patterns for different deployment models
  • Zod schemas for runtime response validation
  • Python client with identical API surface

Resources

Next Steps

Apply patterns in fireflies-core-workflow-a for real-world usage.

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 326,144. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.