Fondo Rate Limits
SkillDev tools'Manage rate limits for Fondo-connected services including Gusto API,
Use Fondo Rate Limits in Claude, ChatGPT or Ahel Desktop
Free. Sign in, add Fondo Rate Limits and connect your AI. About a minute.
Also: Claude Code · Cursor · Codex
Then ask your AI: use the Fondo Rate Limits skill
Details
Instructions available. Your AI can read the instructions. Execution depends on the setup they require.
Account requirements not reviewed. Check the skill instructions before use; Ahel provides instructions and does not run this skill.
No other account needed.
Add Ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.
What this skill tells your AI
The instructions your AI receives, as published by jeremylongshore/tons-of-skills-marketplace in skills/.curated/fondo-rate-limits/SKILL.md and read by Ahel’s review.
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.
Signals
- GitHub stars
- 3k
- Forks
- 415
- Last commit
- Oct 2026
Advanced
- Item type
- skill
- Key
fondo-rate-limits- Source
- github.com/jeremylongshore/tons-of-skills-marketplace