Rate Limits

How request quotas, rate limiting, and overage billing work.

Per-Tier Limits

PlanMonthly RequestsRate LimitOverage
Free1,000/mo30 req/minHard cap
Starter25,000/mo100 req/min$0.003/req
Pro100,000/mo200 req/min$0.002/req
Scale250,000/mo500 req/min$0.001/req

Sliding Window Algorithm

Rate limits use a 60-second sliding window per API key. The window moves continuously—there is no fixed reset boundary. If you send 100 requests at second 0 and wait 30 seconds, you will have approximately 50 requests available as the oldest requests age out of the window.

Rate Limit Headers

Every API response includes three headers that describe your current rate limit status:

HeaderDescriptionExample
X-RateLimit-LimitMaximum requests per window100
X-RateLimit-RemainingRequests remaining in the current window87
X-RateLimit-ResetUnix timestamp when the window resets1711843200

Handling 429 Responses

When you exceed the rate limit, the API returns a 429 Too Many Requests response with a Retry-After header indicating how many seconds to wait:

429 Response
{
  "error": {
    "status": 429,
    "message": "Rate limit exceeded. Retry after 12 seconds.",
    "requestId": "req_abc123def456"
  }
}

// Response headers:
// Retry-After: 12
// X-RateLimit-Limit: 100
// X-RateLimit-Remaining: 0
// X-RateLimit-Reset: 1711843200

Retry Strategy

Implement exponential backoff with the Retry-After header as your baseline:

TypeScript — retry with backoff
async function fetchWithRetry(url: string, options: RequestInit, maxRetries = 3) {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    const response = await fetch(url, options);

    if (response.status !== 429) return response;

    const retryAfter = parseInt(response.headers.get("Retry-After") ?? "5", 10);
    const backoff = retryAfter * Math.pow(2, attempt);
    await new Promise((resolve) => setTimeout(resolve, backoff * 1000));
  }

  throw new Error("Rate limit exceeded after max retries");
}

Server-Side Caching

Responses are cached server-side with per-route TTLs. The X-Cache header indicates whether the response was served from cache. Cached responses still count toward your monthly quota.

Route PatternTTL
/positions/today, /moon/today, /aspects/today, /almanac5 minutes
/horoscope/daily, /horoscope/all15 minutes
All other endpoints1 hour

Related