# Errors

> The Munsit API uses standard HTTP status codes and custom numeric error codes to indicate what went wrong. All errors come back in one consistent JSON format, so a single handler covers every endpoint.

## Error response format

Every error response follows this structure. The HTTP status code in the response header corresponds to the error type, while `errorCode` provides a specific numeric code for programmatic error handling.

```
{
  "errorCode": 40001,
  "errorMessage": "Error description"
}
```

## Error code reference

Every code the API returns, in one table.

| Error code | HTTP status | Error type | Description |
| --- | --- | --- | --- |
| 40001 | 400 | **ValidationError** | Request validation failed |
| 40101 | 401 | **AuthenticationError** | Authentication failed or invalid API key |
| 40201 | 402 | **InsufficientBalanceError** | Insufficient account balance |
| 40301 | 403 | **ModelAccessError** | Model access denied |
| 40401 | 404 | **NotFoundError** | Resource not found |
| 42901 | 429 | **ConcurrencyLimitError** | Concurrent request limit exceeded |
| 50001 | 500/502/503/504 | **InternalError** | Internal server or external service error |

## Error types

Each type carries an `errorCode` (number) and a human-readable `errorMessage` (string). Switch tabs for a real example body of each one.

```
{
  "errorCode": 40001,
  "errorMessage": "Text must have at least 3 words and 10 characters"
}
```

```
{
  "errorCode": 40101,
  "errorMessage": "Invalid API key"
}
```

```
{
  "errorCode": 40201,
  "errorMessage": "Insufficient wallet balance. Required: $0.50, Available: $0.25"
}
```

```
{
  "errorCode": 40301,
  "errorMessage": "This model is not enabled for your account. Please contact support@munsit.com to get access."
}
```

```
{
  "errorCode": 40401,
  "errorMessage": "Model not found: faseeh-v2-preview"
}
```

```
{
  "errorCode": 42901,
  "errorMessage": "Concurrency limit exceeded. Maximum 5 concurrent requests allowed. Current: 6. Please upgrade your plan https://app.munsit.com/en/subscription or contact support@munsit.com for more information."
}
```

```
{
  "errorCode": 50001,
  "errorMessage": "Internal server error"
}
```

| Type | Common scenarios |
| --- | --- |
| **ValidationError**  
400 · 40001 | Empty or missing required fields · text too short (less than 3 words or 10 characters) · parameter values out of range · invalid message types (WebSocket) · missing voice embeddings · payload too large. |
| **AuthenticationError**  
401 · 40101 | Missing `x-api-key` header · invalid API key format · expired API key · revoked or deleted API key · invalid JWT signature. |
| **InsufficientBalanceError**  
402 · 40201 | Account balance is insufficient to complete the request. The message includes the exact amount required and the current available balance — recharge to continue. |
| **ModelAccessError**  
403 · 40301 | The model isn't enabled for your account. Some models require special access — contact [support](/support) to request it. |
| **NotFoundError**  
404 · 40401 | Model not found · voice not found · resource endpoint not found. Some cases return `50001` instead. |
| **ConcurrencyLimitError**  
429 · 42901 | Concurrent request limit for your plan exceeded — Free/no plan 1, Basic 2, Starter 5, Growth 10, Scale 20. See [Rate limits](/rate-limits). |
| **InternalError**  
5xx · 50001 | Internal server errors · external API failures · database connection issues · file storage failures · request timeouts · connection errors. Returned with status 500, 502, 503, or 504. |

## Handling errors

Check the HTTP status code in the response header and the `errorCode` field in the body, then take the matching action.

| Status | Action | Common fixes |
| --- | --- | --- |
| 400 | **Fix the request** | Provide all required fields · meet the text minimum (3 words, 10 characters) · keep parameter values in range · reduce payload size if exceeding limits. |
| 401 | **Verify your API key** | Include the `x-api-key` header · check the key hasn't expired · verify the key format · generate a new key if the current one was revoked. |
| 402 | **Recharge your balance** | Check your balance · add funds via the dashboard · enable auto-topup · verify the cost of the operation before making the request. |
| 403 | **Request model access** | Contact support@munsit.com · verify your plan includes the model · check the model ID is correct. |
| 404 | **Verify the resource exists** | Check the model ID, voice ID, or resource ID · verify the resource hasn't been deleted · make sure you're using the correct endpoint. |
| 429 | **Reduce concurrency or upgrade** | Wait for current requests to complete · reduce simultaneous calls · upgrade your plan · implement request queuing in your application. |
| 5xx | **Retry, then contact support** | Retry after a short delay (exponential backoff recommended) · check the error message for details · if it persists, email support@munsit.com with the error code and message, the request, and a timestamp. For external API errors, wait a few minutes and retry. |

## WebSocket errors

The two sockets report errors differently. For **text to speech**, errors arrive as JSON messages on the socket rather than HTTP responses.

```
{
  "type": "error",
  "message": "Error description"
}
```

| Cause | Message |
| --- | --- |
| **Missing authentication** | "x-api-key or Authorization header is required. Provide it in query string, headers, or initConnection message." |
| **Invalid message type** | 'Invalid message type. Expected "voice-request"' |

**Speech-to-Text streaming ([`/api/v1/listen`](/speech-to-text/streaming))** uses a structured `Error` event, followed by a close code.

```
{ "type": "Error", "code": 4002, "message": "Configure.endpointing must be 100..5000 ms", "recoverable": true }
```

`recoverable: false` always precedes a close with the matching code; `recoverable: true` means the session continues.

| Close code | Meaning |
| --- | --- |
| `1000` | Normal close after `CloseStream`. |
| `1008` | Policy rejection: authentication failed, concurrent-session limit reached, or insufficient wallet balance — the `Error` message says which. |
| `1011` | Internal error, or 12 s with no audio and no `KeepAlive`. |
| `4002` | Invalid connection parameters. |
| `4008` | Audio sent more than 60 s ahead of real time. |

## Best practices

Seven habits that keep error handling boring — in the good way.

| Practice | Why |
| --- | --- |
| **Implement retry logic** | For 500-level errors, use exponential backoff. |
| **Handle rate limits** | Monitor for 429 errors and implement request queuing. |
| **Validate inputs** | Prevent 400 errors by validating before sending requests. |
| **Monitor balance** | Check balance before making requests to avoid 402 errors. |
| **Cache API keys** | Store keys securely and handle expiration gracefully. |
| **Log errors** | Log all errors with context for debugging. |
| **User-friendly messages** | Map error codes to messages your users can act on. |

> Hit something not covered here? Email support@munsit.com, or see the Support page for what to include and check the status page for service updates.
