CClaude Cert Prep
ExplainerCCAR-P · P18 min read

The Message Batches API, Explained

What Batches is, when to use it, and the myth that batch jobs cannot use tools.

The short answer

The Message Batches API processes large sets of Messages API requests asynchronously at about 50% of standard cost, with results typically within an hour and always within 24 hours. It supports everything the sync API does — tool use, vision, prompt caching, and multi-turn conversations. Use it for bulk, non-blocking work. It is the wrong choice for a user's real-time request path, which needs the synchronous API.

The Message Batches API exists for one job: run a large volume of independent Messages API requests when you do not need the answers this second. In exchange for giving up real-time latency, you pay roughly half the standard token price and let Anthropic process the batch in the background. It is the right tool for evaluations, bulk classification, dataset labeling, content generation at scale, and any workload where throughput and cost matter more than immediacy.

This explainer is answer-first, so lead with the shape of it: Batches is asynchronous bulk processing at about 50% cost, with results usually within an hour and guaranteed within 24 hours, and it supports the full Messages API feature set including tool use and multi-turn. The two things people most often get wrong are treating batch as a real-time path (it is not) and believing batch jobs cannot use tools (they can). We cover how it works, the core facts, the sync-versus-batch decision, and the cost math.

What the Batches API is

Batches is a supporting endpoint layered on top of the Messages API. Instead of sending one request and blocking for one response, you submit many requests as a single batch and retrieve the results later. Each request in the batch is an ordinary Messages API call — same model, same message shape, same parameters — wrapped with a custom_id you assign so you can match answers back to inputs.

  • Asynchronous: you submit, then poll, then retrieve — you never hold a connection open waiting.
  • Roughly 50% cheaper than standard pricing on all token usage in the batch.
  • Up to 100,000 requests or 256 MB per batch.
  • Most batches finish within an hour; the maximum is 24 hours.
  • Results remain available for 29 days after the batch is created.
  • Every Messages API feature is supported — vision, tools, prompt caching, structured outputs, and multi-turn conversations.

How it works: submit, poll, retrieve

The lifecycle has three stages. You create the batch with a list of requests, each carrying a custom_id and a params object identical to what you would pass to a single Messages API call. You then poll the batch's processing_status until it reads "ended". Finally you stream the results, matching each one back to its custom_id and checking whether it succeeded.

code
{
  "requests": [
    {
      "custom_id": "classify-001",
      "params": {
        "model": "claude-opus-4-8",
        "max_tokens": 64,
        "messages": [
          { "role": "user", "content": "Classify sentiment (one word): The product is excellent!" }
        ]
      }
    },
    {
      "custom_id": "classify-002",
      "params": {
        "model": "claude-opus-4-8",
        "max_tokens": 64,
        "messages": [
          { "role": "user", "content": "Classify sentiment (one word): Terrible service, never again." }
        ]
      }
    }
  ]
}

// Each result carries your custom_id and a result.type:
//   "succeeded" -> read result.message.content
//   "errored"   -> inspect result.error (fix and resubmit, or retry)
//   "canceled"  -> the batch was canceled
//   "expired"   -> not completed within 24h; resubmit
  • Create: POST the requests; the response gives you a batch id and an initial processing_status.
  • Poll: retrieve the batch by id and check processing_status until it is "ended".
  • Retrieve: stream the results; each has a custom_id and a result whose type is succeeded, errored, canceled, or expired.
  • You can cancel a batch in flight; its status moves to "canceling".

Sync vs. batch: which to use

The deciding question is whether a human is waiting. If a user is staring at a screen expecting a reply, that is a real-time path and it must use the synchronous Messages API. Batches trades latency for cost and throughput, so it fits work that can complete minutes or hours later without anyone blocked.

DimensionSynchronous Messages APIMessage Batches API
LatencySeconds — real-timeUp to 24 hours (usually under 1h)
CostStandard token pricingAbout 50% of standard
ShapeOne request, one responseUp to 100,000 requests per batch
Best forChat, live agents, anything a user waits onBulk classification, evals, labeling, offline generation
Feature supportFull Messages APIFull Messages API (tools, vision, caching, multi-turn)

The tool-use myth

A common misconception is that batch jobs are text-only and cannot use tools. That is false. Because each request in a batch is a full Messages API call, it can include tool definitions, tool_choice, images, prompt caching, and multi-turn message histories — everything the synchronous API supports.

  • Tool use works: include tools and tool_choice in a request's params just as you would synchronously.
  • Multi-turn works: a request's messages array can carry a full prior conversation, including assistant and tool_result turns.
  • Prompt caching works and pairs especially well with batches — a large shared system prompt across many requests is cached, compounding the savings.
  • Vision and structured outputs work too.

The cost math

The batch discount is roughly 50% off standard input and output token pricing, applied to every request in the batch. On a large offline workload the savings are simply half the sync bill — and they stack with prompt caching, since cache reads are already far cheaper than full-price input.

ScenarioSync costBatch cost
10,000 requests, 1,000 input tokens each on a $5/1M input model~$50 input~$25 input
Same, with a large shared cached prefixCache read + $25 uncached remainderAbout half of that again
A single user's live chat turnCorrect — pay standard for speedWrong choice — do not batch

Key takeaways

  • →Batches is asynchronous bulk processing at about 50% of standard cost, with results usually within an hour and always within 24 hours.
  • →It supports the full Messages API feature set — tool use, vision, prompt caching, and multi-turn — not just plain text.
  • →The lifecycle is submit, poll processing_status until "ended", then retrieve results keyed by your custom_id.
  • →Results come back in any order and each has a type of succeeded, errored, canceled, or expired — handle every case.
  • →Use Batches for bulk, non-blocking work; never put a user's real-time request on it — that needs the synchronous API.
  • →The tool-use myth is false: batch requests can define tools and carry full multi-turn histories; they just do not run a live tool loop mid-request.
  • →Batch savings stack with prompt caching, making large shared-context jobs dramatically cheaper.

Now practice it

Reading builds recognition; practice builds judgment. Try these on the P1 material.

Frequently asked

How much does the Batches API save?

About 50% off standard pricing on all token usage in the batch — input and output. The discount applies to every request in the batch and stacks with prompt caching's cheaper cache reads.

How long does a batch take?

Most batches finish within an hour, and the maximum is 24 hours. Anything not completed in 24 hours is marked expired and should be resubmitted. This is why batch is unsuitable for real-time work.

Can batch requests use tools?

Yes. Each request in a batch is a full Messages API call, so it can include tool definitions, tool_choice, vision, prompt caching, and multi-turn histories. The nuance is that a batch does not run a live interactive tool loop mid-request — you assemble the full conversation up front.

When should I NOT use Batches?

Whenever a human is waiting on the answer. Chat turns, live agents, checkout confirmations, and any latency-sensitive path must use the synchronous Messages API. Batches can take up to 24 hours and is for offline, non-blocking work.

How do I match batch results to my inputs?

By the custom_id you assign to each request. Results come back in any order, so never rely on position — always key on custom_id. Also check each result's type (succeeded, errored, canceled, expired) before reading the message.

All explainers

Independent, unofficial study material from Claude Cert Prep. Not affiliated with Anthropic.