429 Too Many Requests. Branch on error.code and honor Retry-After for request or signup email limits.
Per-minute burst limit
Authenticated requests are limited to 6,000 requests per 60 seconds (100 per second) per API key. Unauthenticated requests (missing or invalid key) are limited to 120 requests per 60 seconds per IP address. The window is fixed, not rolling. Each 60-second wall-clock interval is its own counter; all requests within that interval share it, and the counter resets to 0 in a single step at the next boundary. Available budget jumps from0 back to the full bucket size (6000 for authenticated API keys, 120 for unauthenticated IP buckets) instantaneously at the boundary, rather than aging out one slot at a time. Trust X-RateLimit-Reset for the exact reset timestamp; do not assume requests age out individually.
Headers
Successful responses and burst-limit429s carry three headers so you can monitor consumption:
Do not require these headers on error responses. Rejections that happen before the burst counter is consulted, including authentication and authorization failures and monthly-limit rejections, can omit all three. Code that reads them unconditionally will break on those responses. This is how the headers have always behaved; it is not a new quota policy.
A 429 in this case adds one more header:
Example error body
Retry guidance
This 429 is retryable. Recommended pattern:- Honor
Retry-Afteras the minimum wait. Do not retry sooner. - For retries beyond the first, apply exponential backoff with jitter (e.g. base =
Retry-After, double on each attempt, add random jitter in[0, 1s], cap at a few minutes). - Cap the total number of attempts (e.g. 3 to 5) and surface the failure if exhausted, rather than retrying indefinitely.
- Treat
X-RateLimit-Remainingas a leading indicator: if it is near zero on a successful response, slow down voluntarily before the next request to avoid the 429 entirely.
Signup email allowances
Agent signup is always available through REST and signed-out MCP, subject to the request and email limits below.POST /signups always uses 120 requests per minute per IP, even when a
credential is supplied. Anonymous MCP discovery/signup uses a separate fixed
window of 6,000 requests per minute per IP; that initial shared-provider-IP
budget is pending confirmation. These are request budgets, not email budgets.
REST and MCP signup share verification allowances with web signup:
For signup verification emails only, requests from Anthropic’s or OpenAI’s
published connector egress ranges use one shared bucket per provider instead
of the ordinary IP bucket. Each provider has its own bucket. Recipient limits
are unchanged. Other auth email purposes, including password resets and user
invitations, keep the ordinary per-IP limits even on provider IPs.
The ranges are pinned in code from the published lists fetched on October 29,
2026; they are not fetched at runtime:
New, pending and existing accounts consume the same allowance. Changing
User-Agent, rotating recipient emails, or switching between one provider’s
matching IPs does not bypass its shared signup bucket. A 202, absent email or
429 does not reveal account existence. Retrying can renew a pending link and
invalidate the previous one.
The X-RateLimit headers accompany completed REST signup responses and
request-limit rejections; early parameter exceptions may omit them. Use
Retry-After for either signup 429 rather than inferring a wait from the request
budget. For example, an email allowance rejection can return:
Monthly per-company limit
The company’s plan determines its monthly API allowance, independent of the per-minute burst limit:
To read the plans and their standard limits at runtime instead of copying this table, call
GET /plans. It returns null for every Enterprise limit, which is set by contract. See Plans and limits. For this company’s own limit and how many calls it has used this month, call GET /usage and read api_calls. See Usage.
The limit is per company, not per API key. All keys for a company share the same pool.
Enterprise is enabled internally by Finta for contract-managed companies. It bypasses commercial monthly API/MCP quotas and ordinary subscription lockouts, including when Stripe is absent or canceled. Requests are still counted. Valid credentials, company/user permissions, company closure, the independent linked billing-invoice gate, request validation, payload bounds and per-minute abuse limits still apply. Disabling Enterprise restores the ordinary plan gates without changing Stripe billing.
Finta support can set a temporary limit override for a company for the current month. It applies to every user and every API key in the company, and usage is still the company’s total; there is no separate allowance for one user or one key. The override changes both the cap that applies and the number quoted in the error message, and it expires at the end of the month it was set in. The error.code and the do-not-retry rule are the same either way, so read the allowance from the message, or from api_calls.limit in GET /usage, where api_calls.custom_limit is true while an override applies, rather than assuming the plan’s number from the table above.
Counts reset at midnight Pacific Time (US & Canada) on the 1st of each month. This is the Finta application’s configured time zone; the cap is computed in that zone, not in UTC. Consumers in other time zones should convert that local-midnight Pacific boundary to their own clock. The absolute UTC offset shifts by one hour twice a year for daylight saving (PST is UTC-8, PDT is UTC-7), so consumers needing exact second-level precision near month boundaries should account for the active offset on the date in question.
What counts: after the company is onboarded, authenticated requests that reach the monthly meter count regardless of HTTP status. A 400 from bad parameters counts the same as a 200. Unauthenticated requests (401) do not count, and blocked requests (after hitting the monthly limit) are also not counted, so hitting the cap does not extend the cap-exceeded period.
What doesn’t count: GET /onboarding and PATCH /onboarding are always free, even after onboarding or the monthly cap. GET /plans and GET /usage are exempt from the monthly limit. They are never counted and never refused with monthly_limit_exceeded, even after the company has used its whole allowance, so a caller at its limit can still see what upgrading offers and read api_calls.stopped. The per-minute burst limit still applies to them, with the usual Retry-After and X-RateLimit-* headers. GET /billing, which reads what the company pays, is not exempt and counts like any other request.
Onboarding calls
Until the company is onboarded, no API or MCP call counts toward the monthly allowance, and reaching that allowance does not block onboarding. Calls are still logged withcounted: false. The onboarding gate limits which endpoints can answer; quota exemption does not bypass that gate or the usual permissions and billing checks.
GET /onboarding and PATCH /onboarding, and MCP get_onboarding and update_onboarding, never count toward their respective monthly allowances, after setup too. Their per-minute burst and existing security limits still apply. This lets a company on Formation complete setup without spending its 10-call monthly allowance.
The independent billing-invoice gate runs before monthly allowance checks, including on GET /plans and GET /usage. Its 403 invoice_overdue and 503 invoice_status_unavailable refusals are not counted. Pay overdue linked invoices rather than retrying continuously; for a temporary verification failure, honor Retry-After: 60 and use bounded backoff. Existing security burst limits are unchanged.
The 1099 filing endpoints use the same allowance. List returns individual records and full yearly summaries in one call; no additional summary request is needed. Retrieving a filing again to refresh an expired document link consumes another API call.
Example error body
Monthly API limit reached. Your temporary limit allows 1000 calls for this company this month. Resets on November 1, 2026.
Retry-After is not sent in this case. The X-RateLimit-* burst-window headers may be present or absent here, and either way they describe the burst window rather than the monthly cap. Nothing in the response reports remaining monthly quota.
Retry guidance
This 429 is not retryable in the short term. The only meaningful remediation is to upgrade the plan or wait until the 1st of the next month. Recommended pattern:- Branch on
error.codefirst.rate_limit_exceededis the burst case (retryable, see above).monthly_limit_exceededis this case. - If the code is
monthly_limit_exceeded, stop retrying. Surface the error to your user with the reset date from the message body, or page the operator to upgrade the plan.GET /plansstill answers at the limit if you want to show what each plan allows, andGET /usagestill answers too: once itsapi_calls.stoppedisfalse, for example after an upgrade, calls can resume. - SDKs should branch on
error.codedirectly. MissingRetry-Afterdoes not universally mean never retry: export capacity can free up when an existing job finishes.
Report export capacity
A company may have at most five unfinished API exports, across all submitters. New requests above that cap return429 report_export_limit_exceeded without
creating or enqueueing a job. Existing-key replays and retrieval remain available,
subject to the ordinary API request limits. A terminal success or failure releases
its slot. Enterprise does not bypass this export-capacity guard.
This response has no Retry-After, because generation finish time is unknown:
400 invalid_date_range, not 429. PDF exports also
support at most 13 displayed periods; use coarser grouping, CSV or XLSX for more columns.
See Report Exports.
Sheets selection limits
A selected sheet read accepts up to 100 bounded ranges and 10,000 selected cells total; overlapping selections each count toward the total. List/search pagination accepts 1–500 results, default 100. Exceeding a selection limit is400 invalid_request, not a rate-limit 429: reduce the selection before retrying.
Calculation is synchronous and bounded. An HTTP 200 with calculation.status: unavailable omits value matrices rather than inventing results; retry only the needed ranges with bounded backoff. There is no calculation job to poll. Shared request-rate and monthly limits still apply.
Sheets mutation budget
Custom sheet creation and editing accept at most 500 expanded operations per request, shared across all worksheets, ranges and charts. Each non-null cell write and each formatted cell counts separately. Tab setup, chart operations, renames, structural edits, automatic grid expansion and any writes needed to preserve formulas also count. Clears count even for blank cells: contents or formats costs one per cell; all costs two. Copy/fill can emit both value and format edits. Format, clear and copy/fill selection rectangles are bounded to 500 cells. Null entries skip their cell writes; sparse rectangles can exceed 500 cells in area within company grid limits. Template seeding is outside this operation budget. Splitting ranges within one request does not reset the budget. Exceeding it returns400 invalid_request, not a usage-quota 429, and saves nothing. Reduce the batch before retrying; for larger custom documents, create a smaller initial document and populate it with sequential PATCH calls. Each PATCH uses the previous successful response’s revision. Splitting into separate calls is not atomic across those calls: earlier successful calls stay committed if a later one fails. The normal API/MCP call meters still apply independently to each call. A document is limited to 100 tabs, 50 charts per tab and a 1 MiB normalized snapshot; company grid limits normally allow 500 rows and 52 columns.
Creation and PATCH’s optional return_ranges use the same 100-selection/10,000-cell bound as reads. A saved mutation can return a calculation error or unavailable status; retain its ID/revision and reread selected cells rather than repeat the mutation solely to recalculate.
Best practices
- Branch on
error.code, not the status code alone. Burst, monthly and export-capacity errors all use 429 but require different recovery. A generic retry loop can waste calls on monthly exhaustion or export capacity. - Check headers proactively. Monitor
X-RateLimit-Remainingand slow down before you hit the burst limit. - Use larger page sizes. When paginating, set
limitup to 500 to pull more data per request and reduce total calls. - Cache responses. If you are repeatedly pulling the same data, cache it on your end to conserve your monthly quota.
- Check connection requests sparingly. Polling
GET /integrations/{key}/connectevery 10 seconds for a link nobody opens costs about 90 calls over an OAuth link’s 15 minutes, or 180 over a Plaid Hosted Link’s 30 minutes. Where you can talk to the user, ask them to say when they have approved, then check once. See Polling and API usage. - Batch edits, then back off when polling. A bulk update of up to 5,000 transactions costs one call to submit, not one per transaction. Each identical replay, each poll of
GET /jobs/{id}, and each page of its errors is another call, so back off between polls and stop atsuccessorfailed. See Polling and retention. - Group totals in one call. To rank merchants or chart a category month by month, use
GET /aggregations/totalsinstead of callingGET /aggregations/totalonce per merchant or per month. One grouped request answers what often took 100 or more per-merchant calls. - Upload in full chunks. A transaction upload takes up to 500 rows per call, and a clean file of 500 rows or fewer takes one call with
commit: true. Every call counts, including a status check that sends onlyupload_id, so wait between checks on animportingupload. - Sync transactions incrementally. If you keep a local copy of transactions, use
updated_afterto pull only what changed since your last run instead of re-reading every page to discover that a few rows changed.