Rate Limits
Understand Unmarkdown API rate limits, response headers, and best practices for handling 429 responses.
Rate Limit Tiers
Rate limits are applied per API key on a per-second basis. The limit depends on your plan.
- Free plan: 10 requests per second
- Pro plan: 30 requests per second
Requests that exceed the rate limit receive a 429 Too Many Requests response. The response includes headers indicating when you can retry.
Rate Limit Headers
Every API response includes rate limit headers so you can monitor your usage and avoid hitting the limit.
X-RateLimit-Limit
The maximum number of requests allowed per second for your plan.
X-RateLimit-Remaining
The number of requests remaining in the current one-second window.
X-RateLimit-Reset
The Unix timestamp (in seconds) when the current rate limit window resets.
HTTP/1.1 200 OK
X-RateLimit-Limit: 30
X-RateLimit-Remaining: 27
X-RateLimit-Reset: 1709251200429 Responses
When you exceed the rate limit, the API returns a 429 Too Many Requests status code with a JSON error body. The Retry-After header indicates how many seconds to wait before retrying.
HTTP/1.1 429 Too Many Requests
Retry-After: 1
{
"error": {
"code": "rate_limit_exceeded",
"message": "Too many requests. Please retry after 1 second."
}
}Retry Strategy
The recommended approach for handling rate limits is exponential backoff with jitter. Start with a short delay and double it on each consecutive 429 response, adding a small random component to avoid thundering herd problems.
- First retry: wait 1 second
- Second retry: wait 2 seconds
- Third retry: wait 4 seconds
- Add random jitter of 0 to 500 milliseconds to each wait
- Cap the maximum backoff at 30 seconds
Retry Example (JavaScript)
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;
const retryAfter = response.headers.get("Retry-After");
const delay = retryAfter
? parseInt(retryAfter) * 1000
: Math.min(1000 * Math.pow(2, attempt), 30000);
const jitter = Math.random() * 500;
await new Promise((r) => setTimeout(r, delay + jitter));
}
throw new Error("Max retries exceeded");
}Retry Example (Python)
import time, random, requests
def fetch_with_retry(url, headers, max_retries=3):
for attempt in range(max_retries + 1):
response = requests.get(url, headers=headers)
if response.status_code != 429:
return response
retry_after = response.headers.get("Retry-After")
delay = (
int(retry_after)
if retry_after
else min(2**attempt, 30)
)
jitter = random.uniform(0, 0.5)
time.sleep(delay + jitter)
raise Exception("Max retries exceeded")Best Practices
Follow these guidelines to stay within your rate limits and build a reliable integration.
- Monitor the X-RateLimit-Remaining header and throttle requests as it approaches zero
- Batch operations where possible instead of making many individual requests
- Implement retry logic with exponential backoff for all API calls
- Use webhooks or polling intervals rather than tight loops for status checks
- Upgrade to Pro if you consistently need more than 10 requests per second