Back to Blog
TutorialApril 11, 2026·7 min read

API Rate Limiting Best Practices: How to Handle 429 Errors Gracefully

AC

Alex Chen

Developer Advocate

Share:

Introduction

Every production API has rate limits. When your application hits a 429 "Too Many Requests" response, how you handle it determines whether your users see graceful degradation or a broken experience.

This guide covers robust rate limit handling with InstantAPI and any other API.

Understanding Rate Limit Headers

InstantAPI returns standard headers with every response:

  • X-RateLimit-Limit — Maximum requests per window (100/minute)
  • X-RateLimit-Remaining — Requests remaining in current window
  • X-RateLimit-Reset — Unix timestamp when the window resets
  • Retry-After — Seconds to wait before retrying (on 429 responses)

Strategy 1: Exponential Backoff with Jitter

Each retry waits exponentially longer, with random jitter to prevent thundering herd problems:

async function fetchWithRetry(url, options, maxRetries = 3) {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    const response = await fetch(url, options);
    if (response.status !== 429) return response;
    if (attempt === maxRetries) throw new Error("Max retries exceeded");

    const retryAfter = response.headers.get("Retry-After");
    const baseDelay = retryAfter
      ? parseInt(retryAfter) * 1000
      : Math.pow(2, attempt) * 1000;
    const jitter = Math.random() * baseDelay * 0.5;
    await new Promise(r => setTimeout(r, baseDelay + jitter));
  }
}

Strategy 2: Proactive Rate Tracking

Track your usage proactively instead of waiting for errors:

class RateLimitTracker {
  constructor() {
    this.remaining = 100;
    this.resetAt = Date.now();
  }

  updateFromHeaders(headers) {
    this.remaining = parseInt(headers.get("X-RateLimit-Remaining") || "100");
    this.resetAt = parseInt(headers.get("X-RateLimit-Reset") || "0") * 1000;
  }

  async waitIfNeeded() {
    if (this.remaining <= 5) {
      const waitMs = Math.max(0, this.resetAt - Date.now());
      if (waitMs > 0) await new Promise(r => setTimeout(r, waitMs));
    }
  }
}

Strategy 3: Request Queue

For high-volume applications, queue requests at a controlled rate:

class RequestQueue {
  constructor(maxPerMinute = 90) {
    this.queue = [];
    this.interval = (60 / maxPerMinute) * 1000;
    this.processing = false;
  }

  enqueue(fn) {
    return new Promise((resolve, reject) => {
      this.queue.push({ fn, resolve, reject });
      this.process();
    });
  }

  async process() {
    if (this.processing) return;
    this.processing = true;
    while (this.queue.length > 0) {
      const { fn, resolve, reject } = this.queue.shift();
      try { resolve(await fn()); } catch (err) { reject(err); }
      await new Promise(r => setTimeout(r, this.interval));
    }
    this.processing = false;
  }
}

InstantAPI Tips

InstantAPI's limit is 100 requests per minute per key. For higher throughput:

  • Use the batch endpoint — 20 tasks per request, counts as 1 rate-limited call
  • Distribute across API keys — create multiple keys from your dashboard
  • Cache responses — InstantAPI caches identical requests automatically
  • Contact us for enterprise rate limits above 100 req/min
  • Get started — 10 free calls, 100 req/min, built-in caching. Related:

    Ready to try InstantAPI?

    Sign up today and get 10 free credits to explore all 6 AI capabilities. No credit card required.

    Get 10 Free Credits