CertSafari
    Anthropic Claude Certified Developer – Foundations (CCDV-F)· Lessons

    Domain 2 · Lesson 6/25

    Message Batches API and choosing batch over realtime calls

    Claude API Mechanics

    9 min read
    5.52% of exam
    3 sources
    Published 12 Oct 2026
    Docs as of 30 Sep 2026

    What you will be able to do

    • Submit a Message Batch with custom_ids, poll it until it ends, and fetch its results
    • Handle the four batch result types and the limits on size, time and parameters
    • Decide between realtime Messages calls and a batch for a given workload, including how prompt caching behaves in a batch

    1.Submitting, polling and fetching a batch

    A Messages call is the ordinary synchronous request: you send a prompt and wait for a single reply. The Message Batches API runs those same Messages requests asynchronously, in bulk, at half the usual price. You send up to 100,000 requests in one call instead of waiting for each reply in turn, and collect all the answers later. Most batches finish in under an hour. The typical uses are offline jobs: large evaluation runs, moderating a backlog of user content, summarizing a dataset, generating product descriptions.

    Each request in a batch has two parts. custom_id is your own key for the request: 1 to 64 letters, digits, hyphens or underscores. params holds the usual Messages API parameters, the same ones a single synchronous call takes. Because each request is processed independently, one batch can mix vision, tool use, extended thinking and multi-turn conversations. Creating the batch returns its id and a processing_status of in_progress. You poll with that id until the status changes to ended, then download results from the batch's results_url.

    Polling a batch once a minute until processing_status is "ended"python
    import time
    
    client = anthropic.Anthropic()
    
    MESSAGE_BATCH_ID = "msgbatch_01HkcTjaV5uDC8jWR4ZsDV8d"
    
    message_batch = None
    while True:
        message_batch = client.messages.batches.retrieve(MESSAGE_BATCH_ID)
        if message_batch.processing_status == "ended":
            break
    
        print(f"Batch {MESSAGE_BATCH_ID} is still processing...")
        time.sleep(60)
    print(message_batch)

    Batches belong to a Workspace. Any key working in that Workspace can list its batches and read their results, and the list endpoint pages through them for you. A pipeline that loses track of a batch id can therefore find it again by listing.

    Checkpoint 1 of 4· Put it in order

    Put the life of a Message Batch in order

    1. 1.Create the batch with a list of requests, each with a custom_id and params
    2. 2.Poll the batch with retrieve until processing_status is ended
    3. 3.Receive the batch id with processing_status in_progress
    4. 4.Download the results from the batch's results_url

    Sources1

    2.Batch results, limits and unsupported parameters

    Every request in an ended batch has exactly one result, and the batch's request_counts totals them by type. Match each result to its input by custom_id. Only requests that succeeded are billed.

    The four result types of a batched request
    Result typeMeaningBilled?
    succeededRequest was successful; includes the message resultYes
    erroredInvalid request or internal server error; no message createdNo
    canceledBatch was canceled before this request reached the modelNo
    expiredBatch hit its 24-hour expiration before this request reached the modelNo

    A batch that is still processing can be stopped with the cancel endpoint. Right after the call its processing_status is canceling; keep polling until it reaches ended. A canceled batch may contain partial results for requests that were processed before the cancellation, and the rest come back with the canceled result type.

    A batch's limits are measured in time and size. It holds at most 100,000 requests or 256 MB, whichever is reached first. Results become available when every request is done or after 24 hours, whichever comes first, and requests not processed within 24 hours expire. When demand is high, processing slows and more requests expire after 24 hours. Results stay downloadable for 29 days. They can be large, so stream them rather than download the whole file in one go. Because batches run with high concurrency, they can go slightly over a Workspace's spend limit.

    Nearly any Messages request can go into a batch, server tools included, but three parameters return a validation error. stream: true is rejected because results come back as a file. speed (fast mode) is rejected because it tunes synchronous latency. max_tokens: 0 (cache pre-warming) is rejected because the cache entry would likely expire before a follow-up request ran.

    Checkpoint 2 of 4· Check yourself

    A team copies its production request builder into a batch job without changes. The batch fails validation. Which setting in the builder is the most likely cause?

    Sources1

    3.Choosing realtime or batch

    A realtime call is a plain Messages request: synchronous, one reply per request. The rule for choosing between it and a batch comes down to one question: is anyone waiting for the answer? If a user or a downstream step needs the reply in seconds, use a realtime Messages call, streamed when the reply is long. If the work can wait (overnight scoring, a backfill, an evaluation suite), use a batch and pay half. Claude Opus 5.5 costs $4 / $20 per million input/output tokens on realtime calls and $2 / $10 in a batch. Batching also raises throughput, because you are not paying for and pacing thousands of round trips yourself.

    Realtime Messages calls versus the Message Batches API
    ConcernRealtime Messages APIMessage Batches API
    When the answer arrivesIn the response, or streamed as it is generatedMost batches within 1 hour; results available when all requests finish or after 24 hours, and requests still unprocessed then expire
    PriceStandard rates50% of standard prices
    Streaming and fast modeAvailablestream: true and speed are rejected
    Prompt cache hitsPredictable for a stable prefixBest-effort, because requests run concurrently and in any order

    Prompt caching reuses a repeated prompt prefix at reduced cost and latency instead of processing it again. A cache entry lasts 5 minutes by default, refreshed each time it is used, unless you choose the 1-hour lifetime. Caching and batching do combine, but the savings are less predictable. A cache hit needs an earlier request to have written the entry already. In a batch, requests run concurrently and in any order, so many of them start before any entry exists. Even a batch where every request shares one large system prompt can end up hitting the cache well below 100% of the time.

    The documented fix is the 1-hour cache, used with a priming request. Gather the requests that share a prefix, then send a batch containing a single request with that prefix and a 1-hour cache block, which writes the prefix to the cache. As soon as it completes, submit the rest of the requests. You must monitor the job to know when it finishes. This beats the 5-minute cache because batch requests commonly take between 5 minutes and 1 hour.

    Image-heavy jobs have one more limit to respect, and it applies per request, whether realtime or batched. The API accepts 100 images per request for models with a 200k-token context window, and 600 per request for all other models. Claude Opus 5.5 has a 1M-token context window, so it falls under the 600 limit, while Claude Haiku 4.5 (200K) falls under 100.

    Checkpoint 3 of 4· Exam question

    A document-processing application needs to send up to 550 images in a single Messages API request. Which model configuration choice is required to support that volume?

    Checkpoint 4 of 4· Check yourself

    Which workload is the better fit for the Message Batches API rather than realtime calls?

    Sources123

    Exam traps

    Each one states something that sounds right. Open it to see what is actually true.

    1. 1.When every request in a batch shares an identical cached system prompt, the batch should hit the cache almost every time.Why is that wrong?

      Batched requests run concurrently and in any order, so cache hits are best-effort. A 35% hit rate is normal behaviour. The documented way to raise it is to send one priming request with the shared prefix and a 1-hour cache block first, then submit the rest once it completes.

      Covered in Choosing realtime or batch

    2. 2.Errored and expired requests in a batch are still charged at the batch rate.Why is that wrong?

      Only succeeded requests are billed. Errored, canceled and expired requests never created a message and cost nothing.

      Covered in Batch results, limits and unsupported parameters

    Sources

    Every claim above is drawn from one of these pages, quoted as it was written on the date shown.

    1. 1.
      “most batches finishing in less than 1 hour while reducing costs by 50% and increasing throughput.”
      ↩︎ Submitting, polling and fetching a batch
      “Because each request in the batch is processed independently, you can mix different types of requests within a single batch.”
      ↩︎ Submitting, polling and fetching a batch
      “You can poll for the status of the batch and retrieve results when processing has ended for all requests.”
      ↩︎ Submitting, polling and fetching a batch
      “Batches are scoped to a Workspace.”
      ↩︎ Submitting, polling and fetching a batch
      “A Message Batch is limited to either 100,000 Message requests or 256 MB in size, whichever is reached first.”
      ↩︎ Batch results, limits and unsupported parameters
      “Batches expire if processing does not complete within 24 hours.”
      ↩︎ Batch results, limits and unsupported parameters
      “Batch results are available for 29 days after creation.”
      ↩︎ Batch results, limits and unsupported parameters
      “it's recommended to stream results back rather than download them all at once.”
      ↩︎ Batch results, limits and unsupported parameters
      “Fast mode tunes synchronous latency, which doesn't apply to asynchronous batch processing.”
      ↩︎ Batch results, limits and unsupported parameters
      “Canceled batches end up with a status of ended and may contain partial results for requests that were processed before cancellation.”
      ↩︎ Batch results, limits and unsupported parameters
      “All usage is charged at 50% of the standard API prices.”
      ↩︎ Choosing realtime or batch
      “You will not be billed for these requests.”
      ↩︎ Exam trap 2
      “It starts as in_progress, then updates to ended once all the requests in the batch have finished processing, and results are ready.”
      ↩︎ Checkpoint
      “Batch results come back as a single file, not a stream.”
      ↩︎ Checkpoint
      “This approach is well-suited to tasks that do not require immediate responses”
      ↩︎ Checkpoint
    2. 2.
      “The 1-hour cache can help improve your cache hits.”
      ↩︎ Choosing realtime or batch
      “because asynchronous batch requests can be processed concurrently and in any order, cache hits are provided on a best-effort basis.”
      ↩︎ Choosing realtime or batch
      “Send a batch request with a single request that has this shared prefix and a 1-hour cache block.”
      ↩︎ Choosing realtime or batch
      “By default, the cache has a 5-minute lifetime.”
      ↩︎ Choosing realtime or batch
      “because asynchronous batch requests can be processed concurrently and in any order, cache hits are provided on a best-effort basis.”
      ↩︎ Exam trap 1
    3. 3.
      “100 per request on the API, for models with a 200k-token context window.”
      ↩︎ Choosing realtime or batch
      “600 per request on the API, for all other models.”
      ↩︎ Choosing realtime or batch

    Ready to test yourself?

    Practise the 20 questions on this subdomain.

    Spotted a mistake, or was something unclear? Tell us.