> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.beatapi.io/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.beatapi.io/_mcp/server.

# 오류

> BeatAPI가 반환하는 모든 오류 코드와 HTTP 상태, 재시도 가능 여부, 발생 조건, 클라이언트가 취해야 할 조치를 정리합니다.

# 오류

BeatAPI는 모든 실패를 정해진 코드 중 하나로 알려 줍니다. `code` 또는 `retryable`로 분기하세요. `message`는 원인을 사람이 읽을 수 있게 설명한 영어 문장입니다. BeatAPI는 모델 뒤의 공급사를 밝히지 않으며 모델 측의 원본 응답 본문도 전달하지 않습니다. 유일한 예외는 텍스트 엔드포인트에서 모델이 반환하는 영어 입력 검증 문장으로, 입력을 고칠 수 있도록 그대로 전달합니다. 지원 요청을 위해 `request_id`를 보관하세요.

## 오류 객체

이미지·영상 작업, `GET /v1/tasks/{task_id}`, 기능, 워크플로, `/v1/systemone`(별칭 `/v1/decisions` 포함), `/v1/moderations`, `/v1/social-data/call`, `/v1/web/*` 등 BeatAPI의 모든 엔드포인트는 같은 형식으로 오류를 반환합니다.

```json
{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "Rate limit exceeded: at most 60 successful requests per 1 minute(s). Retry after 60 seconds.",
    "retryable": true,
    "request_id": "req_abc123",
    "retry_after_seconds": 60
  }
}
```

| 필드                    | 포함 조건                        | 의미                                                                                                                                                                         |
| --------------------- | ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `code`                | 항상                           | 아래 표의 코드입니다. 분기할 때는 이 값을 사용하세요.                                                                                                                                            |
| `message`             | 항상                           | 원인을 설명하는 영어 문장입니다. `bad_request`의 경우 해당 필드 이름이 들어갑니다. 사람과 로그를 위한 문장이므로 파싱하지 마세요.                                                                                           |
| `retryable`           | 아래 표의 모든 코드                  | 같은 호출이 나중에 성공할 수 있으면 `true`입니다(표의 모든 `429`, `500`, `503` 코드). 요청, 키 또는 잔액을 바꾸기 전까지 다시 실패하면 `false`입니다. `retryable`이 `false`인 호출은 절대 반복하지 마세요. 표에 없는 코드에서만 이 필드가 빠질 수 있습니다. |
| `request_id`          | 항상                           | 보관하세요. 지원팀이 이 값으로 호출을 찾습니다.                                                                                                                                                |
| `retry_after_seconds` | `429 rate_limit_exceeded`에서만 | 기다려야 할 초 단위 시간입니다. 같은 값이 `Retry-After` 헤더로도 전송됩니다. 다른 코드에는 포함되지 않습니다. `503`은 대기 시간을 알 수 없으므로 백오프를 적용해 재시도하세요.                                                              |

`POST /v1/chat/completions`, `POST /v1/responses`, `POST /v1/messages`는 모델을 호출하기 전의 실패에는 이 형식을 사용하고, 호출 중의 실패에는 각 SDK 고유의 오류 형식을 유지합니다. [텍스트 엔드포인트](#text-endpoints)를 참고하세요. Gemini 네이티브 엔드포인트(`/v1beta/...`)와 `GET /v1/models`는 이와 다른 더 단순한 형식을 사용하며, 같은 섹션에서 설명합니다.

`POST /v1/moderations`도 이 형식을 사용합니다. 이 엔드포인트에서는 오류 객체에 OpenAI의 `type`과 `param`도 포함되므로(`param`은 항상 `null`) OpenAI SDK가 평소와 같은 예외를 발생시킵니다. [콘텐츠 검수 API](/moderation)를 참고하세요.

## 실패가 나타나는 위치

작업은 두 시점에서 실패할 수 있으며, 각각 형태가 다릅니다.

1. **생성할 때.** 작업이 만들어지기 전에 요청이 거부됩니다. `error` 객체가 담긴 HTTP 오류를 받으며 `data.id`는 없습니다. 과금되지 않습니다.
2. **접수된 후.** `POST`가 `data.id`와 함께 `201`을 반환했고, 이후 작업이 `status: "failed"`로 끝납니다. `GET /v1/tasks/{task_id}`는 여전히 `200`을 반환하며, 실패 정보는 `data.error_code`, `data.error_message`, `data.retryable`에 있습니다. 작업을 위해 보류된 크레딧은 환불됩니다.

```json
{
  "error": {
    "code": "content_policy_violation",
    "message": "The request was blocked by content moderation. Please change the prompt or the input and try again.",
    "retryable": false,
    "request_id": "req_abc123"
  }
}
```

```json
{
  "data": {
    "id": "task_7Qm2Xc9LpR4vT8sKa1Nf6YbH3eWdJ0uZ",
    "status": "failed",
    "error_code": "content_policy_violation",
    "error_message": "The request was blocked by content moderation. Please change the prompt or the input and try again.",
    "retryable": false
  }
}
```

같은 실패는 두 위치 모두에서, 그리고 사용량 로그의 오류 줄(`content_policy_violation: The request was blocked…`)에서도 같은 코드를 갖습니다. 실패한 작업은 HTTP 오류가 아닙니다. `GET /v1/tasks/{task_id}`는 `status: "failed"`, `error_code`, `error_message`, `retryable`과 함께 `200`을 반환하고, 작업을 위해 보류된 크레딧은 환불됩니다. 실패한 작업에서 `usage.credits_reserved`는 생성 시 보류된 금액이고, `usage.credits_charged`와 `usage.credits_settled`는 `0`이며, `usage.credits_refunded`는 환불된 금액입니다.

접수된 작업은 다음 여섯 가지 코드 중 하나로만 끝날 수 있습니다. 나머지 코드는 요청 시점의 거부입니다.

| `error_code`               | 의미                                 | `retryable` |
| -------------------------- | ---------------------------------- | ----------- |
| `content_policy_violation` | 프롬프트, 입력 또는 결과가 콘텐츠 검수에서 거부되었습니다.  | `false`     |
| `bad_request`              | 모델이 파라미터를 거부했거나 가져올 수 없는 입력이 있습니다. | `false`     |
| `processing_unavailable`   | 모델을 사용할 수 없거나 처리 용량이 가득 찼습니다.      | `true`      |
| `processing_timeout`       | 처리 제한 시간 안에 작업이 끝나지 않아 중단되었습니다.    | `true`      |
| `processing_failed`        | BeatAPI 측의 다른 이유로 처리에 실패했습니다.      | `true`      |
| `result_transfer_failed`   | 결과는 생성되었지만 저장하지 못했습니다.             | `true`      |

시간 초과 정리 과정에서 실패 처리된 작업은 [웹훅](/webhooks) 이벤트를 보내지 않으므로 `GET /v1/tasks/{task_id}` 폴링을 계속하세요. 기준이 되는 정보는 폴링 결과입니다.

### 기능 실행

지연 실행된 기능이 실패하면 위의 공통 오류 형식(`code`, `message`, `retryable`, `request_id`)으로 응답하며, 상태 코드는 오류 코드에 따릅니다(`processing_*` 코드는 `503`). 이 실행은 과금되지 않습니다. 약 85초가 지나도 실행이 계속되면 대신 `status: "running"`과 함께 `202`를 반환합니다.

`operation: "result"`를 지정한 `POST /v1/capabilities/run`은 `request_id`로 저장된 결과를 읽습니다. 결과는 1시간 동안 보관됩니다. 저장된 결과가 없으면 `404 result_expired`(`retryable: false`)를 반환하므로 기능을 다시 실행하세요.

## 코드

| 코드                         | HTTP  | `retryable` | 발생 조건                                                                                                                                                           | 조치                                                                |
| -------------------------- | ----- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
| `bad_request`              | `400` | `false`     | JSON 형식이 잘못되었거나, 엔드포인트가 받지 않는 필드·값·조합(크기, 비율, 길이, 개수, 프롬프트 길이 등)이 있습니다. 메시지에 해당 필드가 표시됩니다. 다운로드할 수 없는 입력 URL이나 처리할 수 없는 파일도 여기에 해당합니다.                          | 지적된 필드를 수정하거나, 공개적으로 접근 가능한 HTTPS URL과 지원되는 형식을 사용하세요.            |
| `content_policy_violation` | `400` | `false`     | 프롬프트, 입력 또는 생성된 결과가 콘텐츠 검수에서 거부되었습니다.                                                                                                                           | 프롬프트나 입력을 바꾸세요. 같은 요청을 다시 보내지 마세요.                                |
| `missing_api_key`          | `401` | `false`     | API 키를 보내지 않았습니다.                                                                                                                                               | `Authorization: Bearer <key>`를 보내세요. 키는 `sk-` 접두사가 있어도 없어도 동작합니다. |
| `invalid_api_key`          | `401` | `false`     | 키가 잘못되었거나 만료, 비활성화, 소진되었습니다. 메시지에 원인이 표시됩니다. 삭제된 키는 즉시 실패합니다.                                                                                                   | 대시보드에서 활성 키를 확인하거나 다른 키로 바꾸세요.                                    |
| `unauthorized`             | `401` | `false`     | `401`의 이전 이름으로, 2026-09-29부터 `missing_api_key`와 `invalid_api_key`로 대체되었습니다. 아직 나타날 수 있습니다.                                                                      | `invalid_api_key`와 같이 처리하세요.                                      |
| `insufficient_credits`     | `402` | `false`     | 잔액 부족: 계정 잔액이 0이거나 이 요청의 가격보다 적습니다. 또는 키 자체의 지출 한도가 가격보다 낮은 경우로, 이때는 메시지에 그렇게 표시됩니다.                                                                            | 충전하거나 키의 한도를 올린 뒤 요청을 다시 보내세요.                                    |
| `forbidden`                | `403` | `false`     | 이 키나 계정으로는 이 호출을 할 수 없습니다. 예를 들어 무료 크레딧으로 쓸 수 없는 모델, 키의 IP 허용 목록 밖에서 보낸 요청, 키의 그룹에 속하지 않은 모델이 해당합니다.                                                            | 메시지를 확인하세요. 무료 크레딧 계정은 충전하면 모든 모델을 사용할 수 있습니다.                    |
| `not_found`                | `404` | `false`     | 텍스트·기능 엔드포인트에서 알 수 없거나 가격이 없는 모델, 알 수 없는 기능, 또는 이 계정에 존재하지 않는 작업입니다. 이미지·영상 작업 엔드포인트에서는 카탈로그에 없는 모델이 대신 `400 bad_request`로 반환됩니다(메시지에 카탈로그에 없다고 표시됨).           | ID와 키가 속한 계정을 확인하세요. 기능의 경우 `suggestions`를 사용하세요.                 |
| `result_expired`           | `404` | `false`     | `operation: "result"`를 지정한 `POST /v1/capabilities/run`에서, 해당 `request_id`에 저장된 결과가 없을 때만 반환됩니다. 결과는 1시간 동안 보관됩니다.                                               | 기능을 다시 실행하세요.                                                     |
| `idempotency_conflict`     | `409` | `false`     | `Idempotency-Key`를 다른 본문이나 경로에 재사용했거나, 이 키를 사용한 첫 요청이 아직 처리 중입니다.                                                                                               | 키는 완전히 같은 요청에만 재사용하세요.                                            |
| `rate_limit_exceeded`      | `429` | `true`      | 키가 너무 많은 요청을 보냈습니다(무료 모델 한도 포함). 텍스트 엔드포인트에서는 모델 자체의 처리 용량이 가득 찼다는 뜻일 수도 있습니다("This model is receiving too many requests").                                     | `Retry-After`에 표시된 시간(또는 `retry_after_seconds`초)만큼 기다린 뒤 재시도하세요.  |
| `internal_error`           | `500` | `true`      | 예상하지 못한 내부 오류입니다.                                                                                                                                               | 한 번 재시도하고, 계속되면 `request_id`와 함께 지원팀에 문의하세요.                      |
| `not_implemented`          | `501` | `false`     | 공개된 엔드포인트이지만 이 게이트웨이에서는 아직 제공하지 않습니다.                                                                                                                           | 재시도하지 말고 다른 엔드포인트를 사용하세요.                                         |
| `processing_unavailable`   | `503` | `true`      | BeatAPI 측에서 모델을 일시적으로 사용할 수 없거나 처리 용량이 가득 찼습니다. 파일 저장소를 일시적으로 사용할 수 없는 업로드도 해당합니다("File storage is temporarily unavailable. Retry later; nothing was stored."). | 나중에 백오프를 적용해 재시도하거나 다른 모델을 사용하세요.                                 |
| `processing_timeout`       | `503` | `true`      | 처리가 제시간에 끝나지 않았습니다.                                                                                                                                             | 백오프를 적용해 재시도하세요.                                                  |
| `processing_failed`        | `503` | `true`      | BeatAPI 측의 다른 이유로 처리에 실패했습니다.                                                                                                                                   | 백오프를 적용해 재시도하세요.                                                  |
| `result_transfer_failed`   | `503` | `true`      | 결과는 생성되었지만 저장하지 못했습니다. 파일을 저장하지 못한 업로드도 해당합니다("The file could not be stored on our side. Retry; nothing was stored.").                                          | 백오프를 적용해 재시도하세요.                                                  |

이미지·영상 작업 엔드포인트에서 본문이 너무 크면 `400 bad_request`("Request body is too large.")입니다. `413 read_request_body_failed`는 텍스트 엔드포인트에만 있으며 위 표에는 없습니다. 본문에 `retryable` 필드가 없습니다. 그대로 재시도해도 소용없으니 더 작은 본문을 보내세요. 아래를 참고하세요.

`processing_unavailable`과 `rate_limit_exceeded`는 서로 다릅니다. `rate_limit_exceeded`는 **사용자 측**의 요청 속도에 관한 것으로, 속도를 늦추라는 뜻입니다. `processing_unavailable`은 모델이 지금 작업을 받을 수 없다는 뜻이며, 요청 자체에는 문제가 없습니다.

BeatAPI는 `502`나 `504`를 반환하지 않습니다. 그래도 `502` 또는 `504`를 받았다면 BeatAPI에 연결할 수 없었던 네트워크 엣지에서 온 것이며, 본문은 JSON이 아닙니다. `503`처럼 백오프를 적용해 재시도하세요. 본문이 `error code: 1010`인 `403`도 마찬가지입니다. 엣지가 클라이언트의 기본 User-Agent(예: Python의 `urllib`)를 거부한 것이므로 `User-Agent`를 명시적으로 보내세요.

### Realtime 코드

이 코드는 [Realtime](/realtime-api) 세션에서만 나타납니다. 웹훅 서명 검증은 받은 콜백을 직접 확인하는 절차이며, BeatAPI는 이에 대한 오류 코드를 반환하지 않습니다([웹훅](/webhooks) 참고).

| 코드                              | HTTP  | `retryable` | 발생 조건                                                                     |
| ------------------------------- | ----- | ----------- | ------------------------------------------------------------------------- |
| `realtime_disabled`             | `503` | `false`     | 이 배포 환경에서는 Realtime Video가 활성화되어 있지 않습니다. 직접 처리할 방법은 없으니 지원팀에 문의하세요.      |
| `realtime_capacity_unavailable` | `503` | `true`      | Realtime 처리 용량을 일시적으로 사용할 수 없습니다. 잠시 후 백오프를 적용해 재시도하세요. 대기 시간은 안내되지 않습니다. |
| `realtime_session_expired`      | `410` | `false`     | 이 세션은 더 이상 사용할 수 없습니다. 새 세션을 만드세요.                                        |
| `origin_not_allowed`            | `403` | `false`     | 이 세션에서 허용되지 않은 브라우저 오리진입니다.                                               |
| `invalid_client_secret`         | `401` | `false`     | 세션의 클라이언트 시크릿이 유효하지 않거나 더 이상 사용할 수 없습니다.                                  |
| `transport_not_allowed`         | `400` | `false`     | 요청한 전송 방식이 허용되지 않습니다.                                                     |

## 텍스트 엔드포인트

`POST /v1/chat/completions`, `POST /v1/responses`, `POST /v1/messages`는 두 단계에서 실패할 수 있으며, 단계마다 본문 형식이 다릅니다.

**1. 모델을 호출하기 전.** 키가 없거나 유효하지 않은 경우, 무료 크레딧 제한, 키의 IP 허용 목록이나 그룹, 라우팅, 요청 속도 제한은 [BeatAPI 오류 형식](#the-error-object)으로 응답합니다. `code`, `message`, `retryable`, `request_id`가 포함되며 `429`에는 `retry_after_seconds`와 `Retry-After`도 포함됩니다. 이 단계에서 알 수 없는 모델은 `404 not_found`입니다. 키의 IP 허용 목록 밖에서 보낸 요청이나 키의 그룹에 속하지 않은 모델은 `403 forbidden`입니다. `/v1/chat/completions`, `/v1/responses`, `/v1/messages` 모두 같습니다.

**Gemini 네이티브 엔드포인트와 `GET /v1/models`.** `/v1beta/...`와 `GET /v1/models`는 BeatAPI 오류 형식을 사용하지 않습니다. 오류는 `{"error":{"message":"... (request id: ...)","type":"beatapi_error","code":...}}` 형태이며 `retryable`이나 `retry_after_seconds`가 없습니다. `429`에는 여전히 `Retry-After` 헤더가 포함됩니다.

**2. 호출 중.** OpenAI·Anthropic SDK가 파싱해 평소와 같은 예외를 발생시킬 수 있도록, 본문은 의도적으로 SDK 고유 형식을 유지합니다. `retryable` 필드는 없으므로 상태 코드와 오류 코드를 사용하세요. 이 단계에서는 모든 `message` 뒤에 요청 ID가 덧붙습니다. 여기서는 세 종류의 실패가 발생합니다.

* **게이트웨이가 직접 거부한 경우**에는 BeatAPI 코드(`insufficient_credits`, `content_policy_violation`, `bad_request`, `not_found`, `internal_error`)를 사용합니다.
* **모델 측 실패**는 `temporary_error`, `upstream_timeout`, `model_unavailable`, `rate_limit_exceeded` 중 하나의 코드와 함께 SDK 고유 형식으로 바꿔 반환하며, HTTP 상태는 유지합니다. 단, `502`와 `504`는 `503`이 됩니다. 공급사와 관련된 BeatAPI 계정 측 문제는 `503 model_unavailable`로 보고합니다.
* **모델이 반환한 영어 파라미터 오류**(예: 컨텍스트 길이 초과)는 입력을 고칠 수 있도록 문장 그대로 전달합니다.

OpenAI 형식(`/v1/chat/completions`, `/v1/responses`):

```json
{
  "error": {
    "message": "This API key's remaining quota is below the price of this request. Raise the key's quota in the console or use another key. (request id: req_abc123)",
    "type": "beatapi_error",
    "param": "",
    "code": "insufficient_credits"
  }
}
```

Anthropic 형식(`/v1/messages`):

```json
{
  "type": "error",
  "error": {
    "type": "insufficient_credits",
    "message": "This API key's remaining quota is below the price of this request. Raise the key's quota in the console or use another key. (request id: req_abc123)"
  }
}
```

게이트웨이가 직접 거부한 경우 OpenAI 형식에서는 `type`이 `beatapi_error`이고 BeatAPI 코드는 `error.code`에 들어갑니다. Anthropic 형식에서는 코드가 `error.type`에 들어갑니다.

| HTTP  | 코드                                                           | 조치                                                                                  |
| ----- | ------------------------------------------------------------ | ----------------------------------------------------------------------------------- |
| `400` | `bad_request` 또는 `content_policy_violation`                  | 요청이나 입력을 수정하세요. 그대로 다시 보내지 마세요. 모델의 영어 파라미터 문장(예: 컨텍스트 초과)은 `message`로 전달됩니다.       |
| `402` | `insufficient_credits`                                       | 충전하거나 키의 한도를 올리세요.                                                                  |
| `404` | `not_found`                                                  | 알 수 없는 모델입니다. `GET /v1/models`로 사용 가능한 모델 목록을 확인하세요.                                |
| `413` | `read_request_body_failed`                                   | 더 작은 본문을 보내세요. 이 코드에는 `retryable` 필드가 없습니다.                                         |
| `429` | `rate_limit_exceeded`                                        | 요청 한도에 도달했거나 모델의 처리 용량이 가득 찼습니다. 백오프를 적용해 재시도하세요. 이 단계에서는 `Retry-After`가 보장되지 않습니다. |
| `500` | `internal_error`(BeatAPI 측) 또는 `temporary_error`(모델 측)       | 백오프를 적용해 한두 번 재시도하세요.                                                               |
| `503` | `model_unavailable`, `upstream_timeout` 또는 `temporary_error` | 백오프를 적용해 재시도하거나 다른 모델을 사용하세요.                                                       |

## 재시도 정책

* **그대로 재시도하지 마세요**(`retryable: false`): `bad_request`, `content_policy_violation`, `missing_api_key`, `invalid_api_key`, `unauthorized`, `insufficient_credits`, `forbidden`, `not_found`, `result_expired`, `read_request_body_failed`, `idempotency_conflict`, `not_implemented`, `realtime_session_expired`. 즉 모든 `400`, `401`, `402`, `403`, `404`, `409`, `410`, `413`, `501`이 해당합니다. `read_request_body_failed`에는 `retryable` 필드가 없고 코드 표에도 없지만 `false`로 취급하세요.
* **기다린 뒤 재시도**(`retryable: true`): `rate_limit_exceeded`. `Retry-After` / `retry_after_seconds`를 따르세요.
* **백오프를 적용해 재시도**(`retryable: true`): `internal_error`와 네 가지 `503` 코드(`processing_unavailable`, `processing_timeout`, `processing_failed`, `result_transfer_failed`). Realtime `503` 코드는 다릅니다. `realtime_capacity_unavailable`은 재시도할 수 있고 `realtime_disabled`는 재시도할 수 없습니다. 지터를 넣은 지수 백오프와 상한을 사용하세요. 실패한 작업은 환불되었으므로, 새로운 시도는 성공할 때만 새로 과금됩니다. 작업 생성 시 `Idempotency-Key`를 보내면 제출을 재시도해도 두 번째 작업이 생기지 않습니다.

## 멱등성

`Idempotency-Key`는 작업 생성과 `POST /v1/capabilities/run`에서 선택 사항입니다.

* 키는 24시간 동안 기억됩니다.
* 255자를 넘는 키는 `400 bad_request`입니다.
* 같은 키를 다른 본문이나 경로에 사용하면 `409 idempotency_conflict`입니다. 첫 요청이 아직 처리 중일 때 같은 키를 사용해도 마찬가지입니다.
* 완전히 같은 요청을 반복하면 저장된 응답을 반환하고 `Idempotent-Replayed: true` 헤더를 추가합니다.
* `2xx` 응답만 저장됩니다. `400` 또는 `402` 이후에는 같은 키로 재시도할 수 있습니다.

## 결과

결과 URL은 `output.media[].url`에 반환됩니다. 보관해야 하는 결과는 직접 다운로드해 저장하세요.

## 변경 내역

* **2026-10-15** — 파일을 저장할 수 없는 업로드는 `503`(`processing_unavailable` 또는 `result_transfer_failed`)으로 응답하며 아무것도 저장되지 않습니다. 텍스트 호출 중 모델 측에서 실패하면 `temporary_error`, `upstream_timeout`, `model_unavailable`, `rate_limit_exceeded`와 함께 SDK 고유 형식으로 바꿔 반환하며, 이 단계의 모든 메시지 뒤에 요청 ID가 덧붙습니다.
* **2026-10-15** — 지연 실행된 기능이 실패하면 이제 `type: api_error`가 담긴 본문이 아니라 공통 오류 형식(`code`, `message`, `retryable`, `request_id`)과 해당 코드의 상태로 응답합니다. `retry_after_seconds`와 `Retry-After`는 `429 rate_limit_exceeded`에서만 보내며 `503`에서는 보내지 않습니다. `result_expired`와 `not_implemented`를 표에 추가했습니다. 게이트웨이가 실제로 반환한 적이 없는 `user_concurrency_exceeded`와 `invalid_signature`는 삭제했습니다. 실패한 작업에서 `usage.credits_charged`는 `0`이고 `usage.credits_refunded`는 환불된 금액입니다. 텍스트 엔드포인트에서는 모델 호출 전의 실패에 BeatAPI 오류 형식을 사용하고, 호출 중의 실패에는 SDK 고유 본문을 유지합니다.
* **2026-09-29** — 이제 `401`은 항상 `missing_api_key`(키를 보내지 않음) 또는 `invalid_api_key`(잘못되었거나 만료, 비활성화, 소진된 키, 메시지에 원인 표시)입니다. `unauthorized`는 두 경우의 이전 이름이며, 오래된 클라이언트에서 보이면 `invalid_api_key`처럼 처리하세요. 잔액 부족은 텍스트 엔드포인트를 포함한 모든 엔드포인트에서 항상 `402 insufficient_credits`입니다. `retryable`은 모든 오류에 포함되며, 모든 오류의 `message`는 원인을 설명하는 영어 문장입니다.
* **2026-09-25** — BeatAPI는 더 이상 `502`나 `504`를 직접 반환하지 않습니다. 완료하지 못한 동기식 소셜 데이터·웹 호출과 백그라운드에서 실패한 리서치 실행(환불됨)을 포함해 모든 처리 실패(`processing_unavailable`, `processing_timeout`, `processing_failed`, `result_transfer_failed`)는 JSON 오류 본문이 담긴 `503`입니다. 그래도 `502`를 받았다면 BeatAPI에 연결할 수 없었던 엣지에서 온 것이며 본문은 JSON이 아닙니다. 백오프를 적용해 재시도하세요.
* **2026-09-23** — 거부된 파라미터나 접근할 수 없는 입력 때문에 접수 후 실패한 작업은 이제 `bad_request`를 보고합니다(이전에는 `processing_failed`). 생성 시 모델 자체의 상태 코드는 더 이상 그대로 전달하지 않습니다. 콘텐츠 검수 거부는 항상 `400 content_policy_violation`이고, 모델을 사용할 수 없으면 `503 processing_unavailable`입니다. 생성 시 잔액이 부족하면 `402 insufficient_credits`입니다.