Rate Limits
To ensure fair usage and stability for all API consumers, generation requests are rate-limited per user. Limits are applied on a rolling 30-minute window.
30 requests
per 30-minute rolling window, per API key
Applies to
POST /text-to-video
POST /image-to-video
GET /video-status is not rate-limited
Rate Limit Headers
Every generation response includes these headers so you can monitor your quota in real-time:
| Header | Type | Description |
|---|---|---|
X-RateLimit-Limit |
integer | Maximum requests allowed per window (30). |
X-RateLimit-Remaining |
integer | Requests remaining in the current window. |
X-RateLimit-Reset |
unix timestamp | Unix timestamp (seconds) when the window resets. |
Retry-After |
integer | Only on 429 — seconds to wait before retrying. |
HTTP/1.1 200 OK Content-Type: application/json X-RateLimit-Limit: 30 X-RateLimit-Remaining:17 X-RateLimit-Reset: 1746463200 ← Unix timestamp
429 — Too Many Requests
When the limit is exceeded, the API returns a 429 with:
HTTP/1.1 429 Too Many Requests Retry-After: 847 X-RateLimit-Limit: 30 X-RateLimit-Remaining:0 { "success": false, "error": "Rate limit exceeded. You have generated 30 videos in the last 30 minutes.", "rate_limit": { "count": 30, "limit": 30, "remaining": 0, "reset_in_seconds": 847, "reset_at": "2026-05-05T18:30:00Z" } }
Best Practices
Monitor X-RateLimit-Remaining
Parse this header after each response. When it drops below 5, slow down your request cadence or queue further calls.
Implement exponential back-off
On a 429, wait for Retry-After seconds before retrying. Increase the delay on subsequent 429s (×2 each time).
Queue requests server-side
Instead of sending bursts, maintain a server-side queue with a rate of ≤1 request every 60 seconds to stay well within limits.
Cache results
Store video URLs from successful generations — you never need to regenerate the same video twice.
Throttled Batch Processing
/** * Process a list of prompts respecting rate limits. * Waits 2 min between batches of 25 to stay under 30/30min. */ async function batchGenerate(prompts, batchSize = 25, delayMs = 120_000) { const results = []; for (let i = 0; i < prompts.length; i += batchSize) { const batch = prompts.slice(i, i + batchSize); const batchResults = await Promise.all( batch.map(prompt => generateVideo(prompt)) ); results.push(...batchResults); // Wait between batches to avoid rate limiting if (i + batchSize < prompts.length) { console.log(`Batch done. Waiting ${delayMs / 1000}s before next batch…`); await new Promise(r => setTimeout(r, delayMs)); } } return results; } // Usage const prompts = [ 'Sunrise over Tokyo skyline', 'Tropical beach with turquoise water', // ... up to N prompts ]; const videos = await batchGenerate(prompts);