Rate Limits
The Flow API uses rate limiting to ensure fair usage and system stability. This guide explains how rate limits work and how to handle them.
Overview
Rate limits are applied per API key and are based on your subscription plan. Limits are enforced using a sliding window algorithm.
Rate Limit Headers
Every API response includes rate limit information in headers:
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1703123456
Retry-After: 60
Header Descriptions
| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum number of requests allowed in the current window |
X-RateLimit-Remaining | Number of requests remaining in the current window |
X-RateLimit-Reset | Unix timestamp (seconds) when the rate limit window resets |
Retry-After | Number of seconds to wait before retrying (only present on 429 responses) |
Rate Limit Tiers
Rate limits vary by subscription plan:
| Plan | Requests per Minute | Requests per Hour | Requests per Day |
|---|---|---|---|
| Free | 60 | 1,000 | 10,000 |
| Stream | 120 | 5,000 | 50,000 |
| River | 300 | 15,000 | 150,000 |
| Ocean | 600 | 30,000 | 300,000 |
Note: Rate limits are subject to change. Check your plan details for current limits.
Rate Limit Windows
Rate limits use sliding windows:
- Per-minute limit: Counts requests in the last 60 seconds
- Per-hour limit: Counts requests in the last 3600 seconds
- Per-day limit: Counts requests in the last 86400 seconds
This means requests don't reset at fixed intervals (e.g., top of the hour), but rather continuously based on the sliding window.
Handling Rate Limits
429 Too Many Requests
When you exceed a rate limit, you'll receive a 429 status code:
{
"error": "Rate limit exceeded",
"message": "You have exceeded the rate limit. Please try again later.",
"retry_after": 60
}
Retry Strategy
- Read the
Retry-Afterheader - This tells you exactly when to retry - Wait before retrying - Don't retry immediately
- Implement exponential backoff - If retry fails, wait longer
Example implementation:
async function makeRequestWithRateLimitHandling(url: string, options: RequestInit) {
const maxRetries = 3;
for (let attempt = 0; attempt <= maxRetries; attempt++) {
const response = await fetch(url, options);
if (response.status === 429) {
const retryAfter = parseInt(response.headers.get('Retry-After') || '60');
if (attempt < maxRetries) {
console.log(`Rate limited. Waiting ${retryAfter} seconds before retry...`);
await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
continue;
}
throw new Error('Rate limit exceeded. Max retries reached.');
}
return response;
}
}
Monitoring Rate Limits
Always check rate limit headers to avoid hitting limits:
async function checkRateLimit(response: Response) {
const remaining = parseInt(response.headers.get('X-RateLimit-Remaining') || '0');
const limit = parseInt(response.headers.get('X-RateLimit-Limit') || '0');
const reset = parseInt(response.headers.get('X-RateLimit-Reset') || '0');
// Log or alert when approaching limit
if (remaining < limit * 0.1) { // Less than 10% remaining
console.warn(`Rate limit warning: ${remaining}/${limit} requests remaining`);
}
return { remaining, limit, reset };
}
Best Practices
1. Monitor Rate Limit Headers
Always check X-RateLimit-Remaining to know how many requests you have left:
const response = await fetch(url, options);
const remaining = parseInt(response.headers.get('X-RateLimit-Remaining') || '0');
if (remaining < 10) {
// Slow down or queue requests
await delayRequests();
}
2. Implement Request Queuing
Queue requests when approaching limits:
class RateLimitedQueue {
private queue: Array<() => Promise<any>> = [];
private processing = false;
async add<T>(fn: () => Promise<T>): Promise<T> {
return new Promise((resolve, reject) => {
this.queue.push(async () => {
try {
const result = await fn();
resolve(result);
} catch (error) {
reject(error);
}
});
this.process();
});
}
private async process() {
if (this.processing || this.queue.length === 0) return;
this.processing = true;
while (this.queue.length > 0) {
const fn = this.queue.shift();
if (fn) await fn();
// Small delay between requests to avoid hitting limits
await new Promise(resolve => setTimeout(resolve, 100));
}
this.processing = false;
}
}
3. Use Bulk Operations
When possible, use bulk endpoints to reduce API calls:
// Instead of multiple POST requests:
for (const post of posts) {
await flow.posts.create(post); // 10 API calls
}
// Use bulk endpoint:
await flow.posts.batchCreate(posts); // 1 API call
4. Cache Responses
Cache GET requests to reduce API calls:
const cache = new Map<string, { data: any; expires: number }>();
async function getCached<T>(key: string, fn: () => Promise<T>, ttl = 60000): Promise<T> {
const cached = cache.get(key);
if (cached && cached.expires > Date.now()) {
return cached.data;
}
const data = await fn();
cache.set(key, { data, expires: Date.now() + ttl });
return data;
}
// Usage
const posts = await getCached('posts', () => flow.posts.list(), 60000);
5. Parallel Requests (with Caution)
Make independent requests in parallel, but respect rate limits:
// Good: Parallel requests for independent resources
const [channels, webhooks] = await Promise.all([
flow.channels.list(),
flow.webhooks.list(),
]);
// Bad: Too many parallel requests (may hit rate limit)
const posts = await Promise.all(
Array(100).fill(0).map(() => flow.posts.create({ ... }))
);
Rate Limit by Endpoint
Some endpoints have stricter rate limits:
| Endpoint | Limit |
|---|---|
POST /v1/posts | Same as plan limit |
GET /v1/posts | Same as plan limit |
POST /v1/posts/batch | 10 requests/minute (bulk operations) |
Increasing Rate Limits
To increase your rate limits:
- Upgrade your plan - Higher tiers have higher limits
- Contact support - Enterprise customers can request custom limits
- Optimize usage - Use bulk operations and caching to reduce API calls
Testing Rate Limits
In the test environment, rate limits are more lenient to allow for testing:
- Test environment: 1,000 requests/minute
- Production: Based on your plan
SDK Support
The Flow SDKs automatically handle rate limits:
TypeScript SDK
import { Flow } from '@flowdev/sdk';
const flow = new Flow('flow_sk_live_...');
// SDK automatically:
// - Retries on 429 with exponential backoff
// - Respects Retry-After header
// - Logs rate limit warnings
Python SDK
from flow_sdk import Flow
flow = Flow(api_key="flow_sk_live_...")
# SDK automatically handles rate limit retries
Monitoring and Alerts
Set up monitoring for rate limit usage:
// Example: Alert when rate limit is low
function monitorRateLimit(response: Response) {
const remaining = parseInt(response.headers.get('X-RateLimit-Remaining') || '0');
const limit = parseInt(response.headers.get('X-RateLimit-Limit') || '0');
const usagePercent = ((limit - remaining) / limit) * 100;
if (usagePercent > 80) {
// Send alert
sendAlert(`Rate limit usage: ${usagePercent.toFixed(1)}%`);
}
}
Common Issues
Issue: Hitting Rate Limits Frequently
Solutions:
- Implement request queuing
- Use bulk operations
- Cache GET requests
- Upgrade your plan
Issue: Retry Loops
Solutions:
- Always respect
Retry-Afterheader - Implement maximum retry limits
- Use exponential backoff
Issue: Rate Limit Headers Missing
Solutions:
- Check that you're using the latest API version
- Ensure you're authenticated (rate limit headers only appear for authenticated requests)
- Contact support if headers are consistently missing
Support
- Documentation: https://docs.flowsocial.app
- Support: https://flowsocial.app/support
- Rate Limit Questions: support@flowsocial.app