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

# Errors

> Error codes and handling for the Nineninesix API.

The API returns errors as JSON with an `error` code and a human-readable `message`.

## Error Format

```json theme={null}
{
  "error": "payment_required",
  "message": "insufficient credits"
}
```

| Field     | Type   | Description                 |
| --------- | ------ | --------------------------- |
| `error`   | string | Machine-readable error code |
| `message` | string | Human-readable description  |

## Errors

### `unauthorized` (401)

The API key is missing, malformed, invalid, or revoked.

```json theme={null}
{ "error": "unauthorized", "message": "invalid API key" }
```

**Fix**: Send a valid, non-revoked key via `Authorization: Bearer sk_996_...` (or `?api_key=` for WebSockets).

### `invalid_json` / `missing_transcript` (400)

The request body is malformed or missing required fields.

**Common causes**:

* Invalid JSON body
* Missing `transcript`, `voice`, `model_id`, or `output_format`

### Invalid `output_format` (400)

The `output_format` uses an unsupported `container`, `encoding`, or `sample_rate`. Validation is strict — there's no silent fallback. The `message` names the offending field.

**Common causes**:

* Removed formats: `container: "mp3"`, `encoding: "pcm_f32le"`
* Unsupported `sample_rate` (only `8000`, `16000`, `22050` are allowed)
* `container: "wav"` on a streaming endpoint (`/tts/sse`, `/tts/websocket` are `raw`-only)

**Fix**: Use a supported combination — see [Create Speech → Output Format](/api-reference/speech#output-format).

### `payment_required` (402)

The organization's credit balance can't cover the request.

```json theme={null}
{ "error": "payment_required", "message": "insufficient credits" }
```

**Fix**: Top up on the [Billing](https://nineninesix.ai/billing) page.

### `rate_limited` / `concurrent_limit` (429)

You've exceeded your org's per-minute request rate or concurrency cap (shared across all your API keys). See [Rate Limits](/rate-limits).

**Fix**: Honor the `Retry-After` header and retry. For `concurrent_limit`, retry the rejected turn on a fresh `context_id` — only that context was rejected, not the whole connection.

### `billing_unavailable` (503)

Credits couldn't be verified, so the request fails closed (no audio is generated and you aren't charged).

**Fix**: Retry shortly.

### `upstream_unavailable` (502)

The synthesis backend errored. Any pre-charge is refunded automatically.

**Fix**: Retry the request. If it persists, contact support.

## Handling Errors in Code

```typescript theme={null}
import { Cartesia, APIError } from "@cartesia/cartesia-js";

const client = new Cartesia({ apiKey: "sk_996_your_api_key", baseURL: "https://api.nineninesix.ai" });

try {
  const res = await client.tts.generate({
    model_id: "gepard-1.0",
    transcript: "Hello!",
    voice: { mode: "id", id: "<voice-id>" },
    output_format: { container: "wav", encoding: "pcm_s16le", sample_rate: 22050 },
  });
} catch (err) {
  if (err instanceof APIError) {
    if (err.status === 402) console.error("Out of credits — top up");
    else if (err.status === 429) console.error("Rate limited — retry later");
    else console.error(`API error: ${err.message}`);
  }
}
```
