> 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.

# Gemini Messages

POST https://direct.beatapi.io/v1/messages
Content-Type: application/json

BeatAPI 키 하나로 Anthropic Messages 형식에서 Gemini 4 Argon, Gemini 4 Carbon, Gemini 3.8 Flash, Gemini 3.1 Pro를 호출합니다.- 현재 모든 Gemini 모델이 엔드포인트 `POST /v1/messages` 하나를 사용합니다. `model`만 바꿔 전환하세요.
- 스트리밍과 도구 사용. `gemini-4-argon`은 이미지와 긴 영상도 이해합니다.
- Anthropic SDK와 호환됩니다. 기본 URL을 바꾸고 BeatAPI 키를 사용하세요. 모든 요청에 `anthropic-version` 헤더를 보내세요.
- `tool_choice`는 모델에 전달되지만 모든 모델이 적용하지는 않으며, `thinking`은 효과가 없습니다. 아래 파라미터 레퍼런스를 참고하세요.텍스트 요청의 기본 URL로는 `https://direct.beatapi.io`를 사용하세요. Cloudflare의 100초 제한을 받지 않으므로 스트리밍하지 않는 긴 요청도 끊기지 않습니다. `https://api.beatapi.io`도 동작하며, 네트워크에서 `direct.beatapi.io`에 접근할 수 없을 때의 대안입니다. 키, 모델, 가격은 양쪽이 같습니다. 이미지와 영상 API는 `https://api.beatapi.io`만 사용합니다.POST/v1/messages실행해 보기API Explorer에서 이 엔드포인트를 엽니다. BeatAPI API 키를 입력하고 전송하세요. 실제 호출이며 본인 잔액에서 과금됩니다.## 모델`model`에 다음 ID 중 하나를 보내세요. 각각 별개의 모델이며, 서로의 별칭으로 취급하지 마세요.| 모델 ID                    | 컨텍스트(토큰)  | 최대 출력(토큰) | 포지셔닝                                                                      | 입력, 1M 토큰당 USD | 출력, 1M 토큰당 USD | 참고                                                                                                                                                                       |
| ------------------------ | --------- | --------- | ------------------------------------------------------------------------- | -------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `gemini-4-argon`         | —         | 1,000,000 | 최대 1M 토큰까지 출력할 수 있는 Google의 Gemini 4 플래그십 모델.                             | \$1.00         | \$5.00         | 이미지와 긴 영상을 이해합니다. 출력은 최대 1,000,000토큰입니다. 충전된 계정이 필요하며 가입 크레딧은 적용되지 않습니다.                                                                                                 |
| `gemini-4-carbon`        | —         | 1,000,000 | 복잡한 디버깅, 과학적 분석, 에이전트를 위한 Gemini 4 추론 모델                                  | \$1.00         | \$5.00         | 추론, 도구, 이미지 입력을 지원합니다. 카탈로그의 최대 출력은 1,000,000 토큰이지만 단일 동기 응답을 보장하지는 않습니다. 기본 네이티브 출력 예산은 추론을 포함해 65,536 토큰이며, 긴 출력에는 이어서 생성하는 처리가 필요합니다. 충전된 계정이 필요하며 가입 크레딧은 적용되지 않습니다. |
| `gemini-3.8-flash`       | —         | —         | 장기 소프트웨어 엔지니어링, 자율 에이전트, 복잡한 엔터프라이즈 워크플로를 위해 설계된 Google의 가장 지능적인 Flash 모델 | \$0.375        | \$1.875        | 장기 소프트웨어 엔지니어링, 에이전트, 복잡한 엔터프라이즈 워크플로를 위한 Flash 등급.                                                                                                                      |
| `gemini-3.1-pro-preview` | 1,048,576 | 65,536    | 에이전트 코딩과 복잡한 문제 해결을 위한 추론 중심 Gemini 프리뷰                                   | \$1.00         | \$6.00         | 에이전트 코딩과 복잡한 문제 해결을 위한 추론 중심 프리뷰. 1,048,576토큰 컨텍스트, 최대 65,536출력 토큰.                                                                                                      |- 가격은 할인이 적용된 기본 등급입니다. 롱 컨텍스트 등급, 캐시 입력 요금, 캐시 쓰기는 이 표에 없습니다. [가격표](https://beatapi.io/pricing)를 참고하세요.
- `—`는 카탈로그에서 해당 수치를 공개하지 않는다는 뜻입니다.이 계열의 이전 ID도 계속 동작하며 [레거시 모델](/text-api/legacy-models)에 나와 있습니다.## 빠른 시작서버에 `@anthropic-ai/sdk` 또는 `anthropic` 패키지를 설치하고 키는 `BEATAPI_API_KEY`에 보관하세요. 브라우저 코드에는 절대 넣지 마세요. SDK가 `anthropic-version` 헤더를 자동으로 보냅니다. 아래는 요청 예시이며 실제로 기록된 모델 출력이 아닙니다.`content`의 `text` 블록에서 답변을 읽은 다음 `stop_reason`과 `usage`를 확인하세요. HTTP 200만으로는 답변이 작업 요구를 충족한다고 볼 수 없으니 애플리케이션에서 검증하세요. 텍스트 요청은 바로 반환되므로 `/v1/tasks`를 폴링하지 마세요.```bash title="cURL"
curl --request POST \
  --url https://direct.beatapi.io/v1/messages \
  --header "x-api-key: $BEATAPI_API_KEY" \
  --header 'anthropic-version: 2023-06-01' \
  --header 'Content-Type: application/json' \
  --data '{
  "model": "gemini-3.8-flash",
  "max_tokens": 2000,
  "messages": [
    {
      "role": "user",
      "content": "Design a resilient webhook retry strategy for a payments API."
    }
  ]
}'
``````python title="Python"
import os
from anthropic import Anthropic

client = Anthropic(api_key=os.environ["BEATAPI_API_KEY"], base_url="https://direct.beatapi.io")
message = client.messages.create(
    model="gemini-3.8-flash",
    max_tokens=2000,
    messages=[
      {
        "role": "user",
        "content": "Design a resilient webhook retry strategy for a payments API."
      }
    ],
)
print(message.content[0].text)
``````javascript title="JavaScript"
import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic({ apiKey: process.env.BEATAPI_API_KEY, baseURL: "https://direct.beatapi.io" });
const message = await client.messages.create({
  "model": "gemini-3.8-flash",
  "max_tokens": 2000,
  "messages": [
    {
      "role": "user",
      "content": "Design a resilient webhook retry strategy for a payments API."
    }
  ]
});
console.log(message.content[0].text);
```## 엔드포인트와 인증`POST https://direct.beatapi.io/v1/messages`x-api-key
string
필수BeatAPI 키입니다. `Authorization: Bearer <BEATAPI_API_KEY>`도 받습니다.모든 요청에 `anthropic-version` 헤더(예: `2023-06-01`)를 보내세요. Anthropic SDK는 자동으로 추가합니다. 인증에는 `x-api-key`와 `Authorization: Bearer <BEATAPI_API_KEY>` 모두 사용할 수 있습니다.## 요청 파라미터요청은 Anthropic Messages 형식을 사용합니다. 아래 레퍼런스에서 각 필드의 동작을 설명합니다. `thinking`은 받지만 결과에 영향을 주지 않습니다. 이 페이지에 없는 필드는 효과가 있다고 보장하지 않습니다.model
string
필수정확한 모델 ID입니다.**허용 값**: `gemini-4-argon`, `gemini-4-carbon`, `gemini-3.8-flash`, `gemini-3.1-pro-preview`- 각 ID는 별개의 모델이며 다른 모델의 별칭이 아닙니다.
- 키로 `GET /v1/models`를 호출해 사용 가능한 모델을 확인하세요.
- 이전 ID `gemini-3.6-flash`와 `gemini-3.7-flash`도 계속 동작하며 [레거시 모델](/text-api/legacy-models)에 나와 있습니다.max_tokens
integer
필수생성 토큰의 상한이며, 추론 토큰을 포함합니다.- 게이트웨이는 이 값을 위 표에 있는 모델의 최대 출력과 비교하지 않습니다. 그 값 이하로 설정하세요.
- `max_tokens`는 요청에 필요한 잔액을 추정하는 데도 쓰입니다. 실제 출력이 작더라도 값이 너무 크면 `402 insufficient_credits`로 거부될 수 있습니다. 필요한 만큼만 설정하세요.추론 모델은 추론을 먼저 작성합니다. `max_tokens`가 너무 작으면 추론이 한도를 모두 써 버려 `text` 블록이 비고 `stop_reason`이 `max_tokens`가 됩니다. 둘 다 담을 여유를 두고, `max_tokens`가 보이면 값을 높이세요.messages
object[]
필수대화 내용이며 오래된 메시지부터 나열합니다. 각 메시지에는 `role`(`user` 또는 `assistant`)와 `content`(문자열 또는 블록 배열)가 있습니다.- 텍스트 블록(`text`), 모델의 도구 요청(`tool_use`), 사용자가 보내는 결과(`tool_result`)가 적용됩니다.
- `tool_result` 블록에는 답하는 대상인 `tool_use` 블록의 `tool_use_id`가 있어야 합니다.system
string | object[]
선택시스템 프롬프트입니다. 문자열 또는 텍스트 블록 배열이며, 텍스트 블록은 하나의 시스템 프롬프트로 합쳐집니다.stream
boolean
선택기본값: false답변을 서버 전송 이벤트로 반환합니다. 아래 스트리밍 섹션을 참고하세요.**기본값**: `false`temperature
number
선택샘플링 온도입니다. 이 값이나 `top_p` 중 하나만 바꾸세요.top_p
number
선택누클리어스 샘플링 임계값입니다.stop_sequences
string[]
선택생성을 멈추는 시퀀스입니다.tools
object[]
선택모델이 호출할 수 있는 도구 정의입니다. 각 도구는 `name`, `description`, `input_schema`로 적용됩니다. 모델은 `tool_use` 블록으로 답하며, 결과는 다음 `user` 메시지의 `tool_result` 블록으로 반환하세요.tool_choice
object
선택모델이 `tools`를 사용하는 방식입니다. `{"type": "auto"}`는 모델이 판단하고(기본값), `{"type": "any"}`는 도구 중 하나를 호출하게 하며, `{"type": "tool", "name": "..."}`는 해당 도구를 호출하게 하고, `{"type": "none"}`은 도구를 호출하지 못하게 합니다. `disable_parallel_tool_use: true`는 답변당 호출을 하나로 제한합니다. `tools`가 없으면 무시됩니다. 이 설정은 모델에 전달되지만 모든 모델이 적용하지는 않습니다. 테스트(2026-10-15)에서 DeepSeek는 무시했고 Qwen은 `any`는 적용했지만 특정 도구 지정은 적용하지 않았으므로, `tool_use` 블록이 있다고 가정하지 말고 답변을 확인하세요.thinking
object
선택효과가 없습니다. 추론을 켜거나 끄지 않으며 추론 예산도 정하지 않습니다. 기본적으로 추론하는 모델은 계속 추론하며, 추론 내용은 `thinking` 블록으로 반환됩니다.## 응답스트리밍하지 않는 호출은 JSON 객체 하나를 반환합니다. 아래는 축약한 예시입니다.```json
{
  "id": "msg_example",
  "type": "message",
  "role": "assistant",
  "model": "gemini-3.8-flash",
  "content": [
    {
      "type": "text",
      "text": "Retry with exponential backoff and jitter, and make every handler idempotent."
    }
  ],
  "stop_reason": "end_turn",
  "stop_sequence": null,
  "usage": {
    "input_tokens": 19,
    "output_tokens": 16
  }
}
```### 응답 필드| 필드               | 타입         | 설명                                                                                                         |
| ---------------- | ---------- | ---------------------------------------------------------------------------------------------------------- |
| `id`             | `string`   | 메시지 ID입니다. 지원과 과금 감사를 위해 요청 ID와 함께 기록하세요.                                                                  |
| `model`          | `string`   | 응답한 모델입니다.                                                                                                 |
| `content[]`      | `object[]` | 콘텐츠 블록: `thinking`(추론하는 모델에서 답변 앞), `text`, `tool_use`.                                                    |
| `content[].text` | `string`   | `text` 블록의 답변 텍스트입니다.                                                                                      |
| `stop_reason`    | `string`   | 완전한 답변이면 `end_turn`, 도구 요청이면 `tool_use`, `max_tokens`에 도달하면 `max_tokens`, 중지 시퀀스와 일치하면 `stop_sequence`입니다. |
| `usage`          | `object`   | `input_tokens`와 `output_tokens`. 추론은 출력으로 계산됩니다. 호출은 실제 토큰 사용량으로 계량됩니다.                                    |## 스트리밍`"stream": true`를 설정하세요. 스트림은 `message_start`로 시작해 `message_stop`으로 끝납니다. 그 사이의 블록은 `content_block_start`, `content_block_delta`, `content_block_stop` 이벤트로 도착하며, `message_delta`에 `stop_reason`이 담겨 있습니다.- 응답은 `text/event-stream`이며, 스트리밍하지 않으면 `application/json`입니다.
- 텍스트는 `text_delta` 이벤트로 도착합니다. 추론 모델은 텍스트 블록 앞에 `thinking_delta` 이벤트가 있는 `thinking` 블록을 보냅니다. 도구 인수는 `input_json_delta` 이벤트로 도착합니다.
- 모델 호출 전에 발생한 실패는 스트림 이벤트가 아니라 HTTP 상태와 함께 일반 JSON 오류로 반환됩니다.
- 명시적인 시간 제한을 설정하고, 스트리밍 응답은 안전하게 다시 연결하세요.```text
event: message_start
data: {"type":"message_start","message":{"id":"msg_example","type":"message","role":"assistant","content":[],"usage":{"input_tokens":19,"output_tokens":1}}}

event: content_block_start
data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}}

event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Retry"}}

event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" with backoff"}}

event: content_block_stop
data: {"type":"content_block_stop","index":0}

event: message_delta
data: {"type":"message_delta","delta":{"stop_reason":"end_turn"},"usage":{"output_tokens":16}}

event: message_stop
data: {"type":"message_stop"}
```## 오류| 오류 또는 증상                                      | 원인                                                 | 해결 방법                                             |
| --------------------------------------------- | -------------------------------------------------- | ------------------------------------------------- |
| `text` 블록이 비어 있고 `stop_reason`이 `max_tokens`임 | 추론 모델이 `max_tokens` 예산을 추론에 모두 썼습니다.               | 모델의 최대 출력 범위 안에서 `max_tokens`를 높이세요.              |
| `402 insufficient_credits`                    | 잔액이 요청 가격보다 적습니다. 대개 `max_tokens`가 너무 크기 때문입니다.    | 충전하거나 `max_tokens`를 낮추세요.                         |
| `403 forbidden`                               | 계정이 무료 크레딧 상태인데 모델이 무료 목록에 없거나, 모델이 키의 그룹 밖에 있습니다. | 충전하거나, 무료 모델을 쓰거나, 그룹에서 해당 모델에 접근할 수 있는 키를 사용하세요. |
| `404 not_found`                               | 알 수 없는 모델 ID이거나 이 키에서 사용할 수 없습니다.                  | `GET /v1/models`로 사용 가능한 모델을 확인하세요.               |
| `429 rate_limit_exceeded`                     | 계정 또는 무료 모델 한도에 도달했습니다.                            | `Retry-After`만큼 기다린 뒤 재시도하세요.                     |### HTTP 오류 요약인증, 라우팅, 요청 속도 제한, 알 수 없는 모델 실패는 모델 호출 전에 BeatAPI 오류 형식(`error.code`, `error.message`, `retryable`, `request_id`)으로 응답합니다. 그 밖의 모든 실패는 Anthropic 형식 `{"type": "error", "error": {"type", "message"}}`를 유지하며, 코드는 `error.type`에 있고 요청 id는 `message`로 끝납니다. [오류](/errors#text-endpoints)를 참고하세요.| HTTP 상태 | 코드                                                         | 조치                                                             |
| ------- | ---------------------------------------------------------- | -------------------------------------------------------------- |
| 400     | `bad_request`, `content_policy_violation`                  | 요청이나 입력을 수정하세요. 그대로 다시 보내지 마세요.                                |
| 401     | `missing_api_key`, `invalid_api_key`                       | 키를 확인하세요. 재시도하지 마세요.                                           |
| 402     | `insufficient_credits`                                     | 충전하거나 키 한도를 높이세요. `max_tokens`가 너무 크면 발생할 수 있습니다.              |
| 403     | `forbidden`                                                | 모델이 키의 그룹이나 IP 허용 목록 밖에 있거나, 무료 크레딧으로 이 모델을 호출할 수 없습니다.        |
| 404     | `not_found`                                                | 알 수 없는 모델입니다. `GET /v1/models`로 사용 가능한 모델 목록을 확인하세요.           |
| 429     | `rate_limit_exceeded`                                      | `Retry-After` 또는 `retry_after_seconds`만큼 기다린 뒤 백오프를 두고 재시도하세요. |
| 500     | `internal_error`, `temporary_error`                        | 백오프를 적용해 한두 번 재시도하세요.                                          |
| 503     | `model_unavailable`, `upstream_timeout`, `temporary_error` | 백오프를 적용해 재시도하거나 다른 모델을 사용하세요.                                  |전체 코드 표와 재시도 정책: [오류](/errors#text-endpoints).## 참고- Gemini 모델은 [Chat Completions](/text-api/gemini/chat-completions), [OpenAI Responses](/text-api/gemini/responses), [Gemini 네이티브](/text-api/gemini/native)에서도 응답합니다.
- Gemini 모델은 기본적으로 추론하며 사고 토큰을 출력으로 과금하므로, `max_tokens`는 답변뿐 아니라 사고까지 고려해 잡으세요.
- 캐시 입력은 더 낮은 요금으로 과금됩니다. `gemini-4-argon`과 `gemini-4-carbon`은 입력 가격의 1/20, `gemini-3.8-flash`와 `gemini-3.1-pro-preview`는 1/10입니다. 별도의 캐시 저장 요금은 없습니다. 캐시 적중을 가정하지 말고 `usage`의 캐시 입력 수를 확인하세요. `gemini-3.1-pro-preview` 프롬프트가 200,000토큰을 넘으면 요청 전체에 상위 등급 요금이 적용됩니다. [가격표](https://beatapi.io/pricing)를 참고하세요.
- 모든 요청에 `anthropic-version`을 보내세요. `thinking`에 의존하지 마세요. 효과가 없습니다.
- API 키는 신뢰할 수 있는 서버에 두고, 응답의 요청 ID를 기록하며, `429`, `500`, `503`만 재시도하세요.

Reference: https://docs.beatapi.io/api-reference/text-api/gemini-messages

## Authentication

- `Authorization` header (bearer token, required) — API 키를 `Authorization: Bearer <BEATAPI_API_KEY>`로 보내세요.

## Servers

- `https://direct.beatapi.io` (Direct, default)
- `https://api.beatapi.io` (API)

## Request

### Body (application/json)

This endpoint expects an object.

- `model` (enum, required) — 정확한 모델 ID입니다. 각 ID는 별개의 모델이며 다른 모델의 별칭이 아닙니다. 키로 `GET /v1/models`를 호출해 사용 가능한 모델을 확인하세요. 이전 ID `gemini-3.6-flash`와 `gemini-3.7-flash`도 계속 동작하며 [레거시 모델](/text-api/legacy-models)에 나와 있습니다. `gemini-4-argon`, `gemini-4-carbon`, `gemini-3.8-flash`, `gemini-3.1-pro-preview`
  - Allowed values: `gemini-4-argon`, `gemini-4-carbon`, `gemini-3.8-flash`, `gemini-3.1-pro-preview`
- `max_tokens` (integer, required) — 생성 토큰의 상한이며, 추론 토큰을 포함합니다. 게이트웨이는 이 값을 위 표에 있는 모델의 최대 출력과 비교하지 않습니다. 그 값 이하로 설정하세요. `max_tokens`는 요청에 필요한 잔액을 추정하는 데도 쓰입니다. 실제 출력이 작더라도 값이 너무 크면 `402 insufficient_credits`로 거부될 수 있습니다. 필요한 만큼만 설정하세요. 추론 모델은 추론을 먼저 작성합니다. `max_tokens`가 너무 작으면 추론이 한도를 모두 써 버려 `text` 블록이 비고 `stop_reason`이 `max_tokens`가 됩니다. 둘 다 담을 여유를 두고, `max_tokens`가 보이면 값을 높이세요.
- `messages` (list of V1MessagesPostRequestBodyContentApplicationJsonSchemaMessagesItems, required) — 대화 내용이며 오래된 메시지부터 나열합니다. 각 메시지에는 `role`(`user` 또는 `assistant`)와 `content`(문자열 또는 블록 배열)가 있습니다. 텍스트 블록(`text`), 모델의 도구 요청(`tool_use`), 사용자가 보내는 결과(`tool_result`)가 적용됩니다. `tool_result` 블록에는 답하는 대상인 `tool_use` 블록의 `tool_use_id`가 있어야 합니다.
- `system` (V1MessagesPostRequestBodyContentApplicationJsonSchemaSystem, optional) — 시스템 프롬프트입니다. 문자열 또는 텍스트 블록 배열이며, 텍스트 블록은 하나의 시스템 프롬프트로 합쳐집니다.
- `stream` (boolean, optional, default: false) — 답변을 서버 전송 이벤트로 반환합니다. 아래 스트리밍 섹션을 참고하세요.
- `temperature` (double, optional) — 샘플링 온도입니다. 이 값이나 `top_p` 중 하나만 바꾸세요.
- `top_p` (double, optional) — 누클리어스 샘플링 임계값입니다.
- `stop_sequences` (list of string, optional) — 생성을 멈추는 시퀀스입니다.
- `tools` (list of V1MessagesPostRequestBodyContentApplicationJsonSchemaToolsItems, optional) — 모델이 호출할 수 있는 도구 정의입니다. 각 도구는 `name`, `description`, `input_schema`로 적용됩니다. 모델은 `tool_use` 블록으로 답하며, 결과는 다음 `user` 메시지의 `tool_result` 블록으로 반환하세요.
- `tool_choice` (V1MessagesPostRequestBodyContentApplicationJsonSchemaToolChoice, optional) — 모델이 `tools`를 사용하는 방식입니다. `{"type": "auto"}`는 모델이 판단하고(기본값), `{"type": "any"}`는 도구 중 하나를 호출하게 하며, `{"type": "tool", "name": "..."}`는 해당 도구를 호출하게 하고, `{"type": "none"}`은 도구를 호출하지 못하게 합니다. `disable_parallel_tool_use: true`는 답변당 호출을 하나로 제한합니다. `tools`가 없으면 무시됩니다. 이 설정은 모델에 전달되지만 모든 모델이 적용하지는 않습니다. 테스트(2026-10-15)에서 DeepSeek는 무시했고 Qwen은 `any`는 적용했지만 특정 도구 지정은 적용하지 않았으므로, `tool_use` 블록이 있다고 가정하지 말고 답변을 확인하세요.
- `thinking` (V1MessagesPostRequestBodyContentApplicationJsonSchemaThinking, optional) — 효과가 없습니다. 추론을 켜거나 끄지 않으며 추론 예산도 정하지 않습니다. 기본적으로 추론하는 모델은 계속 추론하며, 추론 내용은 `thinking` 블록으로 반환됩니다.

## Response

### 200

스트리밍하지 않는 호출은 JSON 객체 하나를 반환합니다. 아래는 축약한 예시입니다.

- `id` (string, optional) — 메시지 ID입니다. 지원과 과금 감사를 위해 요청 ID와 함께 기록하세요.
- `model` (string, optional) — 응답한 모델입니다.
- `content` (list of V1MessagesPostResponsesContentApplicationJsonSchemaContentItems, optional) — 콘텐츠 블록: `thinking`(추론하는 모델에서 답변 앞), `text`, `tool_use`.
- `stop_reason` (string, optional) — 완전한 답변이면 `end_turn`, 도구 요청이면 `tool_use`, `max_tokens`에 도달하면 `max_tokens`, 중지 시퀀스와 일치하면 `stop_sequence`입니다.
- `usage` (V1MessagesPostResponsesContentApplicationJsonSchemaUsage, optional) — `input_tokens`와 `output_tokens`. 추론은 출력으로 계산됩니다. 호출은 실제 토큰 사용량으로 계량됩니다.

## Errors

### 400 Bad Request Error

`bad_request`, `content_policy_violation` 요청이나 입력을 수정하세요. 그대로 다시 보내지 마세요. 인증, 라우팅, 요청 속도 제한, 알 수 없는 모델 실패는 모델 호출 전에 BeatAPI 오류 형식(`error.code`, `error.message`, `retryable`, `request_id`)으로 응답합니다. 그 밖의 모든 실패는 Anthropic 형식 `{"type": "error", "error": {"type", "message"}}`를 유지하며, 코드는 `error.type`에 있고 요청 id는 `message`로 끝납니다. [오류](/errors#text-endpoints)를 참고하세요.

- `map from string to any`

### 401 Unauthorized Error

`missing_api_key`, `invalid_api_key` 키를 확인하세요. 재시도하지 마세요. 인증, 라우팅, 요청 속도 제한, 알 수 없는 모델 실패는 모델 호출 전에 BeatAPI 오류 형식(`error.code`, `error.message`, `retryable`, `request_id`)으로 응답합니다. 그 밖의 모든 실패는 Anthropic 형식 `{"type": "error", "error": {"type", "message"}}`를 유지하며, 코드는 `error.type`에 있고 요청 id는 `message`로 끝납니다. [오류](/errors#text-endpoints)를 참고하세요.

- `map from string to any`

### 402 Payment Required Error

`insufficient_credits` 충전하거나 키 한도를 높이세요. `max_tokens`가 너무 크면 발생할 수 있습니다. 인증, 라우팅, 요청 속도 제한, 알 수 없는 모델 실패는 모델 호출 전에 BeatAPI 오류 형식(`error.code`, `error.message`, `retryable`, `request_id`)으로 응답합니다. 그 밖의 모든 실패는 Anthropic 형식 `{"type": "error", "error": {"type", "message"}}`를 유지하며, 코드는 `error.type`에 있고 요청 id는 `message`로 끝납니다. [오류](/errors#text-endpoints)를 참고하세요.

- `map from string to any`

### 403 Forbidden Error

`forbidden` 모델이 키의 그룹이나 IP 허용 목록 밖에 있거나, 무료 크레딧으로 이 모델을 호출할 수 없습니다. 인증, 라우팅, 요청 속도 제한, 알 수 없는 모델 실패는 모델 호출 전에 BeatAPI 오류 형식(`error.code`, `error.message`, `retryable`, `request_id`)으로 응답합니다. 그 밖의 모든 실패는 Anthropic 형식 `{"type": "error", "error": {"type", "message"}}`를 유지하며, 코드는 `error.type`에 있고 요청 id는 `message`로 끝납니다. [오류](/errors#text-endpoints)를 참고하세요.

- `map from string to any`

### 404 Not Found Error

`not_found` 알 수 없는 모델입니다. `GET /v1/models`로 사용 가능한 모델 목록을 확인하세요. 인증, 라우팅, 요청 속도 제한, 알 수 없는 모델 실패는 모델 호출 전에 BeatAPI 오류 형식(`error.code`, `error.message`, `retryable`, `request_id`)으로 응답합니다. 그 밖의 모든 실패는 Anthropic 형식 `{"type": "error", "error": {"type", "message"}}`를 유지하며, 코드는 `error.type`에 있고 요청 id는 `message`로 끝납니다. [오류](/errors#text-endpoints)를 참고하세요.

- `map from string to any`

### 429 Too Many Requests Error

`rate_limit_exceeded` `Retry-After` 또는 `retry_after_seconds`만큼 기다린 뒤 백오프를 두고 재시도하세요. 인증, 라우팅, 요청 속도 제한, 알 수 없는 모델 실패는 모델 호출 전에 BeatAPI 오류 형식(`error.code`, `error.message`, `retryable`, `request_id`)으로 응답합니다. 그 밖의 모든 실패는 Anthropic 형식 `{"type": "error", "error": {"type", "message"}}`를 유지하며, 코드는 `error.type`에 있고 요청 id는 `message`로 끝납니다. [오류](/errors#text-endpoints)를 참고하세요.

- `map from string to any`

### 500 Internal Server Error

`internal_error`, `temporary_error` 백오프를 적용해 한두 번 재시도하세요. 인증, 라우팅, 요청 속도 제한, 알 수 없는 모델 실패는 모델 호출 전에 BeatAPI 오류 형식(`error.code`, `error.message`, `retryable`, `request_id`)으로 응답합니다. 그 밖의 모든 실패는 Anthropic 형식 `{"type": "error", "error": {"type", "message"}}`를 유지하며, 코드는 `error.type`에 있고 요청 id는 `message`로 끝납니다. [오류](/errors#text-endpoints)를 참고하세요.

- `map from string to any`

### 503 Service Unavailable Error

`model_unavailable`, `upstream_timeout`, `temporary_error` 백오프를 적용해 재시도하거나 다른 모델을 사용하세요. 인증, 라우팅, 요청 속도 제한, 알 수 없는 모델 실패는 모델 호출 전에 BeatAPI 오류 형식(`error.code`, `error.message`, `retryable`, `request_id`)으로 응답합니다. 그 밖의 모든 실패는 Anthropic 형식 `{"type": "error", "error": {"type", "message"}}`를 유지하며, 코드는 `error.type`에 있고 요청 id는 `message`로 끝납니다. [오류](/errors#text-endpoints)를 참고하세요.

- `map from string to any`

## Types

### V1MessagesPostRequestBodyContentApplicationJsonSchemaMessagesItems

- `role` (string, required)
- `content` (V1MessagesPostRequestBodyContentApplicationJsonSchemaMessagesItemsContent, required)

### V1MessagesPostRequestBodyContentApplicationJsonSchemaSystem

시스템 프롬프트입니다. 문자열 또는 텍스트 블록 배열이며, 텍스트 블록은 하나의 시스템 프롬프트로 합쳐집니다.

- string
- list of V1MessagesPostRequestBodyContentApplicationJsonSchemaSystemOneOf1Items

### V1MessagesPostRequestBodyContentApplicationJsonSchemaToolsItems

### V1MessagesPostRequestBodyContentApplicationJsonSchemaToolChoice

모델이 `tools`를 사용하는 방식입니다. `{"type": "auto"}`는 모델이 판단하고(기본값), `{"type": "any"}`는 도구 중 하나를 호출하게 하며, `{"type": "tool", "name": "..."}`는 해당 도구를 호출하게 하고, `{"type": "none"}`은 도구를 호출하지 못하게 합니다. `disable_parallel_tool_use: true`는 답변당 호출을 하나로 제한합니다. `tools`가 없으면 무시됩니다. 이 설정은 모델에 전달되지만 모든 모델이 적용하지는 않습니다. 테스트(2026-10-15)에서 DeepSeek는 무시했고 Qwen은 `any`는 적용했지만 특정 도구 지정은 적용하지 않았으므로, `tool_use` 블록이 있다고 가정하지 말고 답변을 확인하세요.

### V1MessagesPostRequestBodyContentApplicationJsonSchemaThinking

효과가 없습니다. 추론을 켜거나 끄지 않으며 추론 예산도 정하지 않습니다. 기본적으로 추론하는 모델은 계속 추론하며, 추론 내용은 `thinking` 블록으로 반환됩니다.

### V1MessagesPostResponsesContentApplicationJsonSchemaContentItems

- `text` (string, optional) — `text` 블록의 답변 텍스트입니다.

### V1MessagesPostResponsesContentApplicationJsonSchemaUsage

`input_tokens`와 `output_tokens`. 추론은 출력으로 계산됩니다. 호출은 실제 토큰 사용량으로 계량됩니다.

### V1MessagesPostRequestBodyContentApplicationJsonSchemaMessagesItemsContent

- string
- list of V1MessagesPostRequestBodyContentApplicationJsonSchemaMessagesItemsContentOneOf1Items

### V1MessagesPostRequestBodyContentApplicationJsonSchemaSystemOneOf1Items

### V1MessagesPostRequestBodyContentApplicationJsonSchemaMessagesItemsContentOneOf1Items

- `type` (string, optional)
- `text` (string, optional)
- `image_url` (V1MessagesPostRequestBodyContentApplicationJsonSchemaMessagesItemsContentOneOf1ItemsImageUrl, optional)
- `source` (V1MessagesPostRequestBodyContentApplicationJsonSchemaMessagesItemsContentOneOf1ItemsSource, optional)

### V1MessagesPostRequestBodyContentApplicationJsonSchemaMessagesItemsContentOneOf1ItemsImageUrl

- string
- V1MessagesPostRequestBodyContentApplicationJsonSchemaMessagesItemsContentOneOf1ItemsImageUrl1

### V1MessagesPostRequestBodyContentApplicationJsonSchemaMessagesItemsContentOneOf1ItemsSource

- `type` (string, optional)
- `media_type` (string, optional)
- `data` (string, optional)
- `url` (string, optional)

### V1MessagesPostRequestBodyContentApplicationJsonSchemaMessagesItemsContentOneOf1ItemsImageUrl1

- `url` (string, optional)
- `detail` (string, optional)

## Examples

**Request**

```json
{
  "model": "gemini-3.8-flash",
  "max_tokens": 2000,
  "messages": [
    {
      "role": "user",
      "content": "Design a resilient webhook retry strategy for a payments API."
    }
  ]
}
```

**Response**

```json
{
  "id": "msg_example",
  "model": "gemini-3.8-flash",
  "content": [
    {
      "text": "Retry with exponential backoff and jitter, and make every handler idempotent.",
      "type": "text"
    }
  ],
  "stop_reason": "end_turn",
  "usage": {
    "input_tokens": 19,
    "output_tokens": 16
  },
  "role": "assistant",
  "stop_sequence": null,
  "type": "message"
}
```

**SDK Code**

```python 빠른 시작
import requests

url = "https://direct.beatapi.io/v1/messages"

payload = {
    "model": "gemini-3.8-flash",
    "max_tokens": 2000,
    "messages": [
        {
            "role": "user",
            "content": "Design a resilient webhook retry strategy for a payments API."
        }
    ]
}
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript 빠른 시작
const url = 'https://direct.beatapi.io/v1/messages';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"model":"gemini-3.8-flash","max_tokens":2000,"messages":[{"role":"user","content":"Design a resilient webhook retry strategy for a payments API."}]}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go 빠른 시작
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://direct.beatapi.io/v1/messages"

	payload := strings.NewReader("{\n  \"model\": \"gemini-3.8-flash\",\n  \"max_tokens\": 2000,\n  \"messages\": [\n    {\n      \"role\": \"user\",\n      \"content\": \"Design a resilient webhook retry strategy for a payments API.\"\n    }\n  ]\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby 빠른 시작
require 'uri'
require 'net/http'

url = URI("https://direct.beatapi.io/v1/messages")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"model\": \"gemini-3.8-flash\",\n  \"max_tokens\": 2000,\n  \"messages\": [\n    {\n      \"role\": \"user\",\n      \"content\": \"Design a resilient webhook retry strategy for a payments API.\"\n    }\n  ]\n}"

response = http.request(request)
puts response.read_body
```

```java 빠른 시작
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://direct.beatapi.io/v1/messages")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"model\": \"gemini-3.8-flash\",\n  \"max_tokens\": 2000,\n  \"messages\": [\n    {\n      \"role\": \"user\",\n      \"content\": \"Design a resilient webhook retry strategy for a payments API.\"\n    }\n  ]\n}")
  .asString();
```

```php 빠른 시작
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://direct.beatapi.io/v1/messages', [
  'body' => '{
  "model": "gemini-3.8-flash",
  "max_tokens": 2000,
  "messages": [
    {
      "role": "user",
      "content": "Design a resilient webhook retry strategy for a payments API."
    }
  ]
}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp 빠른 시작
using RestSharp;

var client = new RestClient("https://direct.beatapi.io/v1/messages");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"model\": \"gemini-3.8-flash\",\n  \"max_tokens\": 2000,\n  \"messages\": [\n    {\n      \"role\": \"user\",\n      \"content\": \"Design a resilient webhook retry strategy for a payments API.\"\n    }\n  ]\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift 빠른 시작
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = [
  "model": "gemini-3.8-flash",
  "max_tokens": 2000,
  "messages": [
    [
      "role": "user",
      "content": "Design a resilient webhook retry strategy for a payments API."
    ]
  ]
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://direct.beatapi.io/v1/messages")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```