Archive API docs

Rate limits & plans

The Archive API meters /api/v2 on two independent layers: a request-frequency wall and a weighted cost model. The wall is the same on every plan; the weighted bucket is what your plan sizes. Compare the plans below, then price your own query with the calculator.

Layer 1 — the request-frequency wall

Each workspace may send up to 5 requests per second to POST /api/v2, on every plan (the default; it is environment-tunable). This wall counts requests, not cost — a cheap query and an expensive one each consume one unit. Exceed it and the request is rejected with HTTP 429 and a Retry-After header:

{
  "errors": [
    {
      "message": "Rate limit exceeded for this workspace. Retry in 1 second(s).",
      "extensions": { "code": "RATE_LIMIT_EXCEEDED" }
    }
  ]
}

A wall 429 also carries X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers.

Layer 2 — the weighted cost model

The second layer prices each request by how much work it asks for and draws that price from a token bucket: the bucket has a capacity, refills at a steady rate, and each request withdraws its cost. Every workspace drains its own bucket — including a workspace that belongs to an organization, which is priced by the org’s plan but never shares one balance with its siblings. Two rules shape the price:

  • A per-request floor. Every request costs a minimum of 5, covering the fixed overhead of authenticating and loading workspace context. A refund never takes your net cost below this floor.
  • A post-execution refund. A connection’s cost is estimated up front from the page size you request, then reconciled after execution: if a page returns fewer records than you asked for, the unused per-record cost is refunded. Your actual cost is never more than the estimate.

A request that asks for more than the bucket has left is rejected before any field is resolved, with HTTP 429 and a Retry-After header:

{
  "errors": [
    {
      "message": "Rate limit exceeded. Retry after 3 seconds.",
      "extensions": { "code": "RATE_LIMIT_EXCEEDED" }
    }
  ]
}

A rejected request costs you nothing — it does not drain the bucket further. Both layers answer with RATE_LIMIT_EXCEEDED; the message tells you which one you hit, and Retry-After is authoritative either way.

Rate limits by plan

Each workspace draws from a token bucket: the bucket holds up to its capacity, refills at a steady rate, and every request withdraws its weighted cost.

Weighted rate-limit bucket by plan. The request-frequency wall is 5 requests per second on every plan.
Plan Bucket capacity Refill rate Full refill Bucket
Trial 500 5 / s 100 s Own bucket — never pooled, even inside an organization
Startup 5,000 50 / s 100 s Per workspace
Growth 15,000 250 / s 60 s Per workspace
Enterprise 60,000 1,000 / s 60 s Per workspace
Agency 15,000 250 / s 60 s Each org workspace drains its own bucket at Growth numbers
The request-frequency wall — 5 requests per second (300 per minute) — is the same on every plan and is not raised by any of them. Negotiated overrides replace these numbers per workspace or per organization, so read your live quota from the RateLimit-Policy header rather than hard-coding a capacity.

Query cost calculator

A connection’s page cost is search_base + ceil(per_edge × first), plus what you select inside it and any operation surcharge. Every request costs at least 5; every mutation costs a flat 50.

38 weighted cost per request

search_base
30
ceil(0.3 × 20)
+6
edges { node } wrappers
+2
What this buys on each plan
Trial 7 req/min
Startup 78 req/min
Growth 300 req/min *
Enterprise 300 req/min *
Agency 300 req/min *

* capped by the request-frequency wall, not by the bucket.

The calculator opens on a real request — this one:

query.graphql
query ItemsDefault($first: Int, $after: String) {
  items(first: $first, after: $after) {
    totalCount
    edges {
      node {
        id
        provider
        type
        caption
        takenAt
        originalUrl
        archivePublicUrl
        currentEngagement {
          likes
          comments
          views
          earnedMediaValue
        }
      }
    }
    pageInfo {
      hasNextPage
      endCursor
    }
  }
}
variables.json
{
  "first": 10
}
Headers
Authorization: Bearer docs_demo_token_0000000000000000000000
WORKSPACE-ID: 6ccefa76-e8ba-5ab0-9c60-e48a9e235a4a

Reading the RateLimit headers

Every /api/v2 response that carries rate-limit state includes the standard IETF RateLimit-Policy and RateLimit headers. These are your source of truth for your current quota — read them rather than hard-coding any capacity from the table above:

Rate-limit headers
RateLimit-Policy: "<plan>";q=<capacity>;w=<window>
RateLimit: "<plan>";r=<remaining>;t=<reset-epoch>

In RateLimit-Policy, q is the bucket capacity and w is the number of seconds to refill the full bucket. In RateLimit, r is how much you have remaining and t is the epoch second at which the bucket is full again.

Backoff guidance

  • On a 429, honor the Retry-After header — wait the stated number of seconds before retrying.
  • Watch the RateLimit header’s r (remaining) and t (reset) to pace your weighted-cost spend and avoid draining the bucket.
  • Prefer smaller pages and only the fields you need; both reduce cost.