Message Batches API¶
Run a large set of Messages API requests asynchronously, at a lower price than the synchronous API, through the Anthropic Message Batches API shape.
The requests are sent inline, the batch runs without a connection held open, and its results are streamed back as JSONL — exactly the Anthropic workflow, so the official Anthropic SDKs work by changing the base URL.
Why Choose the Message Batches API?¶
-
Lower Price per Token
Batched requests are billed at the published batch rate, well below the on-demand rate for the same model. -
Drop-in Anthropic Compatibility
client.messages.batches.create(...)and.results(...)work unchanged. -
Several Models, One Batch
Each request names its own model, as upstream allows; the batch reports a single aggregate state. -
Private AWS Backend
Requests and results are stored in your own S3 buckets — no traffic to third-party endpoints.
Available Endpoints¶
| Endpoint | Method | What It Does | MCP Tool |
|---|---|---|---|
/anthropic/v1/messages/batches |
POST |
Create a batch from inline requests | anthropic_message_batch |
/anthropic/v1/messages/batches |
GET |
List batches, newest first | anthropic_message_batch_list |
/anthropic/v1/messages/batches/{id} |
GET |
Retrieve a batch and its counters | anthropic_message_batch_get |
/anthropic/v1/messages/batches/{id}/results |
GET |
Stream the results as JSONL | anthropic_message_batch_results |
/anthropic/v1/messages/batches/{id}/cancel |
POST |
Cancel a batch that is still processing | anthropic_message_batch_cancel |
/anthropic/v1/messages/batches/{id} |
DELETE |
Delete a batch that has ended | anthropic_message_batch_delete |
Feature Compatibility¶
| Feature | Status | Notes |
|---|---|---|
| Creation | ||
requests[].custom_id |
Up to 64 characters, unique within the batch | |
requests[].params |
Same parameters as Messages | |
| Several models in one batch | Up to 8, each needing the 100-request minimum | |
tools / tool_choice |
Refused when the batch is created — tool use is not available in a batch | |
| Structured output schema | Refused when the batch is created | |
stream |
A batch has nothing to stream to | |
cache_control |
Accepted and ignored — a batch reads and writes no prompt cache, and the request is answered without one | |
| Lifecycle | ||
| Retrieve / poll | in_progress → canceling → ended |
|
| Results (JSONL) | Streamed; available once processing_status is ended |
|
| Cancel | Requests that already produced a Message keep it, the ones that never ran are reported canceled; cancelling twice, or cancelling a batch that has ended, changes nothing |
|
| Delete | Only once the batch has ended — cancel it first, as upstream requires | |
| List batches | Newest first, with before_id / after_id cursors |
|
archived_at |
Results stay readable until the batch is deleted |
Legend:
- Supported — Fully compatible with Anthropic API
- Partial — Supported with limitations
- Unsupported — Not available in this implementation
results_url and Reverse Proxies
results_url is an absolute URL on the address the request came in on, so client.messages.batches.results(...) works with no extra configuration and a client fetching it outside the SDK gets a URL it can dial as-is. Behind a reverse proxy it names the proxy's own origin, taken from the Host and X-Forwarded-Proto headers — enable ENABLE_PROXY_HEADERS so the forwarded scheme is trusted, or a TLS-terminating proxy yields an http:// URL.
Content Guardrails and Batches
A request that a guardrail would apply to is refused rather than run unguarded. Send those requests without batching.
Prompt Caching and Batches
Batched requests neither read nor write a prompt cache, on any model. A request carrying cache_control is still accepted and answered — the hint is dropped rather than the request — so a result reports no cache_read_input_tokens and no cache_creation_input_tokens. Nothing is lost by leaving it in: batched requests are already billed at the batch rate, and the cache discount was never available at that rate.
Model Support¶
Any chat model available for batch inference in your configured Amazon Bedrock regions can be used — the same identifiers as Messages. To shortlist them, call search_models with route=anthropic_message&batch=true; each entry also carries a batch field.
The shortlist is a hint, not a rule
batch is advertised on a best-effort basis and never used to reject a request. A model it does not advertise — or says nothing about — may still run a batch, so submit the batch rather than ruling the model out; the answer you get back is the authoritative one.
A model that cannot serve batched requests is refused when the batch is created, naming the model; no sibling job is left running. A model this deployment normally serves through another Amazon Bedrock endpoint is batched under the identifier the batch endpoint knows it by, so it needs nothing from you.
Workflow¶
1. Create the batch¶
from anthropic import Anthropic
client = Anthropic(base_url="https://your-host/anthropic", api_key="...")
batch = client.messages.batches.create(
requests=[
{
"custom_id": f"req-{index}",
"params": {
"model": "amazon.nova-micro-v1:0",
"max_tokens": 256,
"messages": [{"role": "user", "content": text}],
},
}
for index, text in enumerate(documents)
]
)
Example request (curl):
curl -X POST "https://your-host/anthropic/v1/messages/batches" \
-H "x-api-key: $API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "Content-Type: application/json" \
-d '{
"requests": [
{
"custom_id": "req-1",
"params": {
"model": "amazon.nova-micro-v1:0",
"max_tokens": 256,
"messages": [{"role": "user", "content": "Summarize: ..."}]
}
}
]
}'
The samples above are abridged: a real batch needs at least 100 requests for each model it names.
Example response:
{
"id": "msgbatch_06fvfg3lbdqarbad8kbo55g0sg5h3s4a",
"type": "message_batch",
"processing_status": "in_progress",
"request_counts": {"processing": 100, "succeeded": 0, "errored": 0, "canceled": 0, "expired": 0},
"created_at": "2026-08-12T20:53:33Z",
"expires_at": "2026-08-13T20:53:33Z"
}
2. Poll until processing ends¶
batch = client.messages.batches.retrieve(batch.id)
print(batch.processing_status, batch.request_counts)
succeeded and errored move as the batch runs, so they can drive a progress bar. canceled and expired are known only once processing_status is ended.
3. Read the results¶
for entry in client.messages.batches.results(batch.id):
if entry.result.type == "succeeded":
print(entry.custom_id, entry.result.message.content[0].text)
Each line pairs a custom_id with its outcome:
{"custom_id": "req-1", "result": {"type": "succeeded", "message": {"id": "msg_req-1", "type": "message", "role": "assistant", "content": [{"type": "text", "text": "..."}], "stop_reason": "end_turn", "usage": {"input_tokens": 22, "output_tokens": 9}}}}
{"custom_id": "req-2", "result": {"type": "errored", "error": {"type": "error", "error": {"type": "invalid_request_error", "message": "..."}}}}
Results Are Not in Request Order
Result lines may come back in any order, as upstream also warns. Match a result to its request with custom_id, never with the line number.
Limits¶
| Limit | Value |
|---|---|
| Minimum requests per model | 100 (default quota) |
| Maximum requests per batch | 100,000 |
| Distinct models per batch | 8 |
| Processing window | 24 hours from creation |
A batch below the minimum, or over the model cap, is refused when it is created and the message names the shortfall — a batch naming several models must reach the minimum for each of them.
The 100-request minimum is a quota default
100 is the default of the Amazon Bedrock quota Minimum number of records per batch inference job, which is set per model and adjustable for some of them — see Amazon Bedrock quotas. The gateway checks against that default, not against your account's own value, so a raised quota is enforced by Amazon Bedrock rather than here — a model given 150 requests clears this check and is then refused by the backend — and a lowered one is not usable: fewer than 100 requests for a model is still refused here.
Prerequisites¶
The Message Batches API is disabled until the deployment declares an AWS IAM service role that Amazon Bedrock assumes to read the requests and write the results:
AWS_BEDROCK_BATCH_ROLE_ARN— the service role.AWS_S3_BUCKET— the bucket holding the batch data.AWS_S3_BATCHES_PREFIX— the prefix it is stored under.
The permissions the role and the server need are listed in IAM Permissions.
While the role is unset, every batch endpoint answers 529.
Billing¶
Batched requests are billed at the published batch rate for the model, roughly half the on-demand rate. Usage is recorded once, when the batch ends. See Cost Management.
See Also¶
- Messages API — the per-request parameters
- Batch API — the OpenAI-shaped equivalent
- Configuration — enabling batches