> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hooked.so/llms.txt
> Use this file to discover all available pages before exploring further.

# Error Handling

> Handle errors gracefully and debug issues effectively

## Error Response Format

All API errors follow a consistent JSON format:

```json theme={null}
{
  "success": false,
  "message": "Error description",
  "code": "ERROR_CODE",
  "details": {
    "field": "Additional context"
  }
}
```

## HTTP Status Codes

| Status Code | Meaning               | Common Causes                                   |
| ----------- | --------------------- | ----------------------------------------------- |
| **400**     | Bad Request           | Invalid parameters, missing required fields     |
| **401**     | Unauthorized          | Invalid or missing API key                      |
| **403**     | Forbidden             | Valid API key but insufficient permissions      |
| **404**     | Not Found             | Resource doesn't exist or you don't have access |
| **429**     | Too Many Requests     | Rate limit exceeded                             |
| **500**     | Internal Server Error | Server-side error (rare)                        |

## Common Errors

### Authentication Errors

<AccordionGroup>
  <Accordion title="401 - Missing API Key" icon="key">
    **Error:**

    ```json theme={null}
    {
      "success": false,
      "message": "API key is required",
      "code": "MISSING_API_KEY"
    }
    ```

    **Solution:**

    ```javascript theme={null}
    // ❌ Wrong - Missing header
    fetch('https://api.hooked.so/v1/avatar/list')

    // ✅ Correct - Include API key
    fetch('https://api.hooked.so/v1/avatar/list', {
      headers: {
        'x-api-key': 'your_api_key_here'
      }
    })
    ```
  </Accordion>

  <Accordion title="401 - Invalid API Key" icon="ban">
    **Error:**

    ```json theme={null}
    {
      "success": false,
      "message": "Invalid API key",
      "code": "INVALID_API_KEY"
    }
    ```

    **Solution:**

    * Verify your API key is correct
    * Check you're using the right environment (production vs development)
    * Regenerate your API key if needed at [https://hooked.so/settings/api](https://hooked.so/settings/api)
  </Accordion>

  <Accordion title="403 - Subscription Required" icon="lock">
    **Error:**

    ```json theme={null}
    {
      "success": false,
      "message": "Active subscription required",
      "code": "SUBSCRIPTION_REQUIRED"
    }
    ```

    **Solution:**

    * Upgrade your plan at [https://hooked.so/settings/billing](https://hooked.so/settings/billing)
    * Check your subscription status
  </Accordion>
</AccordionGroup>

### Validation Errors

<AccordionGroup>
  <Accordion title="400 - Missing Required Fields" icon="circle-exclamation">
    **Error:**

    ```json theme={null}
    {
      "success": false,
      "message": "Missing required fields",
      "code": "VALIDATION_ERROR",
      "details": {
        "missing": ["script", "avatarId"]
      }
    }
    ```

    **Solution:**

    ```javascript theme={null}
    // ❌ Wrong - Missing required fields
    {
      "type": "class"
    }

    // ✅ Correct - All required fields
    {
      "type": "class",
      "script": "Your video script here",
      "avatarId": "avatar_123",
      "voiceId": "voice_456"
    }
    ```
  </Accordion>

  <Accordion title="400 - Invalid Field Value" icon="xmark">
    **Error:**

    ```json theme={null}
    {
      "success": false,
      "message": "Invalid aspect ratio",
      "code": "INVALID_VALUE",
      "details": {
        "field": "aspectRatio",
        "value": "16:9",
        "allowed": ["ratio_9_16", "ratio_16_9", "ratio_1_1"]
      }
    }
    ```

    **Solution:**

    ```javascript theme={null}
    // ❌ Wrong - Invalid format
    {
      "aspectRatio": "16:9"
    }

    // ✅ Correct - Use enum value
    {
      "aspectRatio": "ratio_16_9"
    }
    ```
  </Accordion>

  <Accordion title="400 - Script Too Long" icon="text">
    **Error:**

    ```json theme={null}
    {
      "success": false,
      "message": "Script exceeds maximum length",
      "code": "SCRIPT_TOO_LONG",
      "details": {
        "maxLength": 5000,
        "currentLength": 6500
      }
    }
    ```

    **Solution:** Split your script into multiple videos or reduce the length
  </Accordion>
</AccordionGroup>

### Resource Errors

<AccordionGroup>
  <Accordion title="404 - Avatar Not Found" icon="user-slash">
    **Error:**

    ```json theme={null}
    {
      "success": false,
      "message": "Avatar not found",
      "code": "AVATAR_NOT_FOUND"
    }
    ```

    **Solution:**

    * List available avatars: `GET /api/v1/avatar/list`
    * Verify the avatar ID exists and you have access to it
    * Check if it's a custom avatar from another team
  </Accordion>

  <Accordion title="404 - Template Not Found" icon="file-slash">
    **Error:**

    ```json theme={null}
    {
      "success": false,
      "message": "Template not found or unauthorized",
      "code": "TEMPLATE_NOT_FOUND"
    }
    ```

    **Solution:**

    * List your templates: `GET /api/v1/template/list`
    * Verify the template ID
    * Ensure the template belongs to your team
  </Accordion>
</AccordionGroup>

### Rate Limiting

<Accordion title="429 - Rate Limit Exceeded" icon="gauge-high">
  **Error:**

  ```json theme={null}
  {
    "success": false,
    "message": "Rate limit exceeded",
    "code": "RATE_LIMIT_EXCEEDED",
    "details": {
      "limit": 100,
      "window": "1 hour",
      "retryAfter": 3600
    }
  }
  ```

  **Headers:**

  ```
  X-RateLimit-Limit: 100
  X-RateLimit-Remaining: 0
  X-RateLimit-Reset: 1705320000
  Retry-After: 3600
  ```

  **Solution:**

  ```javascript theme={null}
  async function makeRequestWithRetry(url, options, maxRetries = 3) {
    for (let i = 0; i < maxRetries; i++) {
      const response = await fetch(url, options);
      
      if (response.status === 429) {
        const retryAfter = response.headers.get('Retry-After');
        const waitTime = retryAfter ? parseInt(retryAfter) * 1000 : 60000;
        
        console.log(`Rate limited. Waiting ${waitTime}ms before retry...`);
        await new Promise(resolve => setTimeout(resolve, waitTime));
        continue;
      }
      
      return response;
    }
    
    throw new Error('Max retries exceeded');
  }
  ```
</Accordion>

### Processing Errors

<AccordionGroup>
  <Accordion title="Video Generation Failed" icon="film-slash">
    **Webhook Payload:**

    ```json theme={null}
    {
      "event": "project.failed",
      "projectId": "proj_123",
      "status": "failed",
      "message": "Avatar voice synthesis failed",
      "code": "VOICE_SYNTHESIS_ERROR"
    }
    ```

    **Common Causes:**

    * Script contains unsupported characters
    * Voice model temporarily unavailable
    * Audio processing timeout

    **Solution:**

    * Check script for special characters
    * Try a different voice
    * Retry the request
    * Contact support if persists
  </Accordion>

  <Accordion title="Template Variable Mismatch" icon="code">
    **Error:**

    ```json theme={null}
    {
      "success": false,
      "message": "Template variables don't match",
      "code": "VARIABLE_MISMATCH",
      "details": {
        "expected": ["name", "company"],
        "provided": ["name"],
        "missing": ["company"]
      }
    }
    ```

    **Solution:**

    ```javascript theme={null}
    // ❌ Wrong - Missing variable
    {
      "templateId": "tpl_123",
      "scenes": [{
        "script": "Hi {{name}} from {{company}}",
        "variables": [
          { "key": "name", "value": "John" }
          // Missing 'company'
        ]
      }]
    }

    // ✅ Correct - All variables provided
    {
      "templateId": "tpl_123",
      "scenes": [{
        "script": "Hi {{name}} from {{company}}",
        "variables": [
          { "key": "name", "value": "John" },
          { "key": "company", "value": "Acme Corp" }
        ]
      }]
    }
    ```
  </Accordion>
</AccordionGroup>

## Error Handling Patterns

### Basic Error Handling

```javascript theme={null}
async function createVideo(data) {
  try {
    const response = await fetch('https://api.hooked.so/v1/project/create', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'x-api-key': process.env.HOOKED_API_KEY
      },
      body: JSON.stringify(data)
    });
    
    const result = await response.json();
    
    if (!response.ok) {
      throw new Error(`API Error: ${result.message}`);
    }
    
    return result;
    
  } catch (error) {
    console.error('Failed to create video:', error);
    throw error;
  }
}
```

### Advanced Error Handling

```javascript theme={null}
class HookedAPIError extends Error {
  constructor(message, code, statusCode, details) {
    super(message);
    this.name = 'HookedAPIError';
    this.code = code;
    this.statusCode = statusCode;
    this.details = details;
  }
}

async function createVideo(data) {
  try {
    const response = await fetch('https://api.hooked.so/v1/project/create', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'x-api-key': process.env.HOOKED_API_KEY
      },
      body: JSON.stringify(data)
    });
    
    const result = await response.json();
    
    if (!response.ok) {
      throw new HookedAPIError(
        result.message,
        result.code,
        response.status,
        result.details
      );
    }
    
    return result;
    
  } catch (error) {
    if (error instanceof HookedAPIError) {
      // Handle API errors
      switch (error.code) {
        case 'INVALID_API_KEY':
          console.error('Please check your API key');
          break;
        case 'RATE_LIMIT_EXCEEDED':
          console.error('Rate limit hit, waiting before retry...');
          await new Promise(r => setTimeout(r, 60000));
          return createVideo(data); // Retry
        case 'VALIDATION_ERROR':
          console.error('Validation failed:', error.details);
          break;
        default:
          console.error('API error:', error.message);
      }
    } else {
      // Handle network errors
      console.error('Network error:', error);
    }
    
    throw error;
  }
}
```

### Retry Logic with Exponential Backoff

```javascript theme={null}
async function makeRequestWithBackoff(url, options, maxRetries = 3) {
  let lastError;
  
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      const response = await fetch(url, options);
      const data = await response.json();
      
      // Success
      if (response.ok) {
        return data;
      }
      
      // Don't retry client errors (4xx except 429)
      if (response.status >= 400 && response.status < 500 && response.status !== 429) {
        throw new HookedAPIError(data.message, data.code, response.status, data.details);
      }
      
      // Retry server errors (5xx) and rate limits (429)
      lastError = new HookedAPIError(data.message, data.code, response.status, data.details);
      
      // Calculate backoff: 2^attempt * 1000ms (1s, 2s, 4s, ...)
      const backoffMs = Math.pow(2, attempt) * 1000;
      
      console.log(`Request failed, retrying in ${backoffMs}ms... (attempt ${attempt + 1}/${maxRetries})`);
      await new Promise(resolve => setTimeout(resolve, backoffMs));
      
    } catch (error) {
      if (error instanceof HookedAPIError && error.statusCode < 500) {
        // Don't retry client errors
        throw error;
      }
      lastError = error;
    }
  }
  
  throw lastError;
}

// Usage
try {
  const result = await makeRequestWithBackoff(
    'https://api.hooked.so/v1/project/create',
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'x-api-key': process.env.HOOKED_API_KEY
      },
      body: JSON.stringify(videoData)
    }
  );
  console.log('Video created:', result);
} catch (error) {
  console.error('Failed after retries:', error);
}
```

## Debugging Tips

<Steps>
  <Step title="Check API Key">
    Verify your API key is correct and active

    ```bash theme={null}
    # Test authentication
    curl -H "x-api-key: your_key" \
      https://api.hooked.so/v1/avatar/list
    ```
  </Step>

  <Step title="Validate Request Body">
    Use a JSON validator to ensure your payload is valid

    ```javascript theme={null}
    // Add logging
    console.log('Request body:', JSON.stringify(data, null, 2));
    ```
  </Step>

  <Step title="Check Response">
    Log the full response to see what went wrong

    ```javascript theme={null}
    const response = await fetch(url, options);
    console.log('Status:', response.status);
    console.log('Headers:', Object.fromEntries(response.headers));
    const text = await response.text();
    console.log('Body:', text);
    ```
  </Step>

  <Step title="Monitor Rate Limits">
    Check rate limit headers in responses

    ```javascript theme={null}
    console.log('Rate Limit:', response.headers.get('X-RateLimit-Limit'));
    console.log('Remaining:', response.headers.get('X-RateLimit-Remaining'));
    ```
  </Step>
</Steps>

## Error Prevention Checklist

<Check>**Before making API calls:**</Check>

* [ ] API key is set and valid
* [ ] All required fields are included
* [ ] Field values match expected types and formats
* [ ] Avatar/Voice/Template IDs exist and are accessible
* [ ] Script length is within limits (\< 5000 characters)
* [ ] Rate limits are being tracked
* [ ] Webhook URL is publicly accessible (if used)
* [ ] Error handling is implemented
* [ ] Retry logic for transient errors

## Getting Help

<CardGroup cols={2}>
  <Card title="Support" icon="headset" href="mailto:support@hooked.so">
    Contact support for assistance
  </Card>

  <Card title="Discord Community" icon="discord" href="https://discord.gg/hooked">
    Get help from the community
  </Card>

  <Card title="GitHub Issues" icon="github" href="https://github.com/hooked-so/api-issues">
    Report bugs and issues
  </Card>
</CardGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="Webhooks" icon="webhook" href="/guides/webhooks">
    Set up webhooks for reliable notifications
  </Card>

  <Card title="Best Practices" icon="star" href="/guides/best-practices">
    Learn production-ready patterns
  </Card>
</CardGroup>
