Skip to main content

Rate Limits

The ReelBot API enforces rate limits to ensure fair usage and system stability.

Rate Limits by Endpoint

EndpointLimitWindow
POST /video/generate10 requests1 hour
GET /video/status/{id}60 requests1 minute
GET /video/download/{id}30 requests1 hour

Why These Limits?

  • Generate: Video generation is resource-intensive; 10/hour allows substantial usage while preventing abuse
  • Status: Generous limit for polling; 60/minute = 1 request/second
  • Download: URLs are valid for 1 hour; 30/hour is more than sufficient

Quota Limits

In addition to rate limits, your account has quota limits based on your subscription plan.

Video Generation Quota

PlanVideos per Month
Free3
Starter15
Creator50
Pro150
Business500

API usage counts against the same quota as the Video Studio.

Quota Reset

  • Quotas reset on your billing cycle date
  • Free plan quotas reset monthly from signup date

Rate Limit Headers

Every response includes rate limit information:

HeaderDescription
X-RateLimit-RemainingRequests remaining in current window
X-RateLimit-ResetISO timestamp when limit resets
Retry-AfterSeconds until you can retry (only on 429)

Example Headers

HTTP/1.1 200 OK
X-RateLimit-Remaining: 8
X-RateLimit-Reset: 2025-01-21T17:00:00.000Z

Rate Limit Response

When you exceed a rate limit:

HTTP/1.1 429 Too Many Requests
Retry-After: 1847
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 2025-01-21T17:00:00.000Z
{
"success": false,
"message": "Rate limit exceeded. Please try again later.",
"code": "RATE_LIMITED",
"details": {
"resetAt": "2025-01-21T17:00:00.000Z"
}
}

Handling Rate Limits

Check Headers Proactively

async function makeRequest(url, options) {
const response = await fetch(url, options);

const remaining = response.headers.get('X-RateLimit-Remaining');
const resetAt = response.headers.get('X-RateLimit-Reset');

console.log(`Rate limit: ${remaining} remaining, resets at ${resetAt}`);

if (remaining === '0') {
console.warn('Rate limit exhausted!');
}

return response;
}

Implement Retry Logic

async function requestWithRateLimitRetry(url, options) {
const response = await fetch(url, options);

if (response.status === 429) {
const retryAfter = parseInt(response.headers.get('Retry-After') || '60');
console.log(`Rate limited. Waiting ${retryAfter} seconds...`);

await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));

// Retry once
return fetch(url, options);
}

return response;
}

Queue Requests

For batch operations, implement a queue:

class RateLimitedQueue {
constructor(requestsPerWindow, windowMs) {
this.requestsPerWindow = requestsPerWindow;
this.windowMs = windowMs;
this.queue = [];
this.requestCount = 0;
this.windowStart = Date.now();
}

async add(fn) {
return new Promise((resolve, reject) => {
this.queue.push({ fn, resolve, reject });
this.process();
});
}

async process() {
if (this.queue.length === 0) return;

const now = Date.now();
if (now - this.windowStart >= this.windowMs) {
this.requestCount = 0;
this.windowStart = now;
}

if (this.requestCount >= this.requestsPerWindow) {
const waitTime = this.windowMs - (now - this.windowStart);
setTimeout(() => this.process(), waitTime);
return;
}

const { fn, resolve, reject } = this.queue.shift();
this.requestCount++;

try {
const result = await fn();
resolve(result);
} catch (error) {
reject(error);
}

this.process();
}
}

// Usage
const queue = new RateLimitedQueue(10, 3600000); // 10 per hour

for (const video of videosToGenerate) {
queue.add(() => generateVideo(video));
}

Best Practices

1. Respect Rate Limits

Don't try to circumvent rate limits. They protect both you and the service.

2. Use Efficient Polling

For status checks, use reasonable intervals:

// Good: 5 second intervals
const POLL_INTERVAL = 5000;

// Bad: 100ms intervals (will hit rate limit quickly)
const POLL_INTERVAL = 100;

3. Cache Download URLs

Download URLs are valid for 1 hour. Cache them instead of requesting new ones:

const urlCache = new Map();

async function getDownloadUrl(projectId) {
const cached = urlCache.get(projectId);

if (cached && new Date(cached.expiresAt) > new Date()) {
return cached.downloadUrl;
}

const response = await fetch(`/api/v1/video/download/${projectId}`, {
headers: { 'X-API-Key': API_KEY }
});

const data = await response.json();
urlCache.set(projectId, data);

return data.downloadUrl;
}

4. Batch Wisely

If generating multiple videos, spread requests over time:

async function generateBatch(videos) {
const results = [];

for (const video of videos) {
results.push(await generateVideo(video));

// Wait 6 minutes between requests to stay under 10/hour
if (videos.indexOf(video) < videos.length - 1) {
await new Promise(r => setTimeout(r, 360000));
}
}

return results;
}

Increasing Limits

If you need higher rate limits:

  1. Upgrade your plan: Higher plans may have increased limits
  2. Contact sales: Enterprise customers can negotiate custom limits
  3. Optimize usage: Often, better caching and batching reduces the need for higher limits

Contact: support@reelbot.space