# Errors and limits

> The error format, status codes and error codes returned by the voicast API, and its rate, size and time limits.

Source: https://voicast.jp/en/docs/errors

## Error format

```json
{
  "error": "invalid_config",
  "message": "config に誤りがあります",
  "details": ["fields[0].key は英小文字・数字・_（先頭は英字）", "closing は空でない文字列"],
  "request_id": "req_…"
}
```

- Branch on `error` (the error code). `message` is a human-readable explanation, currently in Japanese, and its wording may change.
- On validation errors (422), `details` lists one entry per problem.
- `request_id` identifies the request. Every response, successful or not, also has it in `x-request-id`. Quote it when contacting support.

## Status codes

| HTTP | Meaning |
| --- | --- |
| 400 | The body is not JSON |
| 401 | The API key is missing, wrong or revoked |
| 402 | New calls are refused for billing reasons |
| 403 | Not allowed |
| 404 | Not found (including resources in another environment) |
| 409 | Conflicts with the current state (duplicate, in use and so on) |
| 422 | Invalid input |
| 429 | Rate limit exceeded |
| 500 | An internal error in voicast |
| 503 | An external service (payments, a connected provider, webhook delivery) is unreachable or not configured |

## Error codes

| HTTP | `error` | Meaning | What to do |
| --- | --- | --- | --- |
| 400 | `invalid_json` | The body is not a JSON object | Send a JSON object with `Content-Type: application/json` |
| 401 | `unauthorized` | The API key is missing, wrong or revoked | Check `Authorization: Bearer vk_…` |
| 402 | `balance_depleted` | The balance is zero or below (prepaid) | Top up, or turn on auto-recharge |
| 402 | `payment_overdue` | 14 days have passed since an invoice was due (invoice billing) | Pay the invoice (service resumes immediately) |
| 402 | `spending_cap_reached` | This month's estimate reached the spending cap (invoice billing) | Raise the cap in the dashboard |
| 403 | `forbidden` | Your role is not enough, or MCP was called from a browser | Ask an owner or admin for a higher role |
| 404 | `not_found` | No such ID, or it belongs to another environment | Check the ID with a list call; make sure you are not mixing test and live keys |
| 409 | `conflict` | A tenant with the same `external_id` exists | Use the existing tenant |
| 409 | `in_use` | Tenants still use this agent | Change their `agent_id` first |
| 409 | `tenant_disabled` | The tenant is disabled | Set `status: active` with `PATCH /v1/tenants/{id}` |
| 409 | `needs_reauth` | The connection is broken | Connect it again on the connect page |
| 422 | `invalid_request` | Invalid input | See `message` and `details` |
| 422 | `invalid_config` | Invalid agent or connection config | Fix the items in `details` |
| 422 | `no_agent` | No agent could be determined | Pass `agent_id` or set one on the tenant |
| 422 | `verify_failed` | The test call before saving a connection failed | Check the URL and API key |
| 422 | `connect_failed` | A connection could not be started (for example, an MCP server's metadata could not be read) | Check the URL and what the server supports |
| 429 | `rate_limited` | Rate limit exceeded | Wait a moment and retry |
| 500 | `internal` | An internal error | Wait a moment and retry. Contact us if it persists |
| 503 | `unavailable` | An external service is unreachable or not configured | Wait a moment and retry |

## When calls are refused

When new calls are refused for billing reasons (402), each channel sees it differently. Calls already in progress are never cut off.

| Channel | What you see |
| --- | --- |
| Web and apps | `POST /v1/sessions` returns 402. If the refusal starts between creating the session and connecting, the offer to `webrtc_url` returns 403 (this will become 402; treat both as "cannot connect") |
| Phone | The voice server closes the stream immediately and Twilio moves on to `action` or the next verb. No call record is created |

## Rate limits

| Applies to | Limit |
| --- | --- |
| The `/v1` API and MCP with an API key | 600 requests per minute per API key (counted together) |
| MCP (signed in) | 300 calls per minute per user |
| MCP client registration | 30 per hour per source address |
| Sign-in emails | 5 per hour per email address |

`/v1` responses carry `x-ratelimit-limit` (the per-minute limit), `x-ratelimit-remaining` and `x-ratelimit-reset` (end of the window, Unix seconds). Over the limit you get 429 `rate_limited` with `Retry-After` (seconds to wait); wait that long and retry (the [SDK](https://voicast.jp/en/docs/sdk.md) does this for you).

## Size and time limits

| Item | Limit |
| --- | --- |
| `client_token` (Web and apps) | 2 minutes, single use |
| Connect-page and webhook-portal links | 15 minutes |
| After rotating a connection secret or the tools signing secret | The old one keeps working for 24 hours |
| Tool responses | voicast waits 8 seconds; up to 4,000 characters of JSON reach the AI |
| Connection actions | Cut off after 3 seconds |
| Agents | 20 fields, 50 FAQ entries, 10 tools, 10 connections ([Agents](https://voicast.jp/en/docs/agents.md)) |
| `GET /v1/calls` | Up to 100 per page (default 50) |
| `GET /v1/usage` | Periods up to 366 days |
| Transcripts | Up to 500 turns, 2,000 characters each |
| Tenant `external_id` | 1–100 characters: letters, digits and `. _ : -` |
| Names (agents, tenants) | Up to 100 characters |
