Skip to main content

Overview

The Nouvel API enforces rate limits to ensure fair usage and system stability. All API keys are subject to a 60 requests per minute limit, regardless of your plan tier.
Rate limits are enforced at the infrastructure level by Unkey, our key management provider. This ensures consistent, reliable rate limiting across all API endpoints.

Rate Limit Details

Limit
number
default:"60"
Maximum number of requests allowed per minute per API key
Window
string
default:"1 minute"
Time window for rate limit calculations (sliding window)
Scope
string
default:"per-key"
Rate limits are applied per API key, not per user or organization

Rate Limit Headers

Every API response includes standard rate limit headers to help you track your usage:
HeaderDescriptionExample
X-RateLimit-LimitMaximum requests allowed in the current window60
X-RateLimit-RemainingNumber of requests remaining in the current window42
X-RateLimit-ResetUnix timestamp when the rate limit window resets1678901234
HTTP/1.1 200 OK
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 42
X-RateLimit-Reset: 1678901234
Content-Type: application/json

When You Exceed the Limit

When you exceed the rate limit, the API returns a 429 Too Many Requests status code:
{
  "error": "Rate limit exceeded",
  "reason": "You have made too many requests. Please wait before trying again.",
  "retryAfter": 23
}
When you receive a 429 response, your request is not processed. You must retry the request after the rate limit window resets.
The response includes:
  • error: Error message indicating rate limit exceeded
  • reason: Human-readable explanation
  • retryAfter: Seconds until you can retry (optional)
Additionally, a Retry-After header indicates how many seconds to wait before retrying.

Endpoint Resource Costs

While all endpoints share the same 60 requests/minute limit, they consume different amounts of system resources:

Video Generation (POST /api/v1/generate)

High resource cost - Triggers AI models, video rendering, and long-running background jobs. Each generation uses significant compute resources.

Status Polling (GET /api/v1/jobs/:id)

Low resource cost - Simple database lookup. You can poll frequently within your rate limit.

Project Listing (GET /api/v1/projects)

Low resource cost - Database query with pagination. Efficient for monitoring multiple jobs.
Even though video generation is resource-intensive, the rate limit is the same for all endpoints. Plan your API usage accordingly to balance generation requests with status checks.

Best Practices

1. Implement Exponential Backoff

When you receive a 429 error, implement exponential backoff to avoid repeatedly hitting the rate limit:
async function generateWithBackoff(url: string, maxRetries = 3) {
  let attempt = 0;

  while (attempt < maxRetries) {
    try {
      const response = await fetch('https://app.nouvel.ai/api/v1/generate', {
        method: 'POST',
        headers: {
          'Authorization': 'Bearer nvl_...',
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({ urls: [url] })
      });

      if (response.status === 429) {
        const backoffMs = Math.pow(2, attempt) * 1000; // 1s, 2s, 4s...
        console.log(`Rate limited. Retrying in ${backoffMs}ms...`);
        await new Promise(resolve => setTimeout(resolve, backoffMs));
        attempt++;
        continue;
      }

      return await response.json();
    } catch (error) {
      throw error;
    }
  }

  throw new Error('Max retries exceeded');
}

2. Cache Responses

Avoid unnecessary API calls by caching responses that don’t change frequently:
  • Cache completed project data (projects in completed or failed status won’t change)
  • Store project metadata locally after the initial fetch
  • Use ETags or Last-Modified headers when available (future enhancement)

3. Batch Operations

When checking status for multiple jobs, use the list endpoint instead of individual status checks:
// Single request to check multiple jobs
const projects = await fetch('https://app.nouvel.ai/api/v1/projects?limit=50', {
  headers: { 'Authorization': 'Bearer nvl_...' }
});

4. Smart Polling Intervals

Adjust your polling frequency based on the project status:
  • Generating status: Poll every 15-30 seconds
  • Post-processing status: Poll every 10-15 seconds
  • Completed/failed status: Stop polling (cache the result)
async function pollUntilComplete(jobId: string) {
  let status = 'generating';

  while (status !== 'completed' && status !== 'failed') {
    const job = await fetch(`https://app.nouvel.ai/api/v1/jobs/${jobId}`, {
      headers: { 'Authorization': 'Bearer nvl_...' }
    }).then(r => r.json());

    status = job.status;

    // Adaptive interval based on status
    const interval = status === 'generating' ? 30000 : 15000;
    await new Promise(resolve => setTimeout(resolve, interval));
  }

  return job;
}

5. Monitor Rate Limit Headers

Track your rate limit usage to avoid hitting the limit:
const response = await fetch('https://app.nouvel.ai/api/v1/generate', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer nvl_...',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ urls: [productUrl] })
});

const remaining = parseInt(response.headers.get('X-RateLimit-Remaining') || '0');
const reset = parseInt(response.headers.get('X-RateLimit-Reset') || '0');

if (remaining < 10) {
  console.warn(`Only ${remaining} requests remaining. Reset at ${new Date(reset * 1000)}`);
}

Webhook Delivery

Webhook deliveries do not count toward your rate limit. Webhooks are initiated by Nouvel’s servers, not your API key, and are not subject to the 60/minute restriction.
When you register a webhookUrl with your generation request, Nouvel will POST to your URL when the job reaches a terminal state. These outbound deliveries are separate from your rate-limited API calls. See the Webhooks guide for full details.

Need Higher Limits?

If your use case requires higher rate limits, please contact our team at support@nouvel.ai. Enterprise plans with custom rate limits are available.
Most integrations work comfortably within the 60/minute limit by following the best practices above. Video generation takes 15-20 minutes per job, so you can submit 60 jobs per minute and they’ll process in parallel.