Skip to main content
AI/MLjeremylongshore

fondo-sdk-patterns

'Build internal tools that consume Fondo financial data exports with

Stars
2,267
Source
jeremylongshore/claude-code-plugins-plus-skills
Updated
2026-05-31
Slug
jeremylongshore--claude-code-plugins-plus-skills--fondo-sdk-patterns
View on GitHubRaw SKILL.md

// install — copy + paste into any project

mkdir -p .claude/skills && curl -fsSL https://raw.githubusercontent.com/jeremylongshore/claude-code-plugins-plus-skills/HEAD/plugins/saas-packs/fondo-pack/skills/fondo-sdk-patterns/SKILL.md -o .claude/skills/fondo-sdk-patterns.md

Drops the SKILL.md into .claude/skills/fondo-sdk-patterns.md. Works with Claude Code, Cursor, and any agent that loads SKILL.md files from .claude/skills/.

Fondo SDK Patterns

Overview

Production-ready patterns for integrating with Fondo tax and accounting data. Fondo is a managed bookkeeping platform that syncs through QuickBooks Online and payroll providers. Integration uses the FONDO_API_KEY-authenticated REST endpoints for exports, the QuickBooks Online API for GL data, and structured CSV parsing with Zod validation for bulk imports.

Singleton Client

const FONDO_BASE = 'https://api.fondo.com/v1';
let _client: FondoClient | null = null;
export function getClient(): FondoClient {
  if (!_client) {
    const apiKey = process.env.FONDO_API_KEY;
    if (!apiKey) throw new Error('FONDO_API_KEY must be set — get it from your Fondo dashboard');
    _client = new FondoClient(apiKey);
  }
  return _client;
}
class FondoClient {
  private headers: Record<string, string>;
  constructor(apiKey: string) { this.headers = { 'Authorization': `Bearer ${apiKey}`, 'Content-Type': 'application/json' }; }
  async getTransactions(start: string, end: string): Promise<FondoTransaction[]> {
    const res = await fetch(`${FONDO_BASE}/transactions?start=${start}&end=${end}`, { headers: this.headers });
    if (!res.ok) throw new FondoError(res.status, await res.text()); return res.json();
  }
  async getAccounts(): Promise<FondoAccount[]> {
    const res = await fetch(`${FONDO_BASE}/accounts`, { headers: this.headers });
    if (!res.ok) throw new FondoError(res.status, await res.text()); return res.json();
  }
}

Error Wrapper

export class FondoError extends Error {
  constructor(public status: number, message: string) { super(message); this.name = 'FondoError'; }
}
export async function safeCall<T>(operation: string, fn: () => Promise<T>): Promise<T> {
  try { return await fn(); }
  catch (err: any) {
    if (err instanceof FondoError && err.status === 429) { await new Promise(r => setTimeout(r, 5000)); return fn(); }
    if (err instanceof FondoError && err.status === 401) throw new FondoError(401, 'Invalid FONDO_API_KEY');
    throw new FondoError(err.status ?? 0, `${operation} failed: ${err.message}`);
  }
}

Request Builder

class FondoQuery {
  private params: Record<string, string> = {};
  dateRange(start: string, end: string) { this.params.start = start; this.params.end = end; return this; }
  category(cat: string) { this.params.category = cat; return this; }
  accountId(id: string) { this.params.account_id = id; return this; }
  rndOnly() { this.params.is_rnd = 'true'; return this; }
  limit(n: number) { this.params.limit = String(n); return this; }
  build() { return new URLSearchParams(this.params).toString(); }
}
// Usage: new FondoQuery().dateRange('2025-01-01','2025-03-31').rndOnly().build();

Response Types

interface FondoTransaction {
  id: string; date: string; description: string; amount: number;
  category: string; account: string; is_rnd: boolean; vendor: string;
}
interface FondoAccount {
  id: string; name: string; type: 'asset' | 'liability' | 'equity' | 'revenue' | 'expense';
  balance: number; currency: string;
}
interface FondoReport {
  id: string; period: string; type: 'trial_balance' | 'profit_loss' | 'balance_sheet';
  generated_at: string; rows: Array<{ account: string; debit: number; credit: number }>;
}
interface FondoRnDCredit {
  tax_year: number; qualifying_expenses: number; credit_amount: number;
  status: 'draft' | 'filed' | 'approved';
}

Testing Utilities

export function mockTransaction(overrides: Partial<FondoTransaction> = {}): FondoTransaction {
  return { id: 'txn-001', date: '2025-03-15', description: 'AWS hosting',
    amount: 450.00, category: 'Cloud Infrastructure', account: 'Operating Expenses',
    is_rnd: true, vendor: 'Amazon Web Services', ...overrides };
}
export function mockAccount(overrides: Partial<FondoAccount> = {}): FondoAccount {
  return { id: 'acct-001', name: 'Operating Expenses', type: 'expense',
    balance: 12500.00, currency: 'USD', ...overrides };
}

Error Handling

Pattern When to Use Example
safeCall wrapper All Fondo API calls Structured error logging with operation context
Retry on 429 Bulk transaction exports 5s backoff before retry
Zod validation CSV import parsing Reject malformed rows before DB insert
Auth validation Client init Fail fast on missing FONDO_API_KEY

Resources

Next Steps

Apply patterns in fondo-core-workflow-a.