Rate Limits

The PostCapture API enforces rate limits to ensure fair usage and service stability.

Current Limits

10
per minute
Requests
60
seconds
Window
Per
user
Scope

Rate limits are shared across all API keys belonging to the same user account. Creating multiple keys does not increase your rate limit budget.

How It Works

PostCapture uses a fixed-window rate limiter. A 60-second window starts with your first request. After 10 requests within that window, subsequent requests receive a 429 response until the window resets.

Window start: Timestamp of your first request in the current window.

Counter: Incremented with each request. Resets to 1 when the window expires.

Expiry: 60 seconds after window start. Your next request after expiry starts a new window.

429 Response Format

When rate limited, the API returns a JSON body and a Retry-After header (in seconds):

HTTP 429
1{
2 "error": "Rate limit exceeded",
3 "message": "Too many requests. Limit is 10 per minute. Try again in 42s.",
4 "retryAfterMs": 42000
5}
Header / FieldDescription
Retry-AfterSeconds until the rate limit window resets (HTTP header).
retryAfterMsMilliseconds until the window resets (JSON body, more precise).

Best Practices

  • Respect Retry-After. Wait the specified duration before retrying instead of polling aggressively.
  • Implement exponential backoff. If you hit the limit, wait progressively longer between retries (e.g., 1s, 2s, 4s).
  • Batch your work. If you need many screenshots, space requests evenly within the rate limit window.
  • Cache results. Screenshots are cached for 60 seconds on the CDN. Avoid re-requesting the same URL within that window.

Retry Example

1async function screenshotWithRetry(postUrl, apiKey, maxRetries = 3) {
2 const url = new URL("https://postcapture.com/api/screenshot");
3 url.searchParams.set("postUrl", postUrl);
4 url.searchParams.set("apiKey", apiKey);
5
6 for (let attempt = 0; attempt <= maxRetries; attempt++) {
7 const res = await fetch(url);
8
9 if (res.ok) return res;
10
11 if (res.status === 429) {
12 const retryAfter = parseInt(res.headers.get("Retry-After") || "10");
13 console.log(`Rate limited. Retrying in ${retryAfter}s…`);
14 await new Promise((r) => setTimeout(r, retryAfter * 1000));
15 continue;
16 }
17
18 throw new Error(`API error: ${res.status}`);
19 }
20
21 throw new Error("Max retries exceeded");
22}