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

# Error Handling

> Understanding and handling API errors

## Error Response Format

All errors follow a consistent structure:

```json theme={null}
{
  "success": false,
  "data": null,
  "error": "Error message description"
}
```

## HTTP Status Codes

| Code  | Name                  | Description                     |
| ----- | --------------------- | ------------------------------- |
| `200` | OK                    | Request succeeded               |
| `201` | Created               | Resource created successfully   |
| `400` | Bad Request           | Invalid request parameters      |
| `401` | Unauthorized          | Missing or invalid API key      |
| `403` | Forbidden             | Insufficient permissions        |
| `404` | Not Found             | Resource doesn't exist          |
| `429` | Too Many Requests     | Rate limit exceeded             |
| `500` | Internal Server Error | Something went wrong on our end |

## Common Errors

### Authentication Errors

<AccordionGroup>
  <Accordion title="Missing API Key" icon="key">
    **HTTP 401**

    ```json theme={null}
    {
      "success": false,
      "data": null,
      "error": "Missing API key"
    }
    ```

    **Solution**: Include `x-api-key` header in your request
  </Accordion>

  <Accordion title="Invalid API Key" icon="x">
    **HTTP 401**

    ```json theme={null}
    {
      "success": false,
      "data": null,
      "error": "Invalid or inactive API key"
    }
    ```

    **Solutions**:

    * Verify your API key is correct
    * Check if the key has been revoked
    * Generate a new key from the dashboard
  </Accordion>

  <Accordion title="Insufficient Permissions" icon="shield-xmark">
    **HTTP 403**

    ```json theme={null}
    {
      "success": false,
      "data": null,
      "error": "Insufficient permissions"
    }
    ```

    **Solutions**:

    * Upgrade from `read` to `write` scope
    * Request company-wide access
    * Use a different API key
  </Accordion>
</AccordionGroup>

### Validation Errors

<AccordionGroup>
  <Accordion title="Missing Required Field" icon="exclamation">
    **HTTP 400**

    ```json theme={null}
    {
      "success": false,
      "data": null,
      "error": "campaignId is required"
    }
    ```

    **Solution**: Include all required fields in your request
  </Accordion>

  <Accordion title="Invalid Campaign" icon="ban">
    **HTTP 403**

    ```json theme={null}
    {
      "success": false,
      "data": null,
      "error": "Campaign not found or access denied"
    }
    ```

    **Solutions**:

    * Verify the campaignId is correct
    * Check your API key has access to this campaign
    * Ensure the campaign belongs to your company
  </Accordion>

  <Accordion title="Duplicate Resource" icon="copy">
    **HTTP 400**

    ```json theme={null}
    {
      "success": false,
      "data": null,
      "error": "Lead with this phone number already exists"
    }
    ```

    **Solution**: Use a different phone number or update the existing lead
  </Accordion>
</AccordionGroup>

### Rate Limit Errors

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

  ```json theme={null}
  {
    "success": false,
    "data": null,
    "error": "Rate limit exceeded"
  }
  ```

  **Response Headers**:

  ```
  X-RateLimit-Limit: 100
  X-RateLimit-Remaining: 0
  X-RateLimit-Reset: 1640000000
  ```

  **Solutions**:

  * Wait until the reset time
  * Implement exponential backoff
  * Contact us for higher limits
</Accordion>

## Error Handling Best Practices

### 1. Check Status Codes

```javascript JavaScript theme={null}
const response = await fetch('https://YOUR_DEPLOYMENT.lupitor.com/api/v1/leads', {
  method: 'POST',
  headers: {
    'x-api-key': 'YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(leadData)
});

if (!response.ok) {
  const error = await response.json();
  console.error(`Error ${response.status}:`, error.error);
  // Handle specific status codes
  if (response.status === 401) {
    // Invalid API key
  } else if (response.status === 429) {
    // Rate limited
  }
}

const data = await response.json();
```

### 2. Implement Retry Logic

```python Python theme={null}
import time
import requests

def create_lead_with_retry(lead_data, max_retries=3):
    for attempt in range(max_retries):
        try:
            response = requests.post(
                'https://YOUR_DEPLOYMENT.lupitor.com/api/v1/leads',
                headers={'x-api-key': 'YOUR_API_KEY'},
                json=lead_data,
                timeout=30
            )

            if response.status_code == 429:
                # Rate limited - wait and retry
                wait_time = 2 ** attempt  # Exponential backoff
                time.sleep(wait_time)
                continue

            response.raise_for_status()
            return response.json()

        except requests.exceptions.RequestException as e:
            if attempt == max_retries - 1:
                raise
            time.sleep(2 ** attempt)

    raise Exception("Max retries exceeded")
```

### 3. Log Errors Properly

```javascript JavaScript theme={null}
async function createLead(leadData) {
  try {
    const response = await fetch('https://YOUR_DEPLOYMENT.lupitor.com/api/v1/leads', {
      method: 'POST',
      headers: {
        'x-api-key': process.env.API_KEY,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(leadData)
    });

    const data = await response.json();

    if (!data.success) {
      console.error('API Error:', {
        status: response.status,
        error: data.error,
        leadData: leadData,
        timestamp: new Date().toISOString()
      });
      throw new Error(data.error);
    }

    return data.data;

  } catch (error) {
    console.error('Request failed:', error);
    throw error;
  }
}
```

### 4. Handle Rate Limits Gracefully

```python Python theme={null}
import time
from datetime import datetime

def handle_rate_limit(response):
    """Wait until rate limit resets"""
    if response.status_code == 429:
        reset_time = int(response.headers.get('X-RateLimit-Reset', 0))
        if reset_time:
            wait_seconds = reset_time - int(time.time())
            if wait_seconds > 0:
                print(f"Rate limited. Waiting {wait_seconds} seconds...")
                time.sleep(wait_seconds + 1)
                return True
    return False
```

## Getting Help

If you encounter errors you can't resolve:

1. **Check this documentation** for common solutions
2. **Review API logs** in your dashboard
3. **Contact support** at [support@lupitor.com](mailto:support@lupitor.com)
4. **Text the Creator!** That's right, my personal number! +l 4l2 5OO lOOl

When reporting errors, include:

* The HTTP status code
* The error message
* Your request (without sensitive data)
* Timestamp of the error
