Skip to main content

Error Response Format

All API errors follow a consistent JSON response format:
{
  "error": "Error message",
  "reason": "Detailed explanation of what went wrong",
  "usage": {
    "used": 145,
    "limit": 100
  }
}
error
string
required
Short error message describing what went wrong
reason
string
Human-readable explanation with additional context (optional)
usage
object
Usage information when error is quota-related (optional)
used
number
Number of videos generated this billing period
limit
number
Maximum videos allowed for your plan

HTTP Status Codes

400 Bad Request

The request was malformed or contained invalid parameters. Common causes:
  • Invalid JSON in request body
  • Missing required fields (url, variantCount, etc.)
  • Invalid URL format (not a valid HTTP/HTTPS URL)
  • Invalid variantCount (must be 1-3)
  • urls not an array of 1-3 valid URLs
{
  "error": "urls must be an array of 1-3 URLs"
}
Always validate your request parameters before sending to avoid 400 errors. These errors indicate a problem with your code, not the API.

401 Unauthorized

Authentication failed. Your API key is missing, invalid, or malformed. Common causes:
  • Missing Authorization header
  • Invalid API key format (must start with nvl_)
  • API key has been revoked
  • API key does not exist
{
  "error": "Unable to resolve user from API key"
}
Always use the Bearer authentication scheme:
Authorization: Bearer nvl_your_api_key_here

402 Payment Required

You have exceeded your plan’s quota or attempted to use a feature not available on your plan. Common causes:
  • Generated more videos than your plan allows this billing period
  • Trial period has ended
  • Plan does not include API access
{
  "error": "quota_exceeded",
  "reason": "You've used all 30 videos for this billing period. Add credits ($8/video) or upgrade your plan.",
  "usage": {
    "used": 30,
    "limit": 30
  }
}
The usage object is included when the error is quota-related, showing your current usage and plan limit.

403 Forbidden

Your API key lacks the required permission to perform this action. Common causes:
  • API key does not have generate permission (for POST /api/v1/generate)
  • API key does not have projects:read permission (for GET endpoints)
  • Attempting to access another user’s resources
{
  "error": "This API key does not have the 'generate' permission"
}
API key permissions cannot be modified after creation. If you need different permissions, revoke the key and create a new one with the correct permissions.
See the Permissions page for details on permission scopes.

404 Not Found

The requested resource does not exist. Common causes:
  • Job ID does not exist
  • Project ID does not exist
  • Typo in the endpoint URL
{
  "error": "Not found",
  "reason": "Job not found"
}
Job IDs are UUIDs (e.g., 550e8400-e29b-41d4-a716-446655440000). Double-check that you’re using the correct ID format from the generation response.

422 Unprocessable Entity

The request was well-formed, but the server cannot process it due to semantic errors. Common causes:
  • URL is not a product page (detected as homepage, category page, blog post, etc.)
  • URL is a valid product page but cannot be processed (unsupported e-commerce platform)
{
  "error": "not_a_product",
  "reason": "example.com is not a product page. Paste a link to a product you want to advertise."
}
The special error code not_a_product is always returned with a 422 status. This indicates the URL was successfully accessed but determined to be a non-product page.

429 Too Many Requests

You have exceeded the rate limit of 60 requests per minute.
{
  "error": "Rate limit exceeded",
  "reason": "You have made too many requests. Please wait before trying again.",
  "retryAfter": 23
}
retryAfter
number
Number of seconds to wait before retrying (optional)
The response also includes a Retry-After header with the same value. See the Rate Limits page for detailed guidance on handling rate limits.

500 Internal Server Error

An unexpected error occurred on the server. Common causes:
  • Temporary service outage
  • Database connection issue
  • Unexpected data format from upstream service
{
  "error": "Internal server error",
  "reason": "An unexpected error occurred. Please try again later."
}
500 errors are rare but can happen. Always implement retry logic with exponential backoff for 5xx errors.

Error Handling Best Practices

1. Implement Comprehensive Error Handling

Always check both the HTTP status code and the error response body:
async function generateVideo(url: string) {
  try {
    const response = await fetch('https://app.nouvel.ai/api/v1/generate', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${process.env.NOUVEL_API_KEY}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ urls: [url], variantCount: 3 })
    });

    const data = await response.json();

    if (!response.ok) {
      // Handle specific error cases
      switch (response.status) {
        case 400:
          throw new Error(`Invalid request: ${data.reason}`);
        case 401:
          throw new Error('Authentication failed. Check your API key.');
        case 402:
          throw new Error(`Quota exceeded: ${data.reason}. Used: ${data.usage?.used}/${data.usage?.limit}`);
        case 403:
          throw new Error(`Permission denied: ${data.reason}`);
        case 404:
          throw new Error('Resource not found');
        case 422:
          if (data.error === 'not_a_product') {
            throw new Error(`Not a product page: ${data.reason}`);
          }
          throw new Error(`Cannot process: ${data.reason}`);
        case 429:
          throw new Error(`Rate limited. Retry after ${data.retryAfter} seconds.`);
        case 500:
          throw new Error('Server error. Please try again later.');
        default:
          throw new Error(`API error: ${data.error}`);
      }
    }

    return data;
  } catch (error) {
    console.error('Video generation failed:', error);
    throw error;
  }
}

2. Retry Strategy

Retry 5xx errors and 429 errors with exponential backoff. Do not retry 4xx errors (except 429).
Status CodeRetry?Strategy
400-403❌ NoClient error - fix your request
404❌ NoResource doesn’t exist
422❌ NoSemantic error - fix your input
429✅ YesExponential backoff (1s, 2s, 4s…)
500-599✅ YesExponential backoff (1s, 2s, 4s…)

3. Log Errors for Debugging

Always log the full error response for debugging:
console.error('API Error:', {
  status: response.status,
  error: data.error,
  reason: data.reason,
  usage: data.usage,
  timestamp: new Date().toISOString()
});

4. Handle Special Error Types

Quota Exceeded (402)

When you receive a 402 error, show the user their current usage and guide them to upgrade:
if (response.status === 402) {
  const { usage } = data;
  console.log(`Quota exceeded: ${usage.used}/${usage.limit} videos used`);
  console.log('Upgrade your plan at: https://app.nouvel.ai/settings/billing');
}

Not a Product (422)

When you receive not_a_product, help the user understand what went wrong:
if (data.error === 'not_a_product') {
  console.error('The URL provided is not a product page.');
  console.error('Please ensure you are providing a direct link to a product detail page,');
  console.error('not a homepage, category page, or blog post.');
}

Contact Support

If you encounter persistent errors or need help debugging:
Include the error response, timestamp, and request ID (if available) when contacting support for faster resolution.