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

# Errors

> Understanding API error responses and codes

## Error Response Format

All API errors return a consistent JSON structure:

```json theme={null}
{
  "error": "Human-readable error message",
  "code": "MACHINE_READABLE_CODE",
  "status": 400,
  "details": {
    "field": "Additional context when applicable"
  }
}
```

## HTTP Status Codes

The Stanna API uses standard HTTP status codes:

| Status Code | Meaning               | Description                                |
| ----------- | --------------------- | ------------------------------------------ |
| 200         | Success               | Request completed successfully             |
| 400         | Bad Request           | Invalid request parameters or format       |
| 401         | Unauthorized          | Missing or invalid API key                 |
| 403         | Forbidden             | Valid API key but insufficient permissions |
| 404         | Not Found             | Resource or endpoint doesn't exist         |
| 429         | Too Many Requests     | Rate limit exceeded                        |
| 500         | Internal Server Error | Server error (contact support)             |
| 502         | Bad Gateway           | Temporary server issue                     |
| 503         | Service Unavailable   | Maintenance or temporary outage            |

## Common Error Codes

### Authentication Errors

#### `AUTH_MISSING_KEY`

**Status:** 401

```json theme={null}
{
  "error": "API key is required",
  "code": "AUTH_MISSING_KEY",
  "status": 401
}
```

**Solution:** Include your API key in the Authorization header.

#### `AUTH_INVALID_KEY`

**Status:** 401

```json theme={null}
{
  "error": "Invalid API key format or expired key",
  "code": "AUTH_INVALID_KEY",
  "status": 401
}
```

**Solution:** Check your API key format and ensure it hasn't been deleted.

#### `AUTH_WORKSPACE_MISMATCH`

**Status:** 403

```json theme={null}
{
  "error": "API key does not have access to this workspace",
  "code": "AUTH_WORKSPACE_MISMATCH",
  "status": 403
}
```

**Solution:** Verify the `workspaceId` parameter matches your API key's workspace.

### Request Errors

#### `VALIDATION_ERROR`

**Status:** 400

```json theme={null}
{
  "error": "Invalid request parameters",
  "code": "VALIDATION_ERROR",
  "status": 400,
  "details": {
    "workspaceId": "workspaceId is required",
    "windowDays": "windowDays must be between 1 and 365"
  }
}
```

**Solution:** Check the required parameters and their valid ranges.

#### `RESOURCE_NOT_FOUND`

**Status:** 404

```json theme={null}
{
  "error": "Client not found",
  "code": "RESOURCE_NOT_FOUND",
  "status": 404,
  "details": {
    "resource": "client",
    "id": "client_123"
  }
}
```

**Solution:** Verify the resource ID exists in your workspace.

#### `INVALID_WORKSPACE`

**Status:** 404

```json theme={null}
{
  "error": "Workspace not found or inactive",
  "code": "INVALID_WORKSPACE",
  "status": 404,
  "details": {
    "workspaceId": "nonexistent.com"
  }
}
```

**Solution:** Check your workspace ID (domain) is correct and active.

### Rate Limiting Errors

#### `RATE_LIMIT_EXCEEDED`

**Status:** 429

```json theme={null}
{
  "error": "Rate limit exceeded",
  "code": "RATE_LIMIT_EXCEEDED",
  "status": 429,
  "details": {
    "limit": 100,
    "window": "1 minute",
    "retryAfter": 45
  }
}
```

**Solution:** Wait before retrying or implement exponential backoff.

### Data Errors

#### `DATA_NOT_READY`

**Status:** 404

```json theme={null}
{
  "error": "Metrics data is still being processed",
  "code": "DATA_NOT_READY",
  "status": 404,
  "details": {
    "estimatedReadyAt": "2024-02-01T10:30:00Z"
  }
}
```

**Solution:** Wait for data processing to complete, then retry.

#### `INTEGRATION_NOT_CONNECTED`

**Status:** 400

```json theme={null}
{
  "error": "Google integration is not connected",
  "code": "INTEGRATION_NOT_CONNECTED",
  "status": 400,
  "details": {
    "provider": "google",
    "connectUrl": "https://app.gostanna.com/integrations"
  }
}
```

**Solution:** Connect the required integration through your dashboard.

#### `INSUFFICIENT_DATA`

**Status:** 404

```json theme={null}
{
  "error": "Not enough data to generate metrics",
  "code": "INSUFFICIENT_DATA", 
  "status": 404,
  "details": {
    "minimumClients": 3,
    "currentClients": 1
  }
}
```

**Solution:** Add more clients or wait for more interaction data.

### Server Errors

#### `INTERNAL_ERROR`

**Status:** 500

```json theme={null}
{
  "error": "An internal server error occurred",
  "code": "INTERNAL_ERROR",
  "status": 500,
  "details": {
    "requestId": "req_abc123"
  }
}
```

**Solution:** Contact support with the request ID.

#### `INTEGRATION_ERROR`

**Status:** 502

```json theme={null}
{
  "error": "External service temporarily unavailable",
  "code": "INTEGRATION_ERROR",
  "status": 502,
  "details": {
    "service": "google",
    "retryAfter": 300
  }
}
```

**Solution:** Retry after the specified delay.

## Error Handling Best Practices

### 1. Check Status Codes

Always check the HTTP status code before parsing the response:

```javascript theme={null}
const response = await fetch(url, options);

if (!response.ok) {
  const error = await response.json();
  console.error(`API Error: ${error.code} - ${error.error}`);
  return;
}

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

### 2. Implement Retry Logic

For temporary errors (429, 500, 502, 503), implement exponential backoff:

```javascript theme={null}
async function apiCallWithRetry(url, options, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      const response = await fetch(url, options);
      
      if (response.ok) {
        return await response.json();
      }
      
      // Don't retry client errors (4xx except 429)
      if (response.status >= 400 && response.status < 500 && response.status !== 429) {
        throw new Error(`Client error: ${response.status}`);
      }
      
      // Calculate delay: 1s, 2s, 4s
      const delay = Math.pow(2, attempt) * 1000;
      await new Promise(resolve => setTimeout(resolve, delay));
      
    } catch (error) {
      if (attempt === maxRetries - 1) throw error;
    }
  }
}
```

### 3. Handle Rate Limits

Respect rate limit headers and implement appropriate delays:

```javascript theme={null}
if (response.status === 429) {
  const retryAfter = response.headers.get('Retry-After');
  const delay = retryAfter ? parseInt(retryAfter) * 1000 : 60000;
  
  console.log(`Rate limited. Retrying after ${delay}ms`);
  await new Promise(resolve => setTimeout(resolve, delay));
  
  // Retry the request
}
```

### 4. Log Errors Appropriately

Log enough information for debugging without exposing sensitive data:

```javascript theme={null}
function logApiError(error, context) {
  console.error('API Error:', {
    code: error.code,
    status: error.status,
    message: error.error,
    endpoint: context.url,
    timestamp: new Date().toISOString(),
    // Don't log API keys or sensitive data
  });
}
```

### 5. Provide User-Friendly Messages

Convert technical error codes into user-friendly messages:

```javascript theme={null}
function getUserFriendlyMessage(errorCode) {
  const messages = {
    'AUTH_INVALID_KEY': 'Your API key is invalid. Please check your settings.',
    'RATE_LIMIT_EXCEEDED': 'Too many requests. Please wait a moment and try again.',
    'DATA_NOT_READY': 'Your data is still being processed. Please try again in a few minutes.',
    'INTEGRATION_NOT_CONNECTED': 'Please connect your integrations first.',
    'INSUFFICIENT_DATA': 'More client data is needed to generate insights.'
  };
  
  return messages[errorCode] || 'An unexpected error occurred. Please try again.';
}
```

## Rate Limiting Details

The API enforces the following rate limits:

| Limit Type      | Threshold       | Window   |
| --------------- | --------------- | -------- |
| Per API Key     | 100 requests    | 1 minute |
| Per Workspace   | 10,000 requests | 1 day    |
| Bulk Operations | 10 requests     | 1 minute |

### Rate Limit Headers

All responses include rate limiting information:

```
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95  
X-RateLimit-Reset: 1643723400
```

### Handling Rate Limits

When you hit a rate limit, the API returns:

```json theme={null}
{
  "error": "Rate limit exceeded",
  "code": "RATE_LIMIT_EXCEEDED", 
  "status": 429,
  "details": {
    "limit": 100,
    "remaining": 0,
    "resetAt": "2024-02-01T10:30:00Z",
    "retryAfter": 45
  }
}
```

Wait for the `retryAfter` seconds before making another request.

## Getting Help

If you encounter errors not covered here:

1. Check your API key and workspace ID
2. Verify the endpoint URL and parameters
3. Test with a simple cURL command
4. Check our status page for known issues
5. Contact support at [support@gostanna.com](mailto:support@gostanna.com) with the error code and request details
