Claude Message Batches API: Half-Price Claude for Work That Can Wait
The Message Batches API runs large numbers of Claude requests asynchronously at 50% of the normal price — usually finishing within an hour. When to use it (classification, extraction, evals, backfills), limits (100,000 requests or 256 MB per batch, 24-hour expiry, 29-day results), a complete Python example, and how it stacks with prompt caching.
Not every AI request needs an answer in two seconds. Tagging 50,000 support tickets, extracting fields from a pile of invoices, summarising last month's documents, running an evaluation suite — none of that is waiting on a user.
For work like that, Anthropic's Message Batches API processes requests asynchronously at 50% of the standard price, input and output.
Limits and prices as of October 2026, from Anthropic's batch processing docs.
How it works
- You submit a batch: a list of normal Messages API requests, each with your own
custom_id. - Anthropic processes them in the background, independently.
- You poll the batch status, and when it's ended, download the results.
Most batches finish within an hour.
The limits
- Up to 100,000 requests or 256 MB per batch, whichever comes first.
- Results become available when everything is done, or after 24 hours. Requests not processed within 24 hours expire (and aren't billed).
- Results can be downloaded for 29 days.
custom_idmust be 1–64 characters: letters, numbers,-and_.- Results may come back in any order — always match on
custom_id.
What it costs
Every model is half price in batch mode. For example (per million tokens):
| Model | Standard input / output | Batch input / output |
|---|---|---|
| Opus 5.5 | $4 / $20 | $2 / $10 |
| Sonnet 5.5 | $2 / $10 | $1 / $5 |
| Haiku 5.5 (prompts ≤100K tokens) | $0.10 / $0.50 | $0.05 / $0.25 |
The batch discount stacks with prompt caching, so a batch where every request shares a long system prompt or document gets both discounts. Put the shared part first and mark it for caching. (Prompt Caching Explained, Claude API Pricing Explained)
A complete Python example
import time
import anthropic
client = anthropic.Anthropic() # reads ANTHROPIC_API_KEY
tickets = [
{"id": "t-1001", "text": "I was charged twice for my subscription"},
{"id": "t-1002", "text": "How do I export my data to CSV?"},
]
batch = client.messages.batches.create(
requests=[
{
"custom_id": t["id"],
"params": {
"model": "claude-haiku-5-5",
"max_tokens": 200,
"system": "Classify the support ticket as one of: billing, how-to, bug, other. Reply with the label only.",
"messages": [{"role": "user", "content": t["text"]}],
},
}
for t in tickets
]
)
while True:
batch = client.messages.batches.retrieve(batch.id)
if batch.processing_status == "ended":
break
time.sleep(60)
for result in client.messages.batches.results(batch.id):
if result.result.type == "succeeded":
label = next(b.text for b in result.result.message.content if b.type == "text")
print(result.custom_id, label.strip())
else:
print(result.custom_id, "failed:", result.result.type)
Note the result loop picks the text block by type: current models can start a response with thinking blocks, so don't assume content[0] is the answer.
Result types
| Type | Meaning | Billed? |
|---|---|---|
succeeded |
Message returned | Yes |
errored |
Invalid request or server error | No |
canceled |
You cancelled the batch first | No |
expired |
Not reached within 24 hours | No |
Collect errored and expired IDs and resubmit them in a new batch.
Good uses
- Classification and tagging of large datasets.
- Structured extraction from documents. (Structured Output From LLMs)
- Evals: running your test prompts against a new model. (Evaluate LLM Outputs)
- Backfills: generating summaries or embeddings-adjacent metadata for existing records.
- Nightly jobs that prepare content for the next day. (Background Jobs and Cron)
Bad uses
- Anything a user is waiting for.
- Multi-step agent loops where each step depends on the last (each batch request is independent).
- Very small jobs, where the wait isn't worth the saving.
Practical tips
- Test a few requests synchronously first — a mistake in the prompt multiplied by 50,000 is expensive.
- Store the batch ID in your database so a restarted worker can resume polling.
- Chunk huge datasets into multiple batches to stay under the limits and get partial results sooner.
- Batches count against rate limits too, including how many requests can be queued.
The summary
- The Message Batches API = 50% off for asynchronous work, usually done within an hour.
- Up to 100,000 requests / 256 MB per batch; 24-hour expiry; results for 29 days.
- Stacks with prompt caching; match results by
custom_id.
EasySpawn gives your app a persistent server where long-running batch jobs and their polling workers can live next to your database, with Claude Code to build them. See how it works or join the waitlist.
Related: Get a Claude API Key · What Are Tokens in AI? · Opus vs Sonnet vs Haiku · How to Build an AI App
Keep reading
Prompt Caching Explained: Cut LLM Costs and Latency on Repeated Prompts
If every request repeats the same long system prompt, documents or tool definitions, prompt caching lets the provider reuse that work for a fraction of the price and time. How it works, structuring prompts for cache hits, Claude's cache_control, OpenAI's automatic caching, and verifying it works.
How to Stop Bots From Running Up Your AI App's Bill
If your app calls an AI model on a user's behalf, every request costs you money — and a bot, a scraper, or one determined user can make thousands of them overnight. Rate limits, usage caps, provider spending limits, and the architecture that keeps a surprise bill from happening.