Message Batches
Purpose and Scope
Message Batches are the SDK surface for sending many independent Messages API creation requests as one asynchronous job. Instead of awaiting each message response inline, a caller creates a batch with a list of request objects, receives a MessageBatch, polls that batch until processing finishes, and then reads individual results. The official API describes batches as starting immediately after creation and taking up to 24 hours to complete, which makes the feature suitable for offline evaluation, bulk summarization, and other workloads where throughput matters more than per-request latency.
In this SDK, the stable entry point is client.messages.batches, implemented by the generated Batches resource under src/resources/messages/batches.ts. A beta-compatible entry point is also available at client.beta.messages.batches, implemented under src/resources/beta/messages/batches.ts. Both resources model the same batch-processing workflow, but the beta variant appends the message-batches-2024-09-24 beta token and supports an explicit betas parameter so callers can compose it with other beta headers.
Sources: src/resources/messages/batches.ts, src/resources/beta/messages/batches.ts
Relevant Source Files
src/resources/messages/batches.ts- Defines the stableBatchesAPI resource, including create, retrieve, list, delete, cancel, and results-oriented behavior for/v1/messages/batches.src/resources/beta/messages/batches.ts- Defines the betaBatchesAPI resource and its beta-header plumbing for the same batch workflow under?beta=true.src/resources/messages/index.ts- Re-exports the stable batch resource and public batch-related TypeScript types from the messages namespace.src/resources/beta/messages/index.ts- Re-exports beta batch resource types, beta parameter types, and the large beta messages type surface.src/resources/beta/messages.ts- Re-exports the beta messages index so the beta namespace can exposemessages.batchesthrough the package tree.src/internal/detect-platform.ts- Provides runtime detection and Stainless telemetry headers used by requests across runtimes, which affects batch calls the same way it affects other SDK API calls.
Core Workflow
A batch request is made of requests, and each item contains a developer-defined custom_id plus params that look like a normal Messages API request. The snippets show max_tokens, messages, and model inside params, and the official API documentation adds that custom_id is used to match results back to submitted requests because results may not be returned in request order. Treat custom_id as your application-level correlation key: make it stable, unique within the batch, and meaningful enough to join results with your source dataset.
The stable creation method is create(params: BatchCreateParams, options?: RequestOptions): APIPromise<MessageBatch>. It strips user_profile_id out of the body, sends the remaining request payload to POST /v1/messages/batches, and conditionally maps user_profile_id to the anthropic-user-profile-id header. That design matters when acting on behalf of another party: attribution is request-level metadata from the caller’s perspective, but it is transmitted as a header that applies to the whole batch. Per-request message parameters remain inside the JSON body.
Sources: src/resources/messages/batches.ts
The beta creation method has the same conceptual shape but additionally separates betas from the body. It sends POST /v1/messages/batches?beta=true and constructs an anthropic-beta header containing any caller-provided beta values plus message-batches-2024-09-24. This means beta batch calls are opt-in at the SDK resource level; callers do not need to remember the exact message-batches beta token when using client.beta.messages.batches.create, but they can still include other beta features when a batch request’s message parameters depend on them.
Sources: src/resources/beta/messages/batches.ts
const batch = await client.messages.batches.create({
requests: [
{
custom_id: 'eval-row-001',
params: {
model: 'claude-opus-4-6',
max_tokens: 1024,
messages: [{ role: 'user', content: 'Hello, world' }],
},
},
],
});Polling, Listing, and Lifecycle Operations
After creation, use retrieve to poll by batch ID. The stable resource calls GET /v1/messages/batches/{messageBatchID} and returns a MessageBatch; the beta resource calls the same path with ?beta=true and beta headers. The generated doc comment explicitly says the retrieve endpoint is idempotent and can be used to poll for completion, and that results are accessed through the results_url field in the response. In practice, this means applications should persist the returned batch ID, poll until processing status reaches a terminal state, and only then fetch or process result rows.
Listing is modeled as a paginated resource rather than a one-shot array. The stable list(query?: BatchListParams, options?: RequestOptions) returns a PagePromise<MessageBatchesPage, MessageBatch> and uses getAPIList('/v1/messages/batches', Page<MessageBatch>, ...). The generated example shows for await (const messageBatch of client.messages.batches.list()), which is the idiomatic SDK pattern for automatically traversing pages. Listing returns the most recently created batches first, so it is useful for dashboards, reconciliation jobs, and recovering a lost batch ID.
Sources: src/resources/messages/batches.ts, src/resources/beta/messages/batches.ts
The lifecycle also includes deletion and cancellation. The stable source snippet documents delete(messageBatchID, options?) and notes that a batch can only be deleted after it has finished processing; to remove an in-progress batch, callers must cancel first. The official cancel endpoint allows cancellation before processing ends and moves the batch into a canceling state while non-interruptible work may finish. Result rows, not just aggregate counts, are the reliable way to determine which individual requests succeeded, errored, expired, or were canceled.
Sources: src/resources/messages/batches.ts
Results Handling
Batch results are not modeled like a normal single JSON response. Both stable and beta batch resource files import JSONLDecoder, and the batch result types exported from the namespace include individual-response and outcome variants such as succeeded, errored, canceled, and expired. That combination reflects the API’s result-delivery model: once a batch has ended, callers fetch the results stream or URL and process JSON Lines records. Each record can then be joined to the original input by custom_id, allowing bulk jobs to tolerate out-of-order results and partial failures.
Because result processing is asynchronous and row-oriented, write consumers as resumable data pipelines rather than assuming an all-or-nothing response. Persist the batch ID and submitted custom IDs before creating the batch. Poll with retrieve, inspect request counts and processing status, then consume result entries and handle each result variant independently. A succeeded result can be parsed like a normal Messages API response, while errored, expired, or canceled results should update the corresponding item in your job store without requiring the entire batch to be retried.
Sources: src/resources/messages/batches.ts, src/resources/beta/messages/batches.ts
API Components
| Component | Stable SDK surface | Beta SDK surface | Notes |
|---|---|---|---|
| Create | client.messages.batches.create(params, options?) | client.beta.messages.batches.create(params, options?) | Sends a list of message creation requests and returns a batch object. |
| Retrieve | client.messages.batches.retrieve(messageBatchID, options?) | client.beta.messages.batches.retrieve(messageBatchID, params?, options?) | Polls batch state by ID; beta accepts beta params. |
| List | client.messages.batches.list(query?, options?) | client.beta.messages.batches.list(params?, options?) | Returns a paginated async iterable of batches. |
| Delete | client.messages.batches.delete(messageBatchID, options?) | client.beta.messages.batches.delete(messageBatchID, params?, options?) | Intended for batches that have finished processing. |
| Cancel | client.messages.batches.cancel(messageBatchID, options?) | client.beta.messages.batches.cancel(messageBatchID, params?, options?) | Initiates cancellation before processing ends. |
| Results | result retrieval uses batch result types and JSONL decoding | beta result retrieval uses beta result types and JSONL decoding | Process individual response rows by custom_id. |
The public types are intentionally re-exported from the messages namespace so application code can import batch shapes without reaching into generated resource files. Stable exports include MessageBatch, MessageBatchRequestCounts, MessageBatchResult, MessageBatchIndividualResponse, DeletedMessageBatch, BatchCreateParams, BatchListParams, and MessageBatchesPage. Beta exports mirror these with beta-prefixed result shapes and add beta-specific parameter types such as BatchRetrieveParams, BatchDeleteParams, BatchCancelParams, and BatchResultsParams. Prefer these exported types for job-store schemas, polling helpers, and typed result consumers.
Sources: src/resources/messages/index.ts, src/resources/beta/messages/index.ts, src/resources/beta/messages.ts
Implementation Details and Runtime Considerations
The batch resources are generated APIResource classes that delegate transport to the shared client via _client.post, _client.get, _client.getAPIList, and _client.delete. Paths are constructed with the SDK’s path template helper for ID-bearing routes, and headers are merged with buildHeaders so per-request RequestOptions headers can participate in the final request. These implementation details are important for advanced users because normal SDK request options, custom headers, middleware, and retry behavior apply to batch operations just as they do to single-message calls.
Runtime detection is centralized in src/internal/detect-platform.ts, which reports language, package version, operating system, architecture, runtime name, and runtime version through Stainless metadata headers. Batch processing itself is server-side API work, but the client request still runs in Node.js, Deno, edge runtimes, browsers when explicitly allowed, or another supported JavaScript environment. If a batch job is long-running, put the polling and result consumption logic in a durable worker or backend process rather than relying on a short-lived browser tab or serverless invocation.
Sources: src/internal/detect-platform.ts, src/resources/messages/batches.ts
Next Steps
Start with the stable client.messages.batches API unless you specifically need beta-only message parameters or beta-managed attribution behavior. Model every submitted item with a unique custom_id, store the batch ID, poll with retrieve, and consume results row by row after completion. For adjacent SDK topics, read the Messages API page to understand the per-request params object, the Streaming Responses page for latency-sensitive workloads, and the Message Batches Reference page when you need the exact generated type names and method signatures.