Rate limits

Rate limits are applied per organization, not per API key. Issuing more keys spreads work across services; it does not raise your throughput. Each key also carries the same per-key ceiling, so one runaway worker cannot starve the rest of your integration.

Response headers

Every response carries your current budget, whether or not it succeeded:

  • Name
    X-RateLimit-Limit
    Type
    integer
    Description

    Requests allowed in the current window for this endpoint class.

  • Name
    X-RateLimit-Remaining
    Type
    integer
    Description

    Requests left in the current window.

  • Name
    X-RateLimit-Reset
    Type
    unix timestamp
    Description

    When the current window resets.

  • Name
    Retry-After
    Type
    seconds
    Description

    Sent on 429 only. Wait this long before retrying.

Read these rather than inferring your budget from failures. Retry-After is authoritative on a 429 — prefer it over a fixed backoff schedule.

What your plan allows

Limits differ by endpoint class, because a point-in-time snapshot or a modeling call costs far more to serve than a read. All windows are 60 seconds.

PlanReadSnapshotModelingMCPBulkSystemVerify
Free6015—10—605
Developer30075—150—3005
Growth1,200300600600—1,2005
Scale3,0007501,5001,5001203,0005
EnterpriseNegotiatedNegotiatedNegotiatedNegotiatedNegotiatedNegotiated5

Read covers company resolution, statements, filings, coverage, time series and the other data routes — the bulk of most integrations. Snapshot covers point-in-time snapshots under /v1/edgar/as-of and query execution (POST /v1/query/execute); replaying a stored result under /v1/query/replay is a read. Snapshot and read are separate budgets: spending one leaves the other untouched. Modeling covers the /v1/modeling routes, which Growth and above include. MCP covers the MCP server. Bulk covers the bulk export routes, which Scale and Enterprise include. System covers the metadata and ingestion-status routes under /v1/system. Verify covers verifying a replay token under /v1/query/verify, which needs no key, so it is counted by caller address rather than by plan: every caller gets the same 5 a minute, and all callers together share a ceiling of 30 a minute.

A dash means the plan includes no route in that class. Enterprise limits are set in each agreement, except Verify, which is the same for everyone. Whatever your plan, your entitlement is authoritative and is reported in the developer portal.

A rate limit is not an entitlement. Every plan includes MCP, but a tool that wraps a modeling, reconciliation or AI route needs the plan that route needs. Check what your plan grants, not only what it meters.

429 handling

When your client is throttled, the API returns HTTP 429 with a Retry-After header and the standard error envelope.

Recommended handling:

  1. stop issuing new requests for that endpoint class
  2. wait for Retry-After seconds
  3. resume with bounded concurrency rather than a burst retry

A 429 is a backoff signal, not a failure. Do not treat it as a permanent error, and do not retry immediately — that consumes the next window before your own work reaches it.

Client strategy

  • Watch X-RateLimit-Remaining and slow down before you are throttled.
  • Prefer sequential or modestly concurrent pagination unless you have measured headroom.
  • Cache stable lookup results such as company resolution.
  • Separate interactive traffic from large historical extraction jobs, so a backfill cannot throttle a user-facing request.

Response cost

Routes differ in how much work one request represents, which matters more than request count when planning a job.

  • A metric time series covers a company's whole reporting history in one request. It resolves in a fixed number of queries regardless of how many years it spans, so requesting a longer history costs little more than a shorter one. Prefer one wide request over a year-by-year loop.
  • Listings return metadata rather than payloads. Narrative disclosure listings carry each disclosure's char_count instead of its text, because a single filing can hold hundreds of kilobytes across its text blocks. Read the text one disclosure at a time, and use char_count to decide what is worth fetching.

ETags

Every response carries a strong ETag over its body:

etag: "23cd694b761edec2ec1c09709a65f26338538979d140d50a2021d3cecb122c43"

It is stable across repeated requests for unchanged content, so store it beside your cached copy and send it back on the next poll.

Conditional requests

Send the stored validator as If-None-Match. When the representation still matches, Arche answers 304 Not Modified with no body:

curl -X GET "https://api.arche.fi/v1/edgar/companies/0000320193" \
  -H "X-Api-Key: $ARCHE_API_KEY" \
  -H 'If-None-Match: "23cd694b761edec2ec1c09709a65f26338538979d140d50a2021d3cecb122c43"' \
  -H "Accept: application/json"

The 304 repeats the ETag and cache metadata, so your cached copy stays valid and you can keep polling with the same validator. A changed representation answers 200 with the new body and a new ETag.

  • Name
    weak comparison
    Type
    behavior
    Description

    W/"abc" matches "abc", per RFC 9110.

  • Name
    If-None-Match: *
    Type
    behavior
    Description

    Matches any existing representation.

  • Name
    several validators
    Type
    behavior
    Description

    A comma-separated list matches if any one of them does.

Only GET and HEAD are conditional, and only successful responses — an error is never answered 304.

Was this page helpful?