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

# Error Codes

> Comprehensive guide to Junis External API error codes and responses

## Overview

The Junis External API uses conventional HTTP status codes to indicate the success or failure of a request. Error responses include a structured JSON body with details about the error, making it easy to debug and handle errors programmatically.

**Base URL**: `https://api.junis.ai`

***

## Error Response Format

### Standard Error Response

All error responses follow this consistent structure:

```json theme={null}
{
  "detail": "Human-readable error message"
}
```

### Structured Error Response

For more complex errors (like rate limiting or scope validation), the API returns additional context:

```json theme={null}
{
  "error": "error_code",
  "message": "Human-readable error message",
  "code": "SPECIFIC_ERROR_CODE",
  "details": {
    // Additional error-specific details
  }
}
```

***

## HTTP Status Codes

<AccordionGroup>
  <Accordion title="2xx Success" icon="check">
    | Status Code | Name       | Description                                         |
    | ----------- | ---------- | --------------------------------------------------- |
    | **200**     | OK         | Request succeeded.                                  |
    | **201**     | Created    | Resource successfully created.                      |
    | **202**     | Accepted   | Request accepted for processing (async operations). |
    | **204**     | No Content | Request succeeded with no response body.            |
  </Accordion>

  <Accordion title="4xx Client Errors" icon="exclamation-circle">
    | Status Code | Name              | Description                                          |
    | ----------- | ----------------- | ---------------------------------------------------- |
    | **400**     | Bad Request       | Invalid request parameters or malformed JSON.        |
    | **401**     | Unauthorized      | Missing or invalid API key.                          |
    | **403**     | Forbidden         | Authenticated but insufficient permissions (scopes). |
    | **404**     | Not Found         | Resource does not exist.                             |
    | **413**     | Payload Too Large | Request body exceeds size limit.                     |
    | **429**     | Too Many Requests | Rate limit exceeded.                                 |
  </Accordion>

  <Accordion title="5xx Server Errors" icon="exclamation-triangle">
    | Status Code | Name                  | Description                            |
    | ----------- | --------------------- | -------------------------------------- |
    | **500**     | Internal Server Error | Unexpected server error.               |
    | **502**     | Bad Gateway           | Upstream service unavailable.          |
    | **503**     | Service Unavailable   | Server temporarily overloaded or down. |
    | **504**     | Gateway Timeout       | Upstream service timeout.              |
  </Accordion>
</AccordionGroup>

***

## Common Error Codes

### Authentication Errors (401)

<AccordionGroup>
  <Accordion title="missing_api_key" icon="key">
    **Description**: No API key provided in request headers.

    **Causes**:

    * Missing `X-API-Key` header
    * Empty `X-API-Key` header value

    **Response Example**:

    ```json theme={null}
    {
      "detail": "API key required. Include X-API-Key header with your request."
    }
    ```

    **Response Headers**:

    ```
    HTTP/1.1 401 Unauthorized
    WWW-Authenticate: ApiKey
    ```

    **Solution**:

    ```bash theme={null}
    # Include X-API-Key header
    curl https://api.junis.ai/api/external/v1/chat/completions \
      -H "X-API-Key: jns_live_YOUR_API_KEY"
    ```
  </Accordion>

  <Accordion title="invalid_api_key" icon="key">
    **Description**: API key not found, revoked, or expired.

    **Causes**:

    * API key deleted by organization admin
    * API key revoked
    * Wrong API key format
    * API key expired (if expiration was set)

    **Response Example**:

    ```json theme={null}
    {
      "detail": "Invalid or expired API key"
    }
    ```

    **Solution**:

    * Verify API key in **Admin → API Keys**
    * Generate new API key if revoked or expired
    * Check API key format: `jns_live_` prefix + 32 characters
  </Accordion>
</AccordionGroup>

***

### Authorization Errors (403)

<AccordionGroup>
  <Accordion title="insufficient_scopes" icon="ban">
    **Description**: API key lacks required scopes for the operation.

    **Causes**:

    * API key created without required scopes
    * API key missing `orchestrator:invoke` scope (required for chat completions)
    * API key missing `sessions:read` or `sessions:messages` scope

    **Response Example**:

    ```json theme={null}
    {
      "error": "insufficient_scopes",
      "message": "API key does not have required permissions",
      "required_scopes": ["orchestrator:invoke"],
      "missing_scopes": ["orchestrator:invoke"],
      "available_scopes": ["sessions:read", "sessions:messages"]
    }
    ```

    **Solution**:

    * Check API key scopes in **Admin → API Keys**
    * Create new API key with required scopes:
      * `orchestrator:invoke` - Chat completions (both streaming and non-streaming)
      * `sessions:read` - List sessions and get session status
      * `sessions:messages` - Get session messages
  </Accordion>

  <Accordion title="organization_access_denied" icon="building">
    **Description**: API key belongs to a different organization.

    **Causes**:

    * Trying to access sessions created by another organization
    * Trying to access resources not owned by your organization

    **Response Example**:

    ```json theme={null}
    {
      "detail": "Access denied. Resource belongs to a different organization."
    }
    ```

    **Solution**:

    * Verify you're using the correct API key for your organization
    * Each API key can only access its own organization's resources
  </Accordion>
</AccordionGroup>

***

### Validation Errors (400)

<AccordionGroup>
  <Accordion title="invalid_input" icon="exclamation">
    **Description**: Request body validation failed.

    **Causes**:

    * Missing required fields
    * Invalid field types
    * Failed Pydantic validation

    **Response Example**:

    ```json theme={null}
    {
      "detail": [
        {
          "loc": ["body", "messages"],
          "msg": "field required",
          "type": "value_error.missing"
        },
        {
          "loc": ["body", "model"],
          "msg": "str type expected",
          "type": "type_error.str"
        }
      ]
    }
    ```

    **Solution**:

    * Check API documentation for required fields
    * Verify data types match schema
    * Example valid request:

    ```json theme={null}
    {
      "messages": [
        {"role": "user", "content": "Hello"}
      ]
    }
    ```
  </Accordion>

  <Accordion title="invalid_json" icon="code">
    **Description**: Malformed JSON in request body.

    **Causes**:

    * Syntax error in JSON
    * Unescaped special characters
    * Trailing commas

    **Response Example**:

    ```json theme={null}
    {
      "detail": "Expecting property name enclosed in double quotes"
    }
    ```

    **Solution**:

    * Validate JSON syntax using a linter
    * Escape special characters properly
    * Remove trailing commas
  </Accordion>
</AccordionGroup>

***

### Resource Errors (404)

<AccordionGroup>
  <Accordion title="session_not_found" icon="comments">
    **Description**: Chat session does not exist.

    **Causes**:

    * Session deleted
    * Wrong session\_id
    * Session belongs to different organization

    **Response Example**:

    ```json theme={null}
    {
      "detail": "Session not found"
    }
    ```

    **Solution**:

    * Verify session\_id is correct
    * Create new session via Chat Completions API
    * List available sessions: `GET /api/external/sessions`
  </Accordion>

  <Accordion title="message_not_found" icon="comment">
    **Description**: Message does not exist in session.

    **Causes**:

    * Invalid message index
    * Session has no messages yet

    **Response Example**:

    ```json theme={null}
    {
      "detail": "Message not found in session"
    }
    ```

    **Solution**:

    * Check session messages: `GET /api/external/sessions/{id}/messages`
    * Verify message index is within range
  </Accordion>
</AccordionGroup>

***

### Rate Limit Errors (429)

<AccordionGroup>
  <Accordion title="rate_limit_exceeded" icon="gauge-high">
    **Description**: Too many requests in time window.

    **Response Example**:

    ```json theme={null}
    {
      "error": "rate_limit_exceeded",
      "message": "Rate limit exceeded: 60 requests per minute",
      "limit": 60,
      "window": "minute",
      "reset_at": 1767261600,
      "retry_after": 45
    }
    ```

    **Response Headers**:

    ```
    HTTP/1.1 429 Too Many Requests
    X-RateLimit-Limit-Minute: 60
    X-RateLimit-Remaining-Minute: 0
    X-RateLimit-Reset-Minute: 1767261600
    X-RateLimit-Limit-Hour: 1000
    X-RateLimit-Remaining-Hour: 950
    X-RateLimit-Reset-Hour: 1767261600
    Retry-After: 45
    ```

    **Solution**:

    * Wait for `retry_after` seconds before retrying
    * Implement exponential backoff
    * Monitor `X-RateLimit-Remaining-*` headers
    * Request higher rate limits in **Admin → API Keys**
    * Cache responses to reduce request frequency

    See [Rate Limits](/api-reference/rate-limits) for more details.
  </Accordion>
</AccordionGroup>

***

### Payload Errors (413)

<AccordionGroup>
  <Accordion title="payload_too_large" icon="file-arrow-up">
    **Description**: Request body exceeds size limit.

    **Causes**:

    * Large message content
    * Too many messages in array
    * Maximum payload: 10MB

    **Response Example**:

    ```json theme={null}
    {
      "detail": "Request payload too large. Maximum size: 10MB"
    }
    ```

    **Solution**:

    * Split large requests into smaller chunks
    * Summarize long messages
    * Use pagination for message history
  </Accordion>
</AccordionGroup>

***

### Server Errors (500)

<AccordionGroup>
  <Accordion title="internal_server_error" icon="server">
    **Description**: Unexpected server error occurred.

    **Causes**:

    * Database connection failure
    * External service timeout
    * Unhandled exception

    **Response Example**:

    ```json theme={null}
    {
      "detail": "Internal server error"
    }
    ```

    **Solution**:

    * Retry request after a few seconds with exponential backoff
    * Check [Status Page](https://status.junis.ai) for incidents
    * Contact support if error persists: [contact@junis.ai](mailto:contact@junis.ai)
  </Accordion>

  <Accordion title="llm_service_unavailable" icon="robot">
    **Description**: LLM provider (Anthropic, OpenAI) unavailable.

    **Causes**:

    * Anthropic API outage
    * OpenAI API rate limits
    * Network timeout to LLM provider

    **Response Example**:

    ```json theme={null}
    {
      "detail": "LLM service temporarily unavailable. Please try again."
    }
    ```

    **Solution**:

    * Retry request with exponential backoff
    * Check [Anthropic Status](https://status.anthropic.com)
    * Wait a few minutes and retry
  </Accordion>

  <Accordion title="orchestrator_error" icon="sitemap">
    **Description**: Agent orchestration failed.

    **Causes**:

    * Agent not found
    * Agent configuration error
    * Tool execution failure

    **Response Example**:

    ```json theme={null}
    {
      "detail": "Orchestrator processing error. Please try again."
    }
    ```

    **Solution**:

    * Retry request
    * Simplify prompt if issue persists
    * Contact support with session\_id for debugging
  </Accordion>
</AccordionGroup>

***

## Error Handling Best Practices

### Retry Logic

Implement exponential backoff for transient errors (429, 500+ status codes):

* **429 Rate Limit**: Use the `Retry-After` header value to wait before retrying
* **5xx Server Errors**: Use exponential backoff (1s, 2s, 4s, etc.)
* **Max Retries**: Limit to 3-5 attempts to avoid infinite loops
* **Client Errors (4xx)**: Do not retry, fix the request instead

### Error Logging

Log errors with sufficient context for debugging:

* **Include**: Timestamp, status code, error message, request URL, method
* **Exclude**: Full API key (log only prefix like `jns_live_abc...`)
* **Structured Logging**: Use JSON format for easier parsing

### User-Friendly Error Messages

Present errors to users in a helpful way:

* **401 Unauthorized**: "Invalid API key. Please check your credentials."
* **403 Forbidden**: "Permission denied. Check your API key scopes."
* **429 Rate Limit**: "Too many requests. Please wait {retry_after} seconds."
* **5xx Server Errors**: "Our servers are experiencing issues. Please try again."
* **Generic Fallback**: Use the `detail` field from the error response

***

## Debugging Tools

### Check API Status

```bash theme={null}
curl https://api.junis.ai/api/health
```

**Healthy Response**:

```json theme={null}
{
  "status": "healthy",
  "version": "1.0.0",
  "timestamp": "2026-01-01T10:00:00Z"
}
```

### Test API Key Authentication

```bash theme={null}
curl https://api.junis.ai/api/external/sessions \
  -H "X-API-Key: jns_live_YOUR_API_KEY"
```

**Success Response** (200 OK):

```json theme={null}
{
  "sessions": [],
  "total": 0,
  "limit": 50,
  "offset": 0
}
```

**Error Response** (401 Unauthorized):

```json theme={null}
{
  "detail": "Invalid or expired API key"
}
```

### Inspect Rate Limits

```bash theme={null}
curl -I https://api.junis.ai/api/external/v1/chat/completions \
  -X POST \
  -H "X-API-Key: jns_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"messages":[{"role":"user","content":"test"}]}'
```

**Response Headers**:

```
HTTP/1.1 200 OK
X-RateLimit-Limit-Minute: 60
X-RateLimit-Remaining-Minute: 55
X-RateLimit-Reset-Minute: 1767261600
X-RateLimit-Limit-Hour: 1000
X-RateLimit-Remaining-Hour: 950
X-RateLimit-Reset-Hour: 1767261600
```

***

## Monitoring and Alerts

### Track Error Rates

Monitor these metrics for your API integration:

<CardGroup cols={2}>
  <Card title="Success Rate" icon="check">
    Track 2xx responses vs total requests

    **Target**: > 99% success rate
  </Card>

  <Card title="4xx Errors" icon="exclamation">
    Client errors (auth, validation, rate limits)

    **Alert**: > 5% of requests
  </Card>

  <Card title="5xx Errors" icon="server">
    Server errors (outages, timeouts)

    **Alert**: Any occurrence
  </Card>

  <Card title="Response Time" icon="clock">
    P50, P95, P99 latency

    **Target**: P95 \< 2 seconds
  </Card>
</CardGroup>

### Sample Monitoring Code

```python theme={null}
import prometheus_client as prom

# Define metrics
api_requests = prom.Counter('api_requests_total', 'Total API requests', ['status'])
api_latency = prom.Histogram('api_latency_seconds', 'API request latency')

# Track request
with api_latency.time():
    response = requests.post(url, headers=headers, json=payload)
    api_requests.labels(status=response.status_code).inc()
```

***

## Need Help?

<CardGroup cols={2}>
  <Card title="API Status" icon="signal" href="https://status.junis.ai">
    Check real-time API status and incidents
  </Card>

  <Card title="Rate Limits" icon="gauge-high" href="/api-reference/rate-limits">
    Learn about rate limiting and optimization
  </Card>

  <Card title="Authentication" icon="key" href="/api-reference/authentication">
    Review API key authentication
  </Card>

  <Card title="Support" icon="life-ring" href="mailto:contact@junis.ai">
    Contact support for assistance
  </Card>
</CardGroup>
