빠른 답변: Claude Batch API는 Messages API 요청을 비동기적으로 처리하며 입력과 출력 토큰 모두 50% 할인된 가격을 적용합니다. 한 번의 호출로 최대 100,000건의 요청(또는 256MB)을 제출하고, 배치가 끝날 때까지 폴링한 다음, 자신의 custom_id를 키로 결과를 읽습니다. 대부분의 배치는 1시간 이내에 완료되며, 최대 한도는 24시간입니다.
분류해야 할 지원 티켓 40,000건이 있거나, 다시 작성해야 할 제품 카탈로그가 있거나, 요약해야 할 한 달치 녹취록이 있습니다. 그중 급한 것은 아무것도 없습니다. 하지만 그 호출을 하나씩 실행하면 모두 정가로 청구되며, 오후 내내 속도 제한에 걸린 재시도를 감시하며 보내게 됩니다.
Claude Batch API는 바로 이런 형태의 작업을 위해 존재합니다. Anthropic에 요청 목록을 넘기고 자리를 뜨면, 동일한 호출을 동기식으로 실행했을 때의 절반 비용이 드는 결과 파일을 받게 됩니다. 운영할 큐도, 동시성 튜닝도, 백오프 로직도 필요 없습니다.
이 가이드에서는 배치 엔드포인트가 하는 일, 비용, 작업을 제출하고 수집하는 방법, 그리고 실제 데이터에 적용하기 전에 코딩 에이전트가 Apidog CLI로 전체 과정을 테스트하게 하는 방법을 다룹니다.
Claude Batch API란 무엇인가요?
Claude Batch API는 /v1/messages/batches에 위치한 비동기 엔드포인트로, 여러 Messages API 요청을 한 번의 제출로 받아 처리가 끝나면 그 결과를 반환합니다. 지연 시간을 대가로 50% 할인을 제공합니다. Anthropic은 이를 배치 처리 문서에서 설명합니다.
설계할 때 고려해야 할 제약 사항은 다음과 같습니다.
- 크기: 배치당 최대 100,000건의 요청 또는 256MB 중 먼저 도달하는 한도까지.
- 시간: 대부분의 배치는 1시간 이내에 완료되며, 완료되지 않은 요청이 만료되기까지의 최대 시간은 24시간입니다.
- 보존: 결과는 배치가 생성된 후 29일 동안 사용할 수 있습니다.
- 기능 동등성: 비전, 도구 사용, 시스템 프롬프트, 프롬프트 캐싱이 모두 배치 안에서 작동합니다.
- 순서: 결과는 임의의 순서로 반환되므로 위치가 아니라
custom_id를 키로 사용해야 합니다.
마지막 항목이 사람들을 당황하게 만드는 부분입니다. 배치는 큐가 아니라 주머니입니다.
Claude Batch API 비용
할인은 입력과 출력 토큰 모두에 50% 정액으로 적용되며, 각 요청이 지정한 모델에 그대로 적용됩니다. 하나의 배치 안에서 모델을 섞을 수 있으므로 저렴한 분류기와 비싼 요약기를 함께 태울 수 있습니다.

| 모델 | 표준 입력 / 출력 (MTok당) | 배치 입력 / 출력 (MTok당) |
|---|---|---|
| Claude Opus 5.5 | $4.00 / $20.00 | $2.00 / $10.00 |
| Claude Sonnet 5.5 | $2.00 / $10.00 | $1.00 / $5.00 |
| Claude Haiku 5.5 (프롬프트 최대 100K) | $0.10 / $0.50 | $0.05 / $0.25 |
| Claude Haiku 5.5 (프롬프트 100K 초과) | $0.50 / $2.50 | $0.25 / $1.25 |
Haiku 행을 주의 깊게 보세요. Haiku 5.5는 프롬프트 크기로 가격을 책정하므로, 하나의 프롬프트가 100,000 토큰을 넘으면 배치 할인 여부와 관계없이 짧은 프롬프트 요율의 5배가 청구됩니다. 장문 컨텍스트 Haiku 작업은 $0.05 / $0.25가 아니라 $0.25 / $1.25로 예측하세요. 이 수치를 바탕으로 예측을 세우기 전에 Anthropic의 가격 페이지를 확인하고, 청구서가 이 글을 읽는 이유라면 Claude API 지출이 어디로 가는지에 대한 분석을 읽어보세요.
배치 가격은 프롬프트 캐싱과도 중첩되며, 진정한 절감은 바로 여기서 나옵니다. 자세한 내용은 아래에서 다룹니다.
첫 배치 제출하기
공식 Python SDK를 설치하고 요청 목록을 만드세요. 각 요청은 직접 지정하는 custom_id와 일반적인 messages.create() 호출과 똑같이 생긴 params 객체를 가집니다.
import anthropic
from anthropic.types.message_create_params import MessageCreateParamsNonStreaming
from anthropic.types.messages.batch_create_params import Request
client = anthropic.Anthropic()
tickets = [
"Card declined three times, support chat timed out.",
"Love the new dashboard, the export button is hidden though.",
"Webhook stopped firing after the 2.4 upgrade.",
]
batch = client.messages.batches.create(
requests=[
Request(
custom_id=f"ticket-{i}",
params=MessageCreateParamsNonStreaming(
model="claude-haiku-5-5",
max_tokens=1024,
output_config={"effort": "low"},
messages=[{
"role": "user",
"content": f"Label this ticket billing, bug, or praise. One word.\n\n{text}",
}],
),
)
for i, text in enumerate(tickets)
]
)
print(batch.id, batch.processing_status)
custom_id에 의미를 담으세요. 데이터베이스 기본 키나 파일 경로를 쓰면 나중에 조인할 필요가 없으며, 결과를 입력과 연결하는 유일한 수단입니다.
원시 HTTP를 선호한다면 동일한 페이로드를 x-api-key와 anthropic-version 헤더와 함께 POST https://api.anthropic.com/v1/messages/batches로 보내면 됩니다. 전체 스키마는 메시지 배치 생성 레퍼런스에서 확인할 수 있습니다.
배치를 폴링하고 결과 수집하기
processing_status가 ended가 될 때까지 배치를 조회한 다음 결과를 스트리밍하세요. 각 결과는 설정한 custom_id와 succeeded, errored, canceled, expired 중 하나인 result.type을 가집니다.
import time
while True:
batch = client.messages.batches.retrieve(batch.id)
if batch.processing_status == "ended":
break
print("still working:", batch.request_counts.processing)
time.sleep(30)
labels, retry = {}, []
for result in client.messages.batches.results(batch.id):
if result.result.type == "succeeded":
msg = result.result.message
labels[result.custom_id] = next(b.text for b in msg.content if b.type == "text")
elif result.result.type == "errored":
retry.append(result.custom_id)
print(f"{len(labels)} labeled, {len(retry)} need another pass")
두 가지 실패 유형은 별도로 처리해야 합니다. invalid_request 오류는 요청 본문이 잘못되었다는 뜻이므로 다시 제출하기 전에 수정하세요. 그 외의 오류는 서버 측 문제이므로 그대로 재시도해도 안전합니다. expired 결과는 해당 요청이 실행되기 전에 24시간 창이 닫혔다는 뜻이며, 이것들도 다시 제출해야 합니다.
30~60초 간격으로 폴링하세요. 매초 조회 엔드포인트를 두드리는 것은 아무 이득도 없고 Claude API 속도 제한에만 영향을 줍니다.
배치 가격에 프롬프트 캐싱 중첩하기
가장 큰 이득은 두 할인을 결합할 때 나옵니다. 배치의 모든 요청이 긴 접두사(스타일 가이드, 분류 체계, 40페이지 계약서)를 공유한다면, 그 접두사를 cache_control로 표시하고 10,000건의 요청 모두에 동일한 표시된 접두사를 보내세요.
shared_system = [
{"type": "text", "text": "You are a support triage analyst."},
{
"type": "text",
"text": taxonomy_document, # thousands of tokens, identical every time
"cache_control": {"type": "ephemeral"},
},
]
배치의 모든 Request에 그 system 블록을 넣으세요. 접두사가 살아 있는 캐시 항목과 바이트 단위로 일치하는 요청은 그 접두사에 대해 캐시 읽기 요율로 청구되며, 50% 배치 할인은 캐시 읽기와 쓰기 모두에 적용됩니다. 완벽한 적중률을 가정하고 예산을 잡지 마세요. 배치는 요청을 순서대로가 아니라 동시에 처리하므로 하나의 배치 안에서의 캐시 적중은 최선 노력 수준입니다. Anthropic의 프롬프트 캐싱 가이드에서 접두사 규칙을 다룹니다. 중단 지점 이전에 바뀌는 바이트는 그 뒤의 모든 것을 무효화하므로, 타임스탬프와 항목별 텍스트는 캐시된 블록 뒤에 두세요.
Claude Code가 Apidog CLI로 엔드포인트를 테스트하게 하기
100,000건의 실제 요청에 돈을 쓰기 전에 배치 생명주기(생성, 조회, 결과)에 대한 회귀 테스트를 원할 것입니다. GUI에서 직접 작성하는 것은 느립니다. 대신 코딩 에이전트가 Apidog CLI로 수행하게 하세요.
npm install -g apidog-cli@latest
apidog auth login --with-token <YOUR_TOKEN>
apidog skill install # pick Claude Code when prompted
그런 다음 Claude Code에 한 번의 프롬프트를 입력하세요:
In Apidog project 4820193, create a test case for POST https://api.anthropic.com/v1/messages/batches
that submits two Haiku 5.5 requests with custom_id ticket-0 and ticket-1, asserts the response
has an id and processing_status, then polls GET /v1/messages/batches/{id} until processing_status
is ended. Run it against the anthropic-staging environment and summarize failures.
에이전트는 페이로드 스키마를 읽고 자체 JSON을 검증한 다음, 케이스를 생성하고 실행합니다:
apidog cli-schema get test-case-create
apidog cli-schema validate test-case-create --file batch-case.json
apidog test-case create --project 4820193 --file batch-case.json
apidog run --test-case 77214 --project 4820193 -e 992301 -r cli,json
API 키는 Apidog 환경 변수에 남아 있으므로 프롬프트나 저장소에 절대 들어가지 않습니다. 리포터를 -r junit로 바꾸면 동일한 명령이 모든 병합 시 CI에서 실행되며, 이는 Apidog CLI 파이프라인 가이드에서 소개한 설정입니다. 아직 CLI를 에이전트에 연결하지 않았다면 Claude Code에서 Apidog CLI 사용하기부터 시작하세요.
배치가 잘못된 선택일 때

| 워크로드 | 배치 사용? | 이유 |
|---|---|---|
| 매일 밤 어제의 로그 요약 | 예 | 기다리는 사람이 없고 50% 할인됨 |
| 코퍼스 전체에 임베딩이나 레이블 백필 | 예 | 100,000건 요청 한도에 부합 |
| 프롬프트 스위트 전반에 걸친 평가 실행 | 예 | custom_id를 키로 한 결과가 테스트 ID에 매핑됨 |
| 채팅 UI 응답 | 아니요 | 사용자는 한 시간을 기다리지 않음 |
| 다음 단계를 고르기 위해 마지막 답변이 필요한 에이전트 루프 | 아니요 | 배치 요청은 서로를 볼 수 없음 |
| 5초 SLA를 지켜야 하는 요청 | 아니요 | 24시간 미만의 지연 시간 보장이 없음 |
몇 가지는 아예 넘어오지 않습니다. 빠른 모드(fast mode)는 Batch API에서 사용할 수 없고, 서버 측 거부 폴백도 여기서는 거부되며, Claude Opus 5.5와 Claude Sonnet 5.5에서 any 또는 tool로 강제한 tool_choice는 일반 호출과 마찬가지로 배치 안에서도 400을 반환합니다. 대신 strict: true와 함께 tool_choice: auto를 사용하세요.
멀티 프로바이더 인프라를 운영한다면 다른 곳에도 같은 패턴이 있습니다. OpenAI Batch API와 Gemini API 배치 모드를 참고하세요. 형태는 다르지만 경제성은 같습니다.
자주 묻는 질문
Claude Batch API란 무엇인가요?
표준 Messages API 요청을 정상 토큰 가격의 50%로 대량 실행하는 비동기 엔드포인트입니다. 자체 ID와 함께 요청 목록을 제출하고, 배치가 끝날 때까지 폴링한 뒤, 29일 이내에 결과를 읽으면 됩니다.
Claude Batch API 비용은 얼마인가요?
입력과 출력 모두 표준 요율의 절반입니다. Claude Sonnet 5.5의 경우 입력 100만 토큰당 $1.00, 출력 100만 토큰당 $5.00이며, 동기식으로는 각각 $2.00과 $10.00입니다.
Claude 배치는 얼마나 걸리나요?
대부분의 배치는 1시간 이내에 완료됩니다. 최대 24시간이며, 그 이후 처리되지 않은 요청은 expired 결과를 반환하므로 다시 제출해야 합니다.
배치 안에서 프롬프트 캐싱을 사용할 수 있나요?
예, 그리고 할인은 중첩됩니다. 공유 접두사를 cache_control로 표시하고 모든 요청에 동일한 접두사를 반복하면, 캐시 읽기는 배치 할인에 더해 입력 가격의 일부만 청구됩니다.
배치의 요청 하나가 실패하면 어떻게 되나요?
그 요청만 실패합니다. 해당 결과는 오류 객체와 함께 type: "errored"를 가지며, 나머지는 모두 성공합니다. 검증 오류는 페이로드를 수정해야 하고, 서버 오류는 그대로 재시도해도 안전합니다.
실행 중인 배치를 취소할 수 있나요?
예. client.messages.batches.cancel(batch_id)는 배치를 canceling으로 전환합니다. 이미 완료된 요청은 결과를 유지하고, 나머지는 canceled로 반환됩니다.
Batch API는 도구와 이미지를 지원하나요?
예. 비전, 도구 정의, 시스템 프롬프트를 포함한 모든 Messages API 기능이 배치 안에서 작동합니다. 예외는 빠른 모드, 서버 측 폴백, 그리고 5.5 모델에서의 강제 도구 선택입니다.
마무리
배치 처리는 프롬프트 캐싱 다음으로 Claude API에서 두 번째로 큰 무료 절감 수단이며, 품질에는 아무런 손해가 없습니다. 같은 모델, 같은 기능, 절반의 가격을, 아마 쓰지도 않았을 지연 시간으로 지불하는 것입니다. 결과는 custom_id를 키로 삼고, 공유 접두사는 캐시하고, expired는 실패가 아니라 재시도로 처리하세요.
확장하기 전에 생명주기를 테스트하세요. Apidog CLI를 설치하고 코딩 에이전트를 배치 엔드포인트로 향하게 한 뒤, 생성된 테스트 케이스를 CI에서 계속 실행하여 스키마 변경이 100,000건의 요청에서 당신을 놀라게 하지 않도록 하세요. 무료 플랜은 4명의 사용자를 지원하며, Apidog을 다운로드하면 몇 분 만에 첫 케이스를 실행할 수 있습니다.
