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

# Error Codes

> Complete reference of API error types, status codes, and billing failures

# Error Codes

The Kallglot API returns structured JSON errors with machine-readable `code` and `type` fields.

<Info>
  In your integration, branch on **HTTP status** and **`error.code`**. Log **`error.message`** and **`request_id`** when you need support.
</Info>

<Note>
  **Avoid mixing up session fields:** Create-session telephony belongs in **`routing`**. If you copy the **`provider`** string from a **response** or a **webhook** payload into your **`POST /v1/sessions`** body, the request will not match the API. Use [Create Session](/api-reference/sessions/create) and [Telephony providers](/concepts/providers) as the source of truth for request JSON.
</Note>

## HTTP Status Codes

| Code  | Description                                          |
| ----- | ---------------------------------------------------- |
| `200` | Success                                              |
| `201` | Created                                              |
| `202` | Accepted                                             |
| `400` | Invalid request                                      |
| `401` | Authentication failed                                |
| `402` | Payment required or API credits exhausted            |
| `403` | Permission denied or inactive organization           |
| `404` | Resource not found                                   |
| `502` | Upstream gateway error (for example SIP dial failed) |
| `409` | Conflict                                             |
| `422` | Request validation failed before handler execution   |
| `429` | Rate limit exceeded                                  |
| `500` | Server error                                         |
| `503` | Temporary service outage                             |

## Error Response Format

```json theme={null}
{
  "error": {
    "type": "permission_error",
    "code": "insufficient_api_credits",
    "message": "API credits exhausted. Purchase more credits to continue.",
    "request_id": "req_123"
  }
}
```

| Field         | Description                                                |
| ------------- | ---------------------------------------------------------- |
| `type`        | High-level error category                                  |
| `code`        | Machine-readable error code                                |
| `message`     | Human-readable explanation                                 |
| `param`       | Request field related to the error, when available         |
| `request_id`  | Request identifier for support and debugging               |
| `retry_after` | Retry delay in seconds for retryable limit/conflict errors |

## Useful Error Headers

| Header                    | When Present                   | Description                      |
| ------------------------- | ------------------------------ | -------------------------------- |
| `X-Request-ID`            | API V1 HTTP responses          | Request identifier               |
| `Retry-After`             | `429` and some `409` responses | Seconds to wait before retrying  |
| `X-API-Credits-Remaining` | Authenticated HTTP responses   | Remaining API credits            |
| `X-API-Credits-Used`      | Authenticated HTTP responses   | Credits used this billing period |

## Error Types

### authentication\_error

| Code                        | Status | Description                                 |
| --------------------------- | ------ | ------------------------------------------- |
| `api_key_invalid`           | `401`  | API key is missing, malformed, or unknown   |
| `api_key_expired`           | `401`  | API key has expired                         |
| `api_key_revoked`           | `401`  | API key has been revoked                    |
| `api_key_wrong_environment` | `401`  | Test/live key used in the wrong environment |
| `stream_token_invalid`      | `401`  | Stream token is invalid or expired          |

### permission\_error

| Code                       | Status | Description                                |
| -------------------------- | ------ | ------------------------------------------ |
| `organization_inactive`    | `403`  | Organization subscription is inactive      |
| `insufficient_api_credits` | `402`  | Organization has no API credits remaining  |
| `insufficient_permissions` | `403`  | API key lacks required permission          |
| `ai_agent_disabled`        | `403`  | AI agent mode is not enabled               |
| `override_not_allowed`     | `403`  | Requested AI override field is not allowed |
| `recording_not_permitted`  | `403`  | Recording access is disallowed by policy   |
| `consent_required`         | `403`  | Recording access requires missing consent  |

### invalid\_request\_error

| Code                       | Status | Description                                                                                              |
| -------------------------- | ------ | -------------------------------------------------------------------------------------------------------- |
| `idempotency_mismatch`     | `400`  | Same idempotency key reused with a different body                                                        |
| `unsupported_mode`         | `400`  | Session mode is not supported                                                                            |
| `transcript_not_available` | `400`  | Transcript is not available for analysis                                                                 |
| `validation_error`         | `400`  | Request body is syntactically valid but semantically invalid                                             |
| `invalid_audio_format`     | `400`  | WebSocket audio format is unsupported                                                                    |
| `routing_failed`           | `400`  | Telephony routing could not be resolved. See the `docs_url` in the error response for specific guidance. |
| `sip_not_enabled`          | `400`  | SIP routing is not enabled. Enable SIP in the Telephony section of the Developer Portal.                 |
| `session_not_dialable`     | `400`  | Session cannot be dialed or hung up in its current state                                                 |
| `no_default_provider`      | `400`  | No provider connection can be resolved. Add a provider connection or buy a managed number.               |
| `phone_number_not_found`   | `400`  | The phone number is not a Kallglot-managed number for this organization                                  |
| `connection_not_found`     | `400`  | The provider connection ID does not exist or is inactive                                                 |
| `connection_invalid`       | `400`  | The provider connection credentials are invalid or expired                                               |

### conflict\_error

| Code                       | Status | Description                          |
| -------------------------- | ------ | ------------------------------------ |
| `session_already_ended`    | `409`  | Session has already ended            |
| `idempotency_conflict`     | `409`  | Matching request is still processing |
| `stream_already_connected` | `409`  | Session already has an active stream |

### not\_found\_error

| Code                  | Status | Description                                                       |
| --------------------- | ------ | ----------------------------------------------------------------- |
| `session_not_found`   | `404`  | Session does not exist or is not owned by your org                |
| `recording_not_found` | `404`  | Recording does not exist                                          |
| `analysis_not_found`  | `404`  | Analysis does not exist                                           |
| `agent_not_found`     | `404`  | AI agent resource not found (Agents API)                          |
| `ai_agent_not_found`  | `404`  | Referenced AI agent ID could not be resolved for session creation |

### rate\_limit\_error

| Code                       | Status | Description                                   |
| -------------------------- | ------ | --------------------------------------------- |
| `rate_limit_exceeded`      | `429`  | Too many requests in the current window       |
| `concurrent_session_limit` | `429`  | Too many active sessions for the organization |

### api\_error

| Code                     | Status | Description                                                                                                                              |
| ------------------------ | ------ | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `internal_error`         | `500`  | Unexpected error—retry or contact support with `request_id`                                                                              |
| `service_unavailable`    | `503`  | Required dependency is temporarily unavailable (message may name a subsystem, e.g. billing). Retry with backoff; not a client or URL bug |
| `freeswitch_unavailable` | `503`  | SIP dialing path temporarily unavailable                                                                                                 |
| `dial_failed`            | `502`  | Outbound SIP dial attempt failed                                                                                                         |

## Handling Errors

### JavaScript

```javascript theme={null}
const response = await fetch('https://api.kallglot.com/v1/sessions', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.KALLGLOT_API_KEY}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    mode: 'bidirectional_translation',
    source_language: 'de',
    target_language: 'en'
  })
});

if (!response.ok) {
  const payload = await response.json();
  const error = payload.error;

  if (response.status === 402 && error.code === 'insufficient_api_credits') {
    console.error('Buy more API credits in the Developer Portal');
  } else if (response.status === 403 && error.code === 'organization_inactive') {
    console.error('Activate a subscription for this organization');
  } else if (response.status === 429) {
    const retryAfter = Number(response.headers.get('Retry-After') || '1');
    await sleep(retryAfter * 1000);
  } else {
    console.error(`${error.code}: ${error.message}`);
  }
}
```

### Python

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

response = requests.post(
    'https://api.kallglot.com/v1/sessions',
    headers={
        'Authorization': f'Bearer {API_KEY}',
        'Content-Type': 'application/json'
    },
    json={
        'mode': 'bidirectional_translation',
        'source_language': 'de',
        'target_language': 'en'
    }
)

if response.status_code == 402:
    error = response.json()['error']
    if error['code'] == 'insufficient_api_credits':
        print('Purchase more API credits in the Developer Portal')
elif response.status_code == 429:
    time.sleep(int(response.headers.get('Retry-After', '1')))
elif response.status_code >= 400:
    error = response.json().get('error', {})
    print(f"{error.get('code')}: {error.get('message')}")
```

## Retry Guidance

| Error Type              | Retry?    | Guidance                                  |
| ----------------------- | --------- | ----------------------------------------- |
| `rate_limit_error`      | Yes       | Wait for `Retry-After` or reset window    |
| `api_error`             | Yes       | Retry with exponential backoff            |
| `conflict_error`        | Sometimes | Retry only when explicitly safe           |
| `invalid_request_error` | No        | Fix the request first                     |
| `authentication_error`  | No        | Correct the credentials or token          |
| `permission_error`      | No        | Fix billing, subscription, or permissions |

## WebSocket Close Codes

| Code   | Meaning                                               |
| ------ | ----------------------------------------------------- |
| `1000` | Normal close                                          |
| `1001` | Going away                                            |
| `1002` | Protocol error                                        |
| `4001` | Invalid or expired stream token                       |
| `4004` | Session not found                                     |
| `4009` | Stream already active                                 |
| `4010` | Session already ended                                 |
| `4029` | Rate limited                                          |
| `4500` | Streaming connection closed after a server-side error |

## Common Issues

<AccordionGroup>
  <Accordion title="api_key_invalid">
    **Cause:** The API key is missing, malformed, or does not exist.

    **What to do:** Confirm the key starts with `sk_live_` or `sk_test_`, pass it in `Authorization: Bearer ...`, and verify that the key still exists in the Developer Portal.
  </Accordion>

  <Accordion title="organization_inactive">
    **Cause:** The key is valid, but the owning organization does not have an active subscription.

    **What to do:** Activate or renew the organization subscription before retrying API requests.
  </Accordion>

  <Accordion title="insufficient_api_credits">
    **Cause:** The organization has exhausted its API credits.

    **What to do:** Purchase more API credits in the Developer Portal and retry the request. Check `X-API-Credits-Remaining` to monitor balances proactively.
  </Accordion>

  <Accordion title="rate_limit_exceeded">
    **Cause:** Too many requests were sent in the current window.

    **What to do:** Honor the `Retry-After` header, reduce concurrency, and implement backoff for automated clients.
  </Accordion>

  <Accordion title="session_not_found">
    **Cause:** The session ID does not exist or does not belong to the authenticated organization.

    **What to do:** Verify the `sess_...` id and ensure you are using an API key for the same organization that created the session.
  </Accordion>

  <Accordion title="sip_not_enabled">
    **Cause:** The session requested SIP routing but SIP is not enabled for this organization.

    **What to do:** Go to the Developer Portal > Telephony and enable SIP in the SIP / PBX section. Configure your allowed IPs before enabling.
  </Accordion>

  <Accordion title="no_default_provider">
    **Cause:** No telephony route could be resolved. You didn't specify a phone number, connection ID, or SIP mode, and there's no default provider connection configured.

    **What to do:** Either pass `routing.phone_number` for a Kallglot-managed number, `routing.connection_id` for an external provider, or `routing.type: "sip"` for SIP mode. Alternatively, set a default provider connection in the Developer Portal.
  </Accordion>

  <Accordion title="routing_failed">
    **Cause:** Telephony routing could not be resolved. This is a general routing error that includes specific guidance in the `docs_url` field of the error response.

    **What to do:** Check the `docs_url` in the error response for specific guidance. Common causes include:

    * No provider connection configured (use `routing.connection_id`)
    * Phone number not managed by your organization (verify in Developer Portal)
    * Ambiguous routing with multiple connections (specify `routing.connection_id`)
    * SIP mode requested but not enabled
  </Accordion>

  <Accordion title="connection_not_found">
    **Cause:** The provider connection ID specified in `routing.connection_id` doesn't exist or has been deleted.

    **What to do:** Verify the connection ID in the Developer Portal > Telephony > External Provider Connections. Ensure the connection is active.
  </Accordion>
</AccordionGroup>
