Rubric
Contents — domains, guide and mocks

Efficient batch processing

CCAR-F 4.512 min read · checked 21 September 2026

Task statementDesign efficient batch processing strategies

Batch or synchronous?

Is someone or something waiting on the result?
  • A person in a live session
    Synchronous APIchat, agents, support
  • A blocking pipeline step
    Synchronous APIpre-merge checks, deploy gates
  • No — results can arrive later
    Message Batchesbackfills, nightly reports, evals
  • Later, but by a deadline
    Batches on a schedulesized to the 24-hour window
The deciding question is whether anything is blocked waiting for the answer. Cost matters only once that is settled.

What the Message Batches API gives you

The Message Batches API accepts a large set of ordinary Messages API requests in one submission and processes them asynchronously. The documentation lists the terms: a batch costs 50% of standard API prices; most batches complete within an hour, but a batch that has not finished within 24 hours expires; one batch can hold up to 100,000 requests or 256 MB, whichever comes first; and results stay available for 29 days after creation. Almost everything a normal request can do works inside a batch — system prompts, vision, tool use, multi-turn message histories, extended thinking and prompt caching — but streaming does not, because results come back as a single file.

PropertyMessage Batches APIWhat it means for design
Price50% of standardLarge, repeatable workloads get dramatically cheaper
LatencyMost within 1 hour; expires at 24 hoursNo latency guarantee — plan for the worst case
SizeUp to 100,000 requests or 256 MBSplit very large jobs into several batches
Order of resultsNot guaranteedMatch every result by custom_id
StreamingNot supportedNothing arrives until the batch has ended
Results retention29 daysDownload and store results you need to keep

Good fits are the ones the docs name: large-scale evaluations, content moderation, data analysis and bulk generation. In architecture terms, that means backfilling an extraction over an archive, re-scoring last month’s support tickets, generating product descriptions for a catalogue, or running a nightly compliance review. Poor fits are anything a user or a pipeline is blocked on — the answer might take an hour, and on a bad day most of a day.

Running a batch well

The batch lifecycle

  1. Pilot on a samplesynchronous; fix prompt and request shape
  2. Submit the batchone custom_id per document
  3. Poll until endedin_progressended
  4. Sort the resultssucceeded, errored, canceled, expired

resubmit only failed or expired items, fixed where needed

Pilot first so the batch is not wasted on a bad prompt; resubmit only the requests that need it.

Pilot first. The docs recommend dry-running a single request shape with the Messages API to avoid validation errors. Go further: run your prompt synchronously over a representative sample, check the outputs against your criteria (4.1) and validators (4.4), and only then submit ten thousand copies of it. A bad prompt in a batch fails ten thousand times at once — cheaply, but after a long wait.

Give every request a meaningful `custom_id`. Results can come back in any order and may not match the order you submitted, so the custom_id is the only reliable link between a result and its source. It must be 1–64 characters of letters, digits, hyphens and underscores. Use your own identifier — inv-2026-09-000417 — so a result can be joined straight back to the record it belongs to.

Submit, then handle each result typepython
batch = client.messages.batches.create(requests=[
    {"custom_id": doc.id,                       # e.g. "inv-2026-09-000417"
     "params": {"model": MODEL, "max_tokens": 2048,
                "system": SYSTEM_BLOCKS,        # shared prefix, cached
                "tools": [record_invoice],
                "tool_choice": {"type": "tool", "name": "record_invoice"},
                "messages": [{"role": "user", "content": doc.text}]}}
    for doc in documents
])

# ...later, once processing_status == "ended"
retry, fix = [], []
for r in client.messages.batches.results(batch.id):
    match r.result.type:
        case "succeeded":
            save(r.custom_id, r.result.message)          # then validate (4.4)
        case "errored" if r.result.error.error.type == "invalid_request_error":
            fix.append(r.custom_id)                      # request must change first
        case "errored" | "expired":
            retry.append(r.custom_id)                    # safe to resubmit as-is

Resubmit only what failed. A request that succeeded is done; do not rerun the batch. The docs distinguish errors: an invalid_request_error means the request body must be fixed before re-sending, while other errors can be retried directly. expired requests never reached the model and can go into the next batch. Requests that succeeded but failed your own validation go through the retry-with-feedback process from 4.4 — in a follow-up batch if time allows. A common fix for a failed request is structural: a document too long for the context window can be split into sections and resubmitted as several requests.

Designing around the 24-hour window

Because a batch can take up to 24 hours, deadlines have to be designed backwards from the worst case, not the typical one. If a business promises results within 30 hours of a document arriving, the latest a document can join a batch is 6 hours after it arrives — so submitting a batch every 6 hours (or more often) keeps the promise even when a batch takes its full window. Submitting once a day would not: a document arriving just after the daily cut-off could wait almost 24 hours to be submitted and 24 more to finish.

Stacking batch with prompt caching

Batch requests in an extraction job usually share a long prefix — the same tool definitions, the same system instructions, the same few-shot examples — and differ only in the document at the end. The docs say prompt caching and batch discounts stack. To give the cache a chance, put the shared content first and mark it with identical cache_control blocks in every request. Cache prefixes are built in a fixed order: tools, then system, then messages.

Structuring a batch request for cache hits

cache prefix order: top to bottom

  1. Toolsrecord_invoice schema — identical in every request
  2. Systeminstructions, criteria and examples + cache_control
  3. User messagethe one document for this custom_id
Everything above the document is identical across the batch and can be read from cache; only the document is new each time.

Two caveats from the documentation keep expectations honest. Because batch requests run asynchronously and concurrently, cache hits are best-effort — the docs cite hit rates anywhere from 30% to 98% — and they suggest the 1-hour cache duration to improve the odds, since the default lifetime is five minutes. And anything that changes the prefix (a different tool list, a tweaked system prompt per request) breaks sharing, so keep per-document variation out of the cached blocks.

Traps the wrong answers are built from

Tempting but wrongDo this instead
Using batches for blocking or interactive work to save moneyKeep anything a person or pipeline waits on synchronous.
Matching results to inputs by positionSet a meaningful custom_id on every request and join on it.
Re-running the whole batch after some requests failResubmit only errored or expired items, fixing invalid requests first.
Planning deadlines on the typical one-hour completionSize submission frequency against the 24-hour worst case.
Submitting a huge batch with an untested promptPilot on a sample synchronously, then batch.

You should now be able to

  • Decide between the Message Batches API and synchronous calls from latency and blocking requirements.
  • Use custom_id to correlate results and handle each result type correctly.
  • Resubmit only failed items, distinguishing requests that need fixing from those that can be retried.
  • Calculate a submission schedule that meets a deadline under the 24-hour processing window.
  • Structure batch requests so a shared, cached prefix precedes per-document content.

Practice questions

Original questions written for this lesson, in the exam’s style. Answer first, then open the reasoning — every option is explained, including why the wrong ones are tempting.

  1. Question 1

    A team runs two Claude workloads: a check that must pass before a pull request can merge, and an overnight job that summarises every support ticket from the previous day for a morning dashboard.

    Which assignment of APIs is most appropriate?

    1. ABoth on the Batches API, to halve cost across the board.
    2. BBoth synchronous, because batches cannot use tools.
    3. CMerge check synchronous; overnight summaries on the Batches API.
    4. DMerge check on batches with polling every minute; summaries synchronous.
    Show answer and reasoning
    1. AIncorrect. The merge check blocks developers; a batch has no latency guarantee and can take up to 24 hours.
    2. BIncorrect. Batch requests do support tool use; this rules out batching for the wrong reason.
    3. CCorrect. The blocking check needs a prompt answer; the overnight job has hours of slack and benefits from the discount.
    4. DIncorrect. Polling faster does not make a batch finish faster, and the job that could wait is the one left at full price.
  2. Question 2

    A batch of 20,000 extraction requests ends with 19,640 succeeded, 300 errored with invalid_request_error, and 60 expired. The engineer’s first instinct is to resubmit the entire batch.

    What is the best next step?

    1. AResubmit all 20,000 requests so the results are consistent.
    2. BRetry the 360 failed requests unchanged in a new batch.
    3. CDiscard the failed items, since 98% coverage is enough.
    4. DFix the 300 invalid requests, then resubmit them with the 60 expired ones.
    Show answer and reasoning
    1. AIncorrect. It pays again for 19,640 completed requests and delays everything.
    2. BIncorrect. The 300 invalid requests will fail again unless their request bodies are fixed first.
    3. CIncorrect. Silently dropping documents leaves gaps nobody downstream knows about.
    4. DCorrect. Only failed items are resubmitted, and invalid ones are corrected first, as the docs describe.
  3. Question 3

    A compliance team must have each uploaded contract reviewed within 30 hours of upload. They want to use the Batches API to cut cost, and documents arrive at random times throughout the day.

    How often must they submit batches to guarantee the deadline?

    1. AAt least every 6 hours, because a batch can take up to 24 hours.
    2. BOnce a day, because most batches finish within an hour.
    3. COnce every 30 hours, matching the deadline.
    4. DIt cannot be done; batches are unsuitable for any deadline.
    Show answer and reasoning
    1. ACorrect. Worst-case wait before submission plus the 24-hour window must fit within 30 hours, so submissions are needed at least every 6 hours.
    2. BIncorrect. Planning on the typical case breaks the guarantee when a batch takes its full window.
    3. CIncorrect. A document arriving just after a submission could wait 30 hours before it is even sent.
    4. DIncorrect. A deadline longer than the processing window can be met with a frequent enough schedule.
  4. Question 4

    Why should each request in a batch carry a meaningful custom_id?

    1. AIt sets the priority with which requests are processed.
    2. BResults may return in any order, so it is how results are matched.
    3. CIt enables prompt caching across requests in the batch.
    4. DIt is used as the cache key for the compiled schema grammar.
    Show answer and reasoning
    1. AIncorrect. The docs describe no priority mechanism; custom_id is for correlation.
    2. BCorrect. The docs state results may not match submission order, so custom_id is the reliable link.
    3. CIncorrect. Caching depends on identical prefixes and cache_control, not on identifiers.
    4. DIncorrect. Grammar caching is keyed on the schema, not on request identifiers.

Sources

Drafted with AI assistance and checked against the sources above; expert review is in progress. Spotted an error? Tell us and it gets fixed, dated and listed on how this is written.