Blog/API Guides

API rate limiting explained — and how to handle 429 errors

June 11, 2026·8 min readAPI Guides

Rate limiting prevents any single client from overwhelming an API. Learn fixed-window vs token-bucket algorithms, how to read rate-limit headers, and how to write retry logic that actually works.

Rate limiting is a technique APIs use to control how many requests a client can make in a given time window. It protects the API server from being overwhelmed, ensures fair access across all users, and prevents accidental (or deliberate) abuse. When you exceed a rate limit, you receive a 429 Too Many Requests response.

The three main rate limiting algorithms

  • Fixed window.Allow N requests per time window (e.g., 100/minute, reset at the start of each minute). Simple but bursty — 200 requests in 2 seconds is fine as long as they're split across a window boundary.
  • Sliding window. Count requests in the rolling N seconds behind the current moment. Smoother than fixed window — prevents boundary bursts. More expensive to compute but fairer.
  • Token bucket. Tokens fill at a steady rate (e.g., 10/second) up to a burst maximum. Requests consume tokens. When empty, requests are rejected. Allows short bursts while enforcing a long-run average rate. Most permissive for bursty-but-bounded traffic.

Most social media platform APIs use fixed-window or sliding-window variants. Aether's own API uses a token bucket model — short bursts are fine, sustained high volume is throttled.

Reading rate limit headers

Well-behaved APIs tell you where you stand before you hit a wall. The standard headers (from the IETF draft and widely adopted):

// Rate limit headers — standard across most APIs
// X-RateLimit-Limit:     Max requests allowed in the current window
// X-RateLimit-Remaining: Requests remaining in the current window
// X-RateLimit-Reset:     Unix timestamp when the window resets
// Retry-After:           Seconds to wait (on 429 responses)

// Reading them in Node.js (fetch):
const response = await fetch("https://api.aetherhq.dev/v1/posts", { ... });
const limit     = response.headers.get("x-ratelimit-limit");
const remaining = response.headers.get("x-ratelimit-remaining");
const reset     = response.headers.get("x-ratelimit-reset");

console.log(`${remaining}/${limit} requests left, resets at ${new Date(Number(reset) * 1000)}`);

Don't wait for a 429 to slow down. Read X-RateLimit-Remaining on every response. When it approaches zero, proactively delay before the next request rather than hammering until you get blocked.

Handling 429 errors — retry with exponential backoff

When you do hit a rate limit, the right response is to wait and retry — not to immediately retry (which makes it worse). Exponential backoff with jitter is the standard pattern:

// Handle 429 errors with exponential backoff
async function postWithRetry(
  aether: Aether,
  params: PostCreateParams,
  maxRetries = 5,
): Promise<Post> {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    try {
      return await aether.posts.create(params);
    } catch (err: unknown) {
      if (!isRateLimitError(err) || attempt === maxRetries) throw err;

      // Check Retry-After header first — it's authoritative
      const retryAfter = err.headers?.["retry-after"];
      const waitMs = retryAfter
        ? parseInt(retryAfter, 10) * 1000
        : Math.min(1000 * 2 ** attempt + Math.random() * 1000, 60_000);

      console.warn(`Rate limited. Retry ${attempt + 1}/${maxRetries} in ${waitMs}ms`);
      await new Promise((r) => setTimeout(r, waitMs));
    }
  }
  throw new Error("Unreachable");
}

function isRateLimitError(err: unknown): err is { status: 429; headers: Record<string, string> } {
  return typeof err === "object" && err !== null && (err as { status?: number }).status === 429;
}

Key points: always check the Retry-After header first — it tells you the exact wait time. Add random jitter to prevent thundering herd scenarios where all your clients retry at the same moment after a window reset.

Social media platform rate limits

Every platform has different limits at different levels — per account, per app, per token. Here are the key limits for all 7 platforms Aether supports:

PlatformLimitWindowNotes
Instagram50 posts/24h per accountRolling 24 hoursBusiness/Creator accounts only
TikTok4 videos/24h per accountRolling 24 hoursPlatform-enforced, not token-level
LinkedIn150 API calls/day per tokenUTC midnight resetApplies to all UGC Post calls
Facebook200 calls/hour per access tokenRolling 1 hourPage token has separate limits
YouTube10,000 quota units/dayPacific midnight resetVideo upload = 1,600 units
Threads250 posts/24h per accountRolling 24 hoursLimit in response headers
Reddit100 requests/minuteRolling 1 minuteAlso: 1 post per 10 minutes (anti-spam)

How Aether handles rate limits for you

When you submit a post via Aether, rate limit validation happens server-side before the post enters the queue. If the submission would exceed a platform limit, you get a structured 429 response with the platform name, limit type, and reset time — before wasting a platform API call.

For scheduled posts in the queue, Aether's worker handles platform-level throttling automatically. Posts are spaced within platform limits, retried with backoff on transient errors, and moved to failed status (with a webhook) only after all retries are exhausted. You don't write any backoff logic.

Next steps

Ready to build?

One API for Instagram, TikTok, LinkedIn, Facebook, YouTube, Threads, and Reddit. Free tier, no credit card required.

Get started free →