Blog
4 min read

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

  1. You submit a batch: a list of normal Messages API requests, each with your own custom_id.
  2. Anthropic processes them in the background, independently.
  3. 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_id must 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