Software Engineeringunpacked

Claude batch API: how the Message Batches API works, and when batch beats realtime

The Claude batch API (the Message Batches API) runs many Messages requests asynchronously at 50% of the standard price. You send up to 100,000 requests in one batch, each with a custom_id, and collect the results when the batch ends: most finish within an hour, but the only promise is 24 hours. Use it for work nobody is waiting on, and keep realtime calls for anything that blocks a person or the next step.

What the Claude batch API is

The Message Batches API takes a list of ordinary Messages API requests, processes them asynchronously, and returns one result per request. The docs pitch it as "well-suited to tasks that do not require immediate responses, with most batches finishing in less than 1 hour while reducing costs by 50%".

Realtime (Messages API) Batch (Message Batches API)
Price Standard 50% of standard, every token
When you get the answer In the response When the batch ends: most within 1 hour, at most 24 hours
Latency promise Answers while you wait None beyond the 24-hour window
Streaming Yes No: results come back as one file
Rate limits Messages API limits Its own limits; batch usage doesn't affect Messages API limits

How a batch works, step by step

  1. Create the batch with a list of requests. Each has a custom_id and the same params you would send to the Messages API.
  2. Poll the batch until its processing_status changes from in_progress to ended.
  3. Read the results. Each line holds a custom_id and a result of type succeeded, errored, canceled or expired.

```python import time import anthropic

client = anthropic.Anthropic()

batch = client.messages.batches.create( requests=[ { "custom_id": f"email-{email['id']}", "params": { "model": "claude-haiku-5-5", "max_tokens": 1024, "system": DAMAGE_REPORT_PROMPT, "messages": [{"role": "user", "content": email["text"]}], }, } for email in todays_emails ] )

while client.messages.batches.retrieve(batch.id).processing_status != "ended": time.sleep(60)

retry = [] for item in client.messages.batches.results(batch.id): if item.result.type == "succeeded": save_report(item.custom_id, item.result.message) else: retry.append(item.custom_id) # errored or expired: send again ```

Two details in that loop matter. Results "can be returned in any order", so custom_id is the only reliable way to match a result to its input: make it meaningful, such as the email or document ID. And only succeeded results are billed; errored, canceled and expired requests cost nothing, so collecting them for a second pass is cheap.

Limits to know

What you can put in a batch

Almost any Messages request: vision, tool use, system prompts, multi-turn conversations, structured output, extended thinking and most beta features. Each request is processed independently, so one batch can mix request types.

Server tools such as web search, web fetch and code execution run inside the batch, with the same server-side loop as a realtime call. Client tools are different. When Claude asks for one of your tools, the result comes back with stop_reason: "tool_use" and the request is over. Your code runs the tool and sends a new request with the result. An agentic loop that waits on your own tools after every step is therefore realtime work, not batch work.

Batch vs realtime: decide from the deadline

The rule is one question: is anyone waiting for this answer?

Realtime: something is waiting Batch: nothing is waiting
A chat reply to a customer Overnight reports
A check a person stands at the counter for A weekly review of last week's cases
A tool call inside an agent loop Large evaluations of a prompt or model
A check that blocks a merge A backlog of documents to extract

Take a bike-rental shop. The same damage-check prompt runs in two places. At the counter, a customer waits for their deposit while the agent checks the return photos: realtime. Overnight, the day's damage emails are classified for the morning team: batch, at half price.

The deadline arithmetic

When results must be ready by a promised time, plan with the worst case, not the typical one:

worst case = time between submissions + 24 hours, plus room to rerun anything that expires.

Say you promise customers a damage report within 36 hours of their email:

The trap is planning with "most batches finish within an hour". That is typical, not promised. And if the deadline is under 24 hours, no schedule can guarantee it: use realtime.

Making batches cheaper and more reliable

Batch processing on the Claude Certified Architect exam

Task 4.5 of the CCAR-F exam (Domain 4, prompt engineering and structured output) covers this directly:

The usual wrong answers are batching a step that someone waits on and trusting the typical run time.

More in all articles.

Sources: Batch processing, read on 21 October 2026; Pricing; Tool use overview; Claude Certified Architect Foundations exam guide v1.0, task statement 4.5.

FAQ

How much cheaper is the Claude batch API?

All batch usage is charged at 50% of the standard API prices, on input tokens, output tokens and special tokens alike. The discount stacks with prompt caching.

How long does a Claude message batch take?

Most batches finish within 1 hour, but the docs promise only 24 hours: results are available when every request has completed or after 24 hours, whichever comes first, and requests not processed by then expire.

Are batch results returned in order?

No. Results can come back in any order, so give every request a unique custom_id and match results on it.

Can I use tools in a batch request?

Yes. Tool use, vision, system prompts, multi-turn conversations and extended thinking all work, and server tools such as web search run inside the batch. A client tool call still needs your code to run it and send a follow-up request, so an agent loop that waits on your tools is a realtime job.