AI agents · · 6 min read
Claude Message Batches: submit and reconcile offline AI work with Python
Send a small batch of fictional business briefs, save its receipt, and reconcile every result by ID before using AI-generated summaries.
By Sociologix Editorial

Move work that can wait out of the chat window
Consider a proposed nightly task: turn a set of approved business briefs into short summaries for a team to review the next morning. The reader does not need a live typing response for every brief. Claude’s Message Batches API processes requests asynchronously, making this a different workflow from an interactive customer-care conversation. [1]
This AI-assisted editorial tutorial uses official documentation checked October 5, 2026. The examples’ local control flow was tested on Python 3.13.15 with synthetic SDK responses. The actual SDK was not installed for those tests, and no live batch, model evaluation or paid API request was run. Treat the API steps as documentation-based instructions, not measured performance results.
1. Start with two fictional briefs
Use an isolated project directory and Python 3.10 or later. Install the official package with python -m pip install anthropic. Configure ANTHROPIC_API_KEY securely in your environment and set CLAUDE_MODEL to an active model ID available to your account. Do not put either configuration into a public website bundle. The SDK reads the API key from the environment. [2]
Running the submission script below creates billable model work in your account. Check your chosen model’s current API pricing before running it. Begin with the two fictional inputs supplied here; postpone real customer documents until you have approved their use and reviewed the feature’s data handling.
Each request needs a unique custom_id within its batch. The documented format allows 1–64 alphanumeric, hyphen or underscore characters. Use opaque identifiers, not email addresses or client names. The params object contains the model, message and output limit. [3]
2. Submit once and keep the receipt
Save this first block as submit_batch.py and run python submit_batch.py once. It creates batch-receipt.json before calling the service. Exclusive file creation blocks another invocation in the same directory from submitting the demonstration again. This is a local teaching safeguard, not a distributed job ledger.
The client disables automatic retries for this submission. The SDK otherwise retries certain failures by default. If the call fails after the server received it, the absence of a response does not prove no batch exists. [2]
If the receipt remains in submitting state, or is unreadable after a crash, stop and reconcile in Claude Console. Do not delete it simply to make the script run again. Once a batch ID is saved, use that ID for status checks rather than creating replacement work.
import json
import os
from pathlib import Path
from anthropic import Anthropic
client = Anthropic(max_retries=0)
model = os.environ['CLAUDE_MODEL']
items = {
'brief-001': 'A fictional shop wants weekly inventory summaries.',
'brief-002': 'A fictional studio wants to organize website inquiries.',
}
requests = [
{'custom_id': key, 'params': {
'model': model,
'max_tokens': 200,
'system': 'Summarize the business need in two sentences. Do not invent details.',
'messages': [{'role': 'user', 'content': text}],
}}
for key, text in items.items()
]
# Exclusive creation blocks accidental reruns in this directory.
with Path('batch-receipt.json').open('x', encoding='utf-8') as receipt:
receipt.write(json.dumps({'state': 'submitting', 'ids': list(items)}))
receipt.flush()
batch = client.messages.batches.create(requests=requests)
receipt.seek(0)
receipt.write(json.dumps({'state': 'submitted', 'batch_id': batch.id,
'ids': list(items)}))
receipt.truncate()
print(batch.id)3. Collect only after processing ends
Save the next block as collect_batch.py in the same directory. Run python collect_batch.py to check the saved batch. If it is still processing, check again later; this script deliberately avoids an endless polling loop. A production scheduler should use a bounded interval and persist its progress.
Once processing ends, the results endpoint returns JSONL records. Their order is not guaranteed, so join them to your inputs using custom_id. The collector also checks that every expected ID appears exactly once. It writes to a partial file and replaces the final file only after that check passes. [4]
Run one collector at a time in this demonstration directory. If a download is interrupted, investigate the partial file before rerunning; the next collection attempt overwrites that partial file. The completed file remains untouched until a complete matching result set has been collected.
import json
from pathlib import Path
from anthropic import Anthropic
receipt = json.loads(Path('batch-receipt.json').read_text(encoding='utf-8'))
if 'batch_id' not in receipt:
raise SystemExit('Submission outcome unknown; reconcile in Claude Console.')
client = Anthropic()
batch = client.messages.batches.retrieve(receipt['batch_id'])
if batch.processing_status != 'ended':
print(batch.processing_status)
raise SystemExit('Check again later; do not submit a new batch.')
expected = set(receipt['ids'])
seen = set()
partial = Path('batch-results.partial.jsonl')
with partial.open('w', encoding='utf-8') as output:
for row in client.messages.batches.results(receipt['batch_id']):
if row.custom_id not in expected or row.custom_id in seen:
raise ValueError('Unexpected or duplicate result ID')
seen.add(row.custom_id)
output.write(json.dumps(row.model_dump(mode='json')) + '\n')
if seen != expected:
raise ValueError('Missing results; keep partial file for investigation')
partial.replace('batch-results.jsonl')
print('Saved all expected results; inspect each result.type before using it.')4. Separate transport success from usable output
A batch’s ended status does not mean every request succeeded. Individual outcomes can be succeeded, errored, canceled or expired. Inspect each result.type, and preserve error details for diagnosis instead of treating a failure as an empty summary. [1]
For succeeded items, inspect result.message.content and result.message.stop_reason. An output stopped by max_tokens can be incomplete; a refusal is different from an ordinary completed turn. These need review before the summary enters a business system. [5]
The collector intentionally stores the full result record instead of printing generated text into logs. For a real application, protect that file and its retention period. Create a separate review report with the input ID, result type, stop reason and a decision such as approve, revise or investigate. Those review decisions are your application’s policy, not API statuses.
- Check factual consistency against the original brief before approving a summary.
- Fix invalid requests before retrying; do not resubmit the entire batch to recover one failed item.
- Keep a record of retry attempts and their relationship to the original request.
- Confirm that automation downstream cannot mistake a saved result for permission to email, quote or update a CRM.
5. Set an operating window and a recovery plan
Anthropic documents a 24-hour processing window, with results available for 29 days from batch creation. Download the results into your approved storage within that window. Do not design a time-critical customer response around an assumed completion time. [1]
The local tests exercised receipt creation, rerun blocking, pending status, out-of-order records and all four outcome labels. They also rejected missing, duplicate and unknown result IDs and preserved an existing final file when reconciliation failed. These checks validate our file-handling logic; they do not validate service authentication, model access, real API serialization or summary quality.
Before scaling, run your own small authorized batch and record the SDK version, model ID, submitted IDs, batch ID and observed outcomes. Review access, retention and the handling of uncertain submissions. The useful milestone is a batch you can account for item by item, including failures—not the largest batch you can submit.
Sources & further reading
Turn offline AI work into an accountable process
Sociologix can help connect document intake, batch processing, result review and business-system handoffs. Bring one recurring workload and the checks your team needs before trusting its output.
Talk to Sociologix