Docs/Api Reference/Rate Limits

Rate Limits

Anvil enforces rate limits to protect the platform and keep response times predictable. This page documents the exact numbers and how to build clients that handle them gracefully.

Limits by Plan

PlanPer minutePer dayConcurrent requests
Free201,0002
Starter6010,0005
Pro300100,00020
Enterprise1,000Unlimited100

Limits are per tenant, not per API key. Spreading traffic across multiple keys does not multiply your quota.

How the Limits Work

We use a sliding-window counter at the API gateway. Each request consumes one token from both the per-minute and per-day buckets. When either bucket empties, subsequent requests return HTTP 429 until the window slides forward.

Concurrency is enforced separately: if you have 20 in-flight requests on a Pro plan, the 21st is queued for up to 500ms then rejected with 429.

Headers

Every response includes these headers so clients can self-regulate:

X-RateLimit-Limit: 300
X-RateLimit-Remaining: 247
X-RateLimit-Reset: 1713420060
Retry-After: 12
  • X-RateLimit-Limit: the ceiling for the current window.
  • X-RateLimit-Remaining: tokens left before hitting the limit.
  • X-RateLimit-Reset: Unix timestamp (seconds) when the bucket refills.
  • Retry-After: only present on 429; seconds to wait before retrying.
  • Handling 429s

    Well-behaved clients honor Retry-After and back off with jitter:

    async function callAnvil(path) {
      for (let attempt = 0; attempt < 5; attempt++) {
        const res = await fetch(`https://api.anvilhk.com/v1${path}`, opts);
        if (res.status !== 429) return res;
        const wait = Number(res.headers.get('Retry-After') ?? 1) * 1000;
        await new Promise(r => setTimeout(r, wait + Math.random() * 500));
      }
      throw new Error('Rate limited — gave up after 5 retries');
    }

    Do NOT retry immediately on 429. Tight retry loops will keep you in a rate-limited state indefinitely.

    Bulk Endpoints

    If you need to process thousands of records, use the bulk endpoints (POST /v1/leads/bulk, POST /v1/contacts/bulk) which accept up to 500 records per call and count as a single request against your quota.

    For very large exports use the async export API, which runs in the background and notifies you via webhook when the file is ready.

    Raising Limits

    Enterprise customers can request custom limits by contacting support with details of the expected traffic pattern. We typically approve increases within 24 hours for legitimate use cases.

    If you are hitting limits regularly on a Pro plan, consider:

  • Caching frequently-read resources (lead lists change slowly — cache for 60s).
  • Switching from polling to webhooks for real-time data.
  • Batching writes via bulk endpoints.