Skip to content
Skillv1.0.0

fondo-rate-limits

Manage rate limits for Fondo-connected services including Gusto API, QuickBooks API, Plaid, and Stripe when building parallel integrations. Trigger: "fondo rate limit", "gusto API limits", "QuickBooks

by jeremylongshore(0) 0 installs
Free
Sign in to install

Free account. Installing gives you the manifest plus copy-paste snippets.

See reviews

About

Imported from jeremylongshore/tons-of-skills-marketplace (skills/.curated/fondo-rate-limits/SKILL.md). Install upstream with npx skills add jeremylongshore/tons-of-skills-marketplace --skill fondo-rate-limits. Copyright stays with the author (MIT).

Fondo Rate Limits

Prerequisites

Confirmed provider limits, an approved concurrency/retry policy, opaque queue telemetry, a finance owner, and synthetic test workload.

Instructions

Honor throttle signals, use bounded backoff and idempotency, route exhausted work to reviewed handling, and reduce load before resuming.

Output

Publish a rate-control receipt with policy version, aggregate throttles, queue outcome, owner, and manual disposition—never financial payloads or credentials.

Examples

Simulate a throttle for a fictional export, verify the retry runs once under its operation ID, and send repeated failure to review without exposing records.

Overview

Fondo itself is a managed tax and accounting service without direct API rate limits, but startups building parallel integrations to the same financial providers Fondo connects to (Gusto, QuickBooks, Plaid, Stripe, Mercury) must coordinate their own API calls to avoid shared-limit conflicts. During Fondo's nightly sync windows, your direct API calls compete for the same provider quotas, making careful scheduling and throttling critical for tax-season workloads and month-end reconciliation batches.

Rate Limit Reference

Endpoint / Provider Limit Window Scope
Gusto payroll API 50 req 1 minute Per access token
QuickBooks Online API 500 req, 10 concurrent 1 minute Per realm (company)
Plaid transactions 100 req 1 minute Per client_id
Stripe reads 100 req/sec 1 second Per API key
Mercury banking API 50 req 1 minute Per API key

Rate Limiter Implementation

class MultiProviderLimiter {
  private limiters: Map<string, { tokens: number; max: number; lastRefill: number; rate: number }> = new Map();

  register(provider: string, maxPerMinute: number) {
    this.limiters.set(provider, {
      tokens: maxPerMinute, max: maxPerMinute,
      lastRefill: Date.now(), rate: maxPerMinute / 60_000,
    });
  }

  async acquire(provider: string): Promise<void> {
    const l = this.limiters.get(provider);
    if (!l) throw new Error(`Unknown provider: ${provider}`);
    const now = Date.now();
    l.tokens = Math.min(l.max, l.tokens + (now - l.lastRefill) * l.rate);
    l.lastRefill = now;
    if (l.tokens >= 1) { l.tokens -= 1; return; }
    const waitMs = (1 - l.tokens) / l.rate;
    await new Promise(r => setTimeout(r, waitMs));
    l.tokens = 0;
  }
}

const limiter = new MultiProviderLimiter();
limiter.register("gusto", 40);      // 40/min leaves room for Fondo syncs
limiter.register("quickbooks", 400); // buffer under 500/min
limiter.register("plaid", 80);

Retry Strategy

async function providerRetry<T>(
  provider: string, fn: () => Promise<Response>, maxRetries = 3
): Promise<T> {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    await limiter.acquire(provider);
    const res = await fn();
    if (res.ok) return res.json();
    if (res.status === 429) {
      const retryAfter = parseInt(res.headers.get("Retry-After") || "15", 10);
      const jitter = Math.random() * 3000;
      await new Promise(r => setTimeout(r, retryAfter * 1000 + jitter));
      continue;
    }
    if (res.status >= 500 && attempt < maxRetries) {
      await new Promise(r => setTimeout(r, Math.pow(2, attempt) * 2000));
      continue;
    }
    throw new Error(`${provider} API ${res.status}: ${await res.text()}`);
  }
  throw new Error("Max retries exceeded");
}

Batch Processing

async function batchReconcile(transactions: any[], provider: string, batchSize = 15) {
  const results: any[] = [];
  for (let i = 0; i < transactions.length; i += batchSize) {
    const batch = transactions.slice(i, i + batchSize);
    const batchResults = await Promise.all(
      batch.map(txn => providerRetry(provider, () =>
        fetch(`${PROVIDER_URLS[provider]}/transactions`, {
          method: "POST", headers: providerHeaders[provider],
          body: JSON.stringify(txn),
        })
      ))
    );
    results.push(...batchResults);
    if (i + batchSize < transactions.length) await new Promise(r => setTimeout(r, 5000));
  }
  return results;
}

Error Handling

Issue Cause Fix
Gusto 429 during payroll sync Fondo nightly sync competing Schedule calls outside midnight UTC window
QuickBooks concurrent limit 10+ parallel requests Cap concurrency at 8 with p-queue
Plaid ITEM_LOGIN_REQUIRED Token expired mid-batch Re-authenticate, resume from last offset
Stripe idempotency conflict Duplicate key on retry Use unique idempotency keys per transaction
Mercury timeout on bulk export Large date range query Split into monthly chunks

Resources

Next Steps

See fondo-performance-tuning.

Use it

Copy one of these into your project. Installing also returns the manifest and these snippets.

yaml
targets:
  - https://api.opensmartroute.ai/api/v1/registry/jeremylongshore-tons-of-skills-marketplace-fondo-rate-limits/manifest   # or paste the manifest below

Manifest

An Open Capability Manifest: the router reads it to know what this does, what it costs and when to pick it.

jeremylongshore-tons-of-skills-marketplace-fondo-rate-limits.ocm.jsonjson
{
  "ocm": "1",
  "id": "jeremylongshore-tons-of-skills-marketplace-fondo-rate-limits",
  "kind": "skill",
  "name": "fondo-rate-limits",
  "description": "Manage rate limits for Fondo-connected services including Gusto API, QuickBooks API, Plaid, and Stripe when building parallel integrations. Trigger: \"fondo rate limit\", \"gusto API limits\", \"QuickBooks throttling\".",
  "publisher": "jeremylongshore",
  "version": "1.0.0",
  "capabilities": {
    "domains": [
      "coding"
    ],
    "tags": [
      "skill-md",
      "saas",
      "accounting",
      "fondo",
      "skills-sh"
    ],
    "languages": [
      "en"
    ]
  },
  "quality_prior": 0.6,
  "examples": [
    "Manage rate limits for Fondo-connected services including Gusto API, QuickBooks API, Plaid, and Stripe when building parallel integrations. Trigger: \"fondo rate limit\", \"gusto API limits\", \"QuickBooks throttling\"."
  ],
  "primary": false,
  "metadata": {
    "source": {
      "provider": "skills.sh",
      "repository": "https://github.com/jeremylongshore/tons-of-skills-marketplace",
      "path": "skills/.curated/fondo-rate-limits/SKILL.md",
      "ref": "HEAD",
      "url": "https://github.com/jeremylongshore/tons-of-skills-marketplace/blob/HEAD/skills/.curated/fondo-rate-limits/SKILL.md",
      "key": "jeremylongshore/tons-of-skills-marketplace/skills/.curated/fondo-rate-limits/SKILL.md"
    },
    "compatibility": "Designed for Claude Code",
    "allowed_tools": [
      "Read,",
      "Write,",
      "Edit"
    ],
    "license": "MIT"
  },
  "instructions": "# Fondo Rate Limits\n\n## Prerequisites\n\nConfirmed provider limits, an approved concurrency/retry policy, opaque queue telemetry, a finance owner, and synthetic test workload.\n\n## Instructions\n\nHonor throttle signals, use bounded backoff and idempotency, route exhausted work to reviewed handling, and reduce load before resuming.\n\n## Output\n\nPublish a rate-control receipt with policy version, aggregate throttles, queue outcome, owner, and manual disposition—never financial payloads or credentials.\n\n## Examples\n\nSimulate a throttle for a fictional export, verify the retry runs once under its opera",
  "cost": {
    "context_tokens": 1254
  }
}

Fetch it by URL: GET /api/v1/registry/jeremylongshore-tons-of-skills-marketplace-fondo-rate-limits/manifest?version=1.0.0

Reviews

Star ratings from people who tried it. One review per account; edit yours any time.

No reviews yet. Install it, try it, and be the first to rate it.