# Claude Batch API Pricing: When 50% Off Beats Prompt Caching

> The Claude Batch API halves every token price for jobs that can wait up to 24 hours, but on a big shared prompt, cached standard calls can still cost less.

- URL: https://blog.laozhang.ai/en/posts/claude-batch-api
- Published: 2026-10-30
- Updated: 2026-10-30
- Author: LaoZhang AI Team (https://blog.laozhang.ai/en/about)
- Topic: API Guides
- Tags: Claude API, Message Batches API, Batch API, Prompt Caching, API Pricing, Python

---
The Claude Batch API, officially the Message Batches API, bills every token at 50% of standard prices: input, output, and prompt-cache writes and reads. What you give up is speed. Anthropic says most batches finish in under an hour, but any request still unprocessed after 24 hours expires, so batches suit evals, classification, extraction, bulk rewrites and nightly reports, not anything a person is waiting on. As of October 30, 2026, Claude Sonnet 5.5 costs $1 per million input tokens and $5 per million output tokens in a batch, against $2 and $10 on the standard Messages API.

Whether that halves your bill depends on what you already do. If your requests share a long prompt and you cache it on standard calls, caching may already save more than batching would: for 10,000 Sonnet 5.5 requests with a 3,000-token shared prefix, cached standard calls cost $44.00 and a batch without caching costs $50.50. The batch wins clearly once caching also works inside it, falling to $22.72 at a 98% cache hit rate, or when your prompts share little and output is a big part of the bill.

To use it, send your requests to `POST /v1/messages/batches`, each with a unique `custom_id` and the same `cache_control` block on the shared prefix, poll until `processing_status` reads `ended`, then match results by `custom_id`, because they come back out of order. Resend `expired` requests and errors other than `invalid_request_error`, and fix the invalid ones first; none of these failures is billed. Anthropic's batch pricing applies on the Claude API, Claude Platform on AWS and Claude Models on Google Cloud (Anthropic managed). Amazon Bedrock and Google's Vertex AI run their own Claude batch products with their own formats and prices, and as of October 30, 2026 Bedrock's batch list includes no 5.5 model. A gateway that only forwards `/v1/messages` gives you no batch discount at all.

## Claude Batch API pricing: 50% off input, output and cache tokens

Every model that supports batches costs exactly half its standard rate in a batch, and Anthropic's [Batch processing documentation](https://platform.claude.com/docs/en/build-with-claude/batch-processing) says the cut covers input, output "and any special tokens". Prompt-caching multipliers stack on top of it, as the [Claude API pricing page](https://platform.claude.com/docs/en/about-claude/pricing) states: a 5-minute cache write costs 1.25x the input price and a 1-hour write 2x, while a cache read costs 0.05x on Opus 5.5 and Sonnet 5.5, 0.025x on Fable 5.1 and 0.1x on Haiku 5.5, and the batch then halves each of those. Prices as of October 30, 2026, in USD per million tokens:

| Model | Standard input / output | Batch input / output | Batch 5-min cache write | Batch cache read |
|---|---|---|---|---|
| Claude Fable 5.1 | $10 / $50 | $5 / $25 | $6.25 | $0.125 |
| Claude Opus 5.5 | $4 / $20 | $2 / $10 | $2.50 | $0.10 |
| Claude Sonnet 5.5 | $2 / $10 | $1 / $5 | $1.25 | $0.05 |
| Claude Haiku 5.5, prompts up to 100K tokens | $0.10 / $0.50 | $0.05 / $0.25 | $0.0625 | $0.005 |
| Claude Haiku 5.5, prompts over 100K tokens | $0.50 / $2.50 | $0.25 / $1.25 | $0.3125 | $0.025 |

The two cache columns are standard input × multiplier × 0.5. Older models are halved the same way: Opus 5, 4.8, 4.7, 4.6 and 4.5 cost $2.50 / $12.50 in a batch, Sonnet 5 costs $1 / $5, Sonnet 4.6 and 4.5 cost $1.50 / $7.50, and Haiku 4.5 costs $0.50 / $2.50. Two other modifiers also stack with the batch discount. US-only processing with `inference_geo: "us"` multiplies every token category by 1.1 on Claude 4.6 and later, and Claude 4.6 and later models other than Haiku 5.5 bill their full 1M-token context at standard rates, so long prompts get the same 50% cut. Fast mode is the one pricing option a batch can't use. Per-model detail lives in [Claude Fable 5.1 API Pricing: What Changed and What You'll Pay](https://blog.laozhang.ai/en/posts/claude-fable-5-1-api-pricing) and [Claude Sonnet 5.5 Cache Read Price Cut to $0.10: What You Save](https://blog.laozhang.ai/en/posts/claude-sonnet-5-5-cache-read-price).

## Batch or prompt caching: which is cheaper for 10,000 requests?

For a job whose requests share a long prompt, prompt caching on standard calls can cost less than a batch that doesn't cache, and a batch that does cache beats both. The table below was recomputed on October 30, 2026 from Anthropic's list prices for one workload: 10,000 requests, each with a 3,000-token shared prefix (instructions, schema, examples), 800 tokens of unique input and 250 output tokens. Cached standard calls assume near-100% hits, because requests sent one after another keep the 5-minute entry warm. Inside a batch, every miss writes the prefix again at the write price.

| Model | Standard, no cache | Standard + 5-min cache, ~100% hits | Batch, no cache | Batch + 5-min cache, 30% hits | Batch + 5-min cache, 98% hits | Batch + 1-hour cache, 30% hits |
|---|---|---|---|---|---|---|
| Claude Haiku 5.5 | $5.05 | $2.35 | $2.52 | $2.38 | $1.21 | $3.17 |
| Claude Sonnet 5.5 | $101.00 | $44.00 | $50.50 | $47.20 | $22.72 | $62.95 |
| Claude Opus 5.5 | $202.00 | $88.00 | $101.00 | $94.40 | $45.44 | $125.90 |
| Claude Fable 5.1 | $505.00 | $212.50 | $252.50 | $234.88 | $109.92 | $313.62 |

Cached standard calls beat the cache-less batch on all four models, by about 13% on Sonnet 5.5 ($4.40 against $5.05 per 1,000 requests), because caching cuts the 3,000-token prefix to 5% of its input price while the batch only halves it. Output works the other way. It is 24.8% of the uncached standard bill in this workload, caching never touches it, and the batch halves it, so the larger your output share, the more a batch is worth over caching alone. A batch whose cache actually hits is the cheapest option on every model, at 22–24% of the uncached standard bill. If your prompts share almost nothing, there is nothing to cache and the batch is simply 50% off the whole bill.

To rerun this for your own job, the batch cost is requests × (prefix × input price × (hit rate × read multiplier + (1 − hit rate) × write multiplier) + unique tokens × input price + output tokens × output price) × 0.5. Drop the final 0.5 for standard calls, and replace the bracketed cache term with 1 when you don't cache.

## When does caching inside a batch pay off? Above about 21% hits

Caching the shared prefix inside a batch saves money only when more than about 21% of requests hit the cache with the 5-minute lifetime, or about 51% with the 1-hour lifetime. Below that, the writes on every miss cost more than the reads save. The break-even hit rate is (w − 1) / (w − r), where w is the write multiplier and r the read multiplier: 20.8% on Opus 5.5 and Sonnet 5.5, 20.4% on Fable 5.1 and 21.7% on Haiku 5.5 with 5-minute writes, and 51.3%, 50.6% and 52.6% with 1-hour writes. The batch discount halves both sides equally, so it doesn't move the threshold.

If your alternative is cached standard calls rather than an uncached batch, the bar is higher. In the workload above, a batch with 5-minute caching undercuts near-perfect cached standard calls only above about 39% hits on Sonnet 5.5 and Opus 5.5, 32% on Haiku 5.5 and 42% on Fable 5.1. Anthropic can't tell you your rate in advance: batch requests run concurrently and in any order, so cache hits are best effort, and the documentation says users "typically experience cache hit rates ranging from 30 percent to 98 percent". At the bottom of that range, a batch can end up costing more than the cached standard calls you already run.

![Line chart of a 10,000-request Claude Sonnet 5.5 job: batch with 5-minute cache drops below a cache-less batch at 21% hits and below cached standard calls at 39%, while 1-hour cache needs 51%](https://blog.laozhang.ai/posts/en/claude-batch-api/img/batch-cache-break-even.webp)

Anthropic suggests the 1-hour lifetime for batches with shared context, since a batch can take longer than 5 minutes. It doubles the write price, though, and at 30% hits it makes the Sonnet 5.5 job dearer than not caching at all. Pick it only when you expect it to lift your hit rate past about 51%. Anthropic's other advice raises hits for either lifetime: put identical `cache_control` blocks in every request, keep requests flowing steadily so 5-minute entries don't lapse, and share as much of the prompt as you can. For a 1-hour entry, the marker is `{"type": "ephemeral", "ttl": "1h"}`. A `max_tokens: 0` pre-warm request is rejected inside a batch.

Every `succeeded` result carries the usual `usage` object, so summing `cache_read_input_tokens` and `cache_creation_input_tokens` over your first batch gives your real hit rate for the next decision. How breakpoints, lifetimes and minimum prefix sizes work is covered in [Claude Prompt Caching: How It Works, Costs, 512-Token Minimum](https://blog.laozhang.ai/en/posts/claude-prompt-caching).

## How to submit a Claude batch in Python: create, poll, collect by custom_id

A batch is a list of ordinary Messages API requests, each wrapped with a `custom_id`, sent in one call; you then poll its status and stream the results when it ends. The `anthropic` Python SDK 2.3.0 and the TypeScript `@anthropic-ai/sdk` 1.3.0, both released October 23, 2026, expose this as `messages.batches.create`, `retrieve`, `results`, `list`, `cancel` and `delete`. You need a Claude Console API key; [Claude API Key: How to Get One, Is It Free, and Safe Buying](https://blog.laozhang.ai/en/posts/claude-api-key-free-tier) covers getting one.

1. Send one request with the exact `params` you plan to batch to the standard Messages API first. Batch params are validated asynchronously, so a wrong field only shows up as `errored` results after the whole batch has ended.
2. Give every request a `custom_id` of 1–64 letters, digits, hyphens or underscores, unique within the batch, and keep the mapping to your own records. Every `params` needs `max_tokens` of at least 1.
3. Create the batch within the size limits in the next sections, then poll `processing_status` every minute or so until it reads `ended`. The `succeeded`, `errored`, `canceled` and `expired` counts in `request_counts` stay at 0 until the whole batch ends, so a batch showing nothing but `processing` is not stuck.
4. Stream the results and sort each one by type: keep `succeeded`, queue `expired` and server-side errors for another batch, and set `invalid_request_error` aside to fix.
5. Submit the retry list as a new batch with the same function.

![Claude batch workflow: submit, poll until processing_status is ended, stream results, then keep succeeded, resend expired, canceled and server errors, and fix invalid_request_error first](https://blog.laozhang.ai/posts/en/claude-batch-api/img/batch-results-flow.webp)

```python
import time
import anthropic

client = anthropic.Anthropic()  # reads ANTHROPIC_API_KEY

def make_request(custom_id: str, text: str) -> dict:
    return {
        "custom_id": custom_id,  # 1-64 chars: letters, digits, - and _
        "params": {
            "model": "claude-haiku-5-5",
            "max_tokens": 300,
            "messages": [{"role": "user", "content": text}],
        },
    }

def run_batch(requests: list[dict], poll_seconds: int = 60) -> tuple[dict, list[str], list[str]]:
    batch = client.messages.batches.create(requests=requests)
    print("created", batch.id, batch.processing_status)
    while batch.processing_status != "ended":
        time.sleep(poll_seconds)
        batch = client.messages.batches.retrieve(batch.id)
        print("status", batch.processing_status, batch.request_counts)
    done, retry, fix = {}, [], []
    for item in client.messages.batches.results(batch.id):  # order is not guaranteed
        r = item.result
        if r.type == "succeeded":
            done[item.custom_id] = r.message.content[0].text  # first block is text when thinking and tools are off
        elif r.type == "expired":
            retry.append(item.custom_id)          # never reached the model, not billed
        elif r.type == "errored" and r.error.error.type == "invalid_request_error":
            fix.append(item.custom_id)            # resending the same body fails again
        elif r.type == "errored":
            retry.append(item.custom_id)          # server-side error, safe to resend
    return done, retry, fix

# texts = {"doc-00001": "...", "doc-00002": "...", ...}
# done, retry, fix = run_batch([make_request(cid, t) for cid, t in texts.items()])
# done2, retry2, fix2 = run_batch([make_request(cid, texts[cid]) for cid in retry])
```

On October 30, 2026, this workflow ran end-to-end with SDK 2.3.0 against a local mock server that implements the documented batch endpoints and response shapes, not against Anthropic's servers. It confirms the control flow and result handling, not real processing times, validation messages or billing. Five requests went in, and the mock returned two `succeeded`, one `errored` with `api_error`, one `expired` and one `errored` with `invalid_request_error`, in reverse order. The code matched all five by `custom_id`, resubmitted the `api_error` and `expired` requests in a second batch where both succeeded, and left the invalid one in the fix list.

## Batch result types: what to resend and what you are billed for

Each line of the results file is a `.jsonl` record with a `custom_id` and a `result` whose `type` is one of four values, and only `succeeded` costs money. The lines are not in input order, which is why the code above keys everything by `custom_id`. One failed request doesn't affect the others, and results use the API version of the request that created the batch.

| Result type | What happened | Billed? | What to do |
|---|---|---|---|
| `succeeded` | The request ran; `result.message` holds the normal Messages response | Yes, at batch prices | Store it by `custom_id` |
| `errored` with `invalid_request_error` | The request body failed validation | No | Fix the body, test it on the Messages API, then put it in a new batch |
| `errored` with another error type | An internal server error | No | Resend it unchanged in a new batch |
| `canceled` | You canceled the batch before this request ran | No | Resend it if you still need it |
| `expired` | The 24-hour window closed before this request ran | No | Resend it in a new batch |

The split between the two kinds of `errored` follows Anthropic's own sample code: an invalid request fails again if you send the same body, while other errors can go straight back into a new batch. A batch result that ends with `stop_reason: "pause_turn"` is a `succeeded` result whose server-tool turn didn't finish; continue it by resubmitting the paused assistant content, in a batch or a standard call.

## Message Batches API limits: 100,000 requests, 256 MB, 24 hours

The limits apply at three levels: each batch has a size cap, each batch has a time window, and each organization has a request rate and a cap on queued work by usage tier. These are the per-batch rules from Anthropic's Batch processing documentation as of October 30, 2026:

| Limit | Value | What happens at the limit |
|---|---|---|
| Requests per batch | 100,000 | Whichever comes first, count or size, caps the batch |
| Size per batch | 256 MB | A larger request returns 413 `request_too_large` |
| Processing window | 24 hours from creation (`expires_at`) | Requests not yet processed come back `expired`, unbilled |
| Results availability | 29 days from `created_at`, not from `ended_at` | The batch stays visible, but results can no longer be downloaded |
| Scope | One Console Workspace | Only requests and users in that Workspace can see the batch and its results |
| Spend limit | Your Workspace spend limit | High concurrency can push a batch slightly over it |

The organization limits from the [Claude API rate limits page](https://platform.claude.com/docs/en/api/rate-limits) are shared across all models, and batch usage doesn't count against your Messages API limits:

| Usage tier | Batch API requests per minute | Batch requests in the processing queue |
|---|---|---|
| Start | 1,000 | 200,000 |
| Build | 2,000 | 300,000 |
| Scale | 4,000 | 500,000 |

A request counts toward the queue until the model has processed it, so two full batches on the Start tier fill it. New organizations may start in an Evaluation tier below Start, whose batch numbers Anthropic doesn't publish, and higher limits come through sales as a Custom tier. Rate limits on ordinary calls are a separate problem, covered in [Claude API Error: Rate Limit Reached: Find the Right Limit Before You Retry](https://blog.laozhang.ai/en/posts/claude-api-error-rate-limit-reached).

## Why is my Claude batch slow, and what happens after 24 hours?

A slow batch is usually still within the rules. Anthropic promises only the 24-hour window, calls "most batches finishing in less than 1 hour" the typical case, and warns that processing may slow down "based on current demand and your request volume", in which case more requests may expire. It publishes no numbers for those slowdowns, so a batch that takes several hours on a busy day has not broken anything.

The few public timings are individual reports. On Hacker News on April 27, 2026, user erans, who routed every turn of an agent loop through the Batch API, wrote that a one-entry batch "usually took ~90–120 seconds" and that Haiku batches "often felt slower" than Sonnet or Opus ones, calling the testing small and non-rigorous. A [Developers Digest production guide](https://www.developersdigest.tech/blog/claude-batch-api-production-guide) updated October 18, 2026 reports a median of 5 to 30 minutes in its own measurements. The [Claude status page history](https://status.claude.com/history) lists no batch incident in 2025 or 2026; the last ones were elevated errors on November 4, 2024 and delayed processing on November 6–7, 2024. An empty incident log doesn't rule out the demand-driven slowdowns Anthropic describes.

Some requests are slow by design. A request using the 300,000-token output beta "can take over an hour" on its own, and the batch worker throttles `web_search` per organization, so large web-search batches take longer. When a batch ends with `expired` results, resend just those `custom_id`s in a new batch; they weren't billed. If your pipeline needs answers in minutes, send those requests to the standard Messages API and handle overloads there, as described in [Claude API Error 529 Overloaded: Configure Retries and Reduce Pressure](https://blog.laozhang.ai/en/posts/claude-api-error-529-overloaded).

## Tool use, thinking and web search in a batch: what works and what fails

Nearly everything that works on the Messages API also works in a batch, and different request types can share one batch. What gets rejected with a validation error is anything that needs a live connection or a feature reserved for real-time calls. Status per Anthropic's batch documentation as of October 30, 2026:

| Feature | In a batch? | What to know |
|---|---|---|
| Client tool use and multi-turn conversations | Yes | Each request is one Messages call, so when Claude returns `tool_use`, you run the tool and send its result in a new request |
| Server tools: web search, web fetch, code execution, MCP connectors, tool search | Yes | The batch runs the server-side loop for more iterations per turn than a standard call before returning `pause_turn` |
| Extended thinking, vision, system prompts, most beta features | Yes | Same parameters as the Messages API |
| Output up to 300,000 tokens (beta) | Yes, batch only | Header `output-300k-2026-03-24`; Opus 5.5, Sonnet 5.5, Haiku 5.5 and several Opus and Sonnet 4.6–5 models; Claude API and Claude Platform on AWS only; standard batch prices |
| `stream: true` | No | Validation error |
| Fast mode (`speed`) | No | Validation error |
| Server-side `fallbacks` | No | Validation error |
| `max_tokens: 0` | No | Every request needs `max_tokens` of at least 1 |

The client-tool row is the real limit for agents. A batch request can't pause and wait for your tool result, so an agent loop pays a full batch round trip for every tool call, which fits large evaluation runs but not one interactive agent. Issue reports on Anthropic's SDK repositories in March and May 2026 also describe batch-only tool quirks on Opus 4.6, Opus 4.7 and Sonnet 4.6, such as malformed tool input and missing parallel tool calls, one more reason to dry-run a tool request on the Messages API before batching thousands of them.

## Where you can get the batch discount: Claude API, AWS, Google Cloud

Anthropic lists the Message Batches API as generally available on the Claude API, Claude Platform on AWS and Claude Models on Google Cloud (Anthropic managed) as of October 30, 2026, with the same `/v1/messages/batches` requests and batch pricing as the Claude API. Amazon Bedrock and Google's Vertex AI are different: each runs its own batch product for Claude, with its own input format, limits and price list.

On [Amazon Bedrock](https://aws.amazon.com/bedrock/pricing/), which is a separate service from Claude Platform on AWS, AWS says select models from Anthropic and others get batch inference "at a 50% lower price compared to on-demand inference pricing". Jobs read a JSONL file from S3 with one `recordId` and `modelInput` per line, need at least 100 records for Claude models, and take up to 100,000 records and 5 GB. Bedrock's list of batch-supported models showed Claude models up to Opus 5, Opus 4.6, Sonnet 4.6 and Haiku 4.5 on October 30, 2026, with no 5.5 model or Fable 5.1, and Bedrock's Converse request format can't call tools in a batch, so tool requests need the InvokeModel format.

[Vertex AI batch prediction for Claude](https://docs.cloud.google.com/vertex-ai/generative-ai/docs/partner-models/claude/batch) is Google's managed version. It reads requests from a BigQuery table or a JSONL file in Cloud Storage, each with a `custom_id` and a `request` carrying `"anthropic_version": "vertex-2023-10-16"`. The global endpoint isn't supported and a project gets 4 concurrent batch jobs by default. Its page, updated October 28, 2026, lists Sonnet 5.5, Opus 5.5, Haiku 5.5, Fable 5.1 and Fable 5. Google's batch price for Claude is on the Vertex AI pricing page, so check the row for your model there before assuming a discount.

A gateway passes on the batch discount only if it implements `/v1/messages/batches`. On October 30, 2026 at 13:56 UTC, with a usage-billed laozhang.ai key, `GET /v1/messages/batches?limit=1`, `POST /v1/messages/batches` and `GET /v1/messages/batches/{id}` on api.laozhang.ai all returned HTTP 404 with "Invalid URL", and nothing was charged. Before you move batch work to any gateway, try a one-request batch through it first.

*Disclosure: [laozhang.ai is our own service](https://blog.laozhang.ai/en/about#laozhang). Its prices are platform pricing, not an independent comparison.*

If you're on Claude Max or Team, the monthly API credits those plans include, $100 on Max 5x and $200 on Max 20x as of October 8, 2026, also pay for Message Batches once you link a Console organization; [Claude Usage Limits by Plan: What 5x and 20x Actually Multiply](https://blog.laozhang.ai/en/posts/claude-usage-limits-by-plan) covers how the credit works.

## Claude Batch API: other questions

### Can I change or cancel a Claude batch after submitting it?

You can't modify a submitted Message Batch; cancel it and submit a corrected one. `POST /v1/messages/batches/{id}/cancel` moves it to `canceling` and then `ended`, and cancellation may not take effect at once. The batch can still hold partial results for requests that ran before the cancel, according to Anthropic's batch documentation as of October 30, 2026.

### Does the Message Batches API have a webhook?

No webhook is documented as of October 30, 2026. Anthropic's batch documentation and its retrieve endpoint describe polling `processing_status`, and the Claude Console shows each Workspace's batches on its Batches page.

### Can I delete batch data, and is it covered by zero data retention?

Anthropic stores batch inputs and outputs for up to 29 days after creation, and its batch documentation lists the Message Batches API as not eligible for zero data retention or HIPAA as of October 30, 2026. You can delete a batch with `DELETE /v1/messages/batches/{id}` once it has finished processing; cancel an in-progress batch first.

### Is Claude Code's /batch command the same as the Batch API?

No. Claude Code's built-in `/batch` splits a coding task into 5 to 30 independent units and runs a background subagent for each in its own git worktree; it doesn't use the Message Batches API. Sending Claude Code work to the Batch API takes a third-party tool such as claude-batch-toolkit on GitHub, and choosing between the API and Claude Code in the first place is covered in [Claude API vs Claude Code: Which One to Use and How You Pay](https://blog.laozhang.ai/en/posts/claude-api-vs-claude-code).

## Sources

External pages this guide links to, in the order they appear. Last updated 2026-10-30.

- [Batch processing documentation](https://platform.claude.com/docs/en/build-with-claude/batch-processing) (platform.claude.com)
- [Claude API pricing page](https://platform.claude.com/docs/en/about-claude/pricing) (platform.claude.com)
- [Claude API rate limits page](https://platform.claude.com/docs/en/api/rate-limits) (platform.claude.com)
- [Developers Digest production guide](https://www.developersdigest.tech/blog/claude-batch-api-production-guide) (developersdigest.tech)
- [Claude status page history](https://status.claude.com/history) (status.claude.com)
- [Amazon Bedrock](https://aws.amazon.com/bedrock/pricing/) (aws.amazon.com)
- [Vertex AI batch prediction for Claude](https://docs.cloud.google.com/vertex-ai/generative-ai/docs/partner-models/claude/batch) (docs.cloud.google.com)
