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

# Error Handling

> Understand how to handle errors from the Turris Public API

# Error Handling

The Turris Public API uses conventional HTTP response codes and returns detailed error information to help you handle issues gracefully.

## HTTP Status Codes

| Status Code | Meaning                                                 |
| ----------- | ------------------------------------------------------- |
| `200`       | Success - Request completed successfully                |
| `201`       | Created - Resource was created successfully             |
| `400`       | Bad Request - Invalid request parameters                |
| `401`       | Unauthorized - Missing or invalid authentication        |
| `403`       | Forbidden - Valid auth but insufficient permissions     |
| `404`       | Not Found - Resource doesn't exist                      |
| `422`       | Unprocessable Entity - Validation failed                |
| `429`       | Too Many Requests - Rate limit exceeded                 |
| `500`       | Internal Server Error - Something went wrong on our end |

## Error Response Format

All error responses follow a consistent format:

```json theme={null}
{
  "statusCode": 400,
  "requestId": "dev-63c50377-1cfa-4d51-bce7-d187507853db",
  "errorType": "invalid_input",
  "errorMessage": ["Field 'npn' is required"],
  "timestamp": "2025-01-30T09:58:12.488Z"
}
```

### Response Fields

| Field          | Type      | Description                                             |
| -------------- | --------- | ------------------------------------------------------- |
| `statusCode`   | number    | HTTP status code                                        |
| `requestId`    | string    | Unique identifier for this request (useful for support) |
| `errorType`    | string    | Category of the error                                   |
| `errorMessage` | string\[] | Array of human-readable error messages                  |
| `timestamp`    | string    | ISO 8601 timestamp of when the error occurred           |

## Error Types

### `unauthorized`

Authentication failed or was not provided.

```json theme={null}
{
  "statusCode": 401,
  "errorType": "unauthorized",
  "errorMessage": ["Authentication token not provided"]
}
```

**Common causes:**

* Missing `Authorization` header
* Expired JWT token
* Invalid token format

### `forbidden`

Authentication succeeded but the request is not allowed.

```json theme={null}
{
  "statusCode": 403,
  "errorType": "forbidden",
  "errorMessage": ["IP address \"192.168.1.1\" not in allowed list for token \"***-a5ed\""]
}
```

**Common causes:**

* IP not in allowlist (for Restricted Access Tokens)
* Insufficient permissions for the requested resource

### `invalid_input`

Request validation failed.

```json theme={null}
{
  "statusCode": 400,
  "errorType": "invalid_input",
  "errorMessage": [
    "npn must be a string",
    "stateCode must be a valid US state code"
  ]
}
```

**Common causes:**

* Missing required fields
* Invalid field formats
* Mutually exclusive parameters provided together

### `not_found`

The requested resource doesn't exist.

```json theme={null}
{
  "statusCode": 404,
  "errorType": "not_found",
  "errorMessage": ["Agent with ID '507f1f77bcf86cd799439011' not found"]
}
```

### `internal_error`

Something went wrong on our servers.

```json theme={null}
{
  "statusCode": 500,
  "errorType": "internal_error",
  "errorMessage": ["An unexpected error occurred"]
}
```

<Note>
  If you receive a 500 error, please contact support with the `requestId` for investigation.
</Note>

## Handling Errors

### Example: JavaScript/TypeScript

```typescript theme={null}
async function fetchAgents() {
  try {
    const response = await fetch(
      'https://public.api.live.turrisfi.com/v1/agents',
      {
        headers: {
          'Authorization': `Bearer ${accessToken}`
        }
      }
    );

    if (!response.ok) {
      const error = await response.json();
      
      switch (error.statusCode) {
        case 401:
          // Token expired - refresh and retry
          await refreshToken();
          return fetchAgents();
        case 429:
          // Rate limited - wait and retry
          await sleep(60000);
          return fetchAgents();
        case 400:
          // Bad request - log and don't retry
          console.error('Validation error:', error.errorMessage);
          throw new Error(error.errorMessage.join(', '));
        default:
          throw new Error(`API error: ${error.errorMessage.join(', ')}`);
      }
    }

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

### Example: Python

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

def fetch_agents(access_token: str, retry_count: int = 0):
    try:
        response = requests.get(
            'https://public.api.live.turrisfi.com/v1/agents',
            headers={'Authorization': f'Bearer {access_token}'}
        )
        
        if response.status_code == 200:
            return response.json()
        
        error = response.json()
        
        if response.status_code == 401 and retry_count < 1:
            # Token expired - refresh and retry
            new_token = refresh_token()
            return fetch_agents(new_token, retry_count + 1)
        
        if response.status_code == 429 and retry_count < 3:
            # Rate limited - wait and retry
            time.sleep(60)
            return fetch_agents(access_token, retry_count + 1)
        
        raise Exception(f"API error: {', '.join(error['errorMessage'])}")
        
    except requests.RequestException as e:
        print(f"Request failed: {e}")
        raise
```

## Best Practices

<AccordionGroup>
  <Accordion title="Always check the status code">
    Don't assume requests succeed. Check the HTTP status code and handle errors appropriately.
  </Accordion>

  <Accordion title="Log the requestId">
    The `requestId` is essential for debugging. Log it when errors occur so you can reference it when contacting support.
  </Accordion>

  <Accordion title="Implement retry logic">
    For transient errors (429, 500, 503), implement exponential backoff retry logic.
  </Accordion>

  <Accordion title="Handle token expiration gracefully">
    OAuth tokens expire after 60 minutes. Implement proactive token refresh or handle 401 errors by refreshing and retrying.
  </Accordion>
</AccordionGroup>
