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:
| Platform | Limit | Window | Notes |
|---|---|---|---|
| 50 posts/24h per account | Rolling 24 hours | Business/Creator accounts only | |
| TikTok | 4 videos/24h per account | Rolling 24 hours | Platform-enforced, not token-level |
| 150 API calls/day per token | UTC midnight reset | Applies to all UGC Post calls | |
| 200 calls/hour per access token | Rolling 1 hour | Page token has separate limits | |
| YouTube | 10,000 quota units/day | Pacific midnight reset | Video upload = 1,600 units |
| Threads | 250 posts/24h per account | Rolling 24 hours | Limit in response headers |
| 100 requests/minute | Rolling 1 minute | Also: 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
- See all platform limits in the scheduling API reference
- Learn how webhooks notify you when a post fails due to rate limiting: webhooks guide
- Full rate limit reference across all platforms: rate limit reference tool