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