← Blog

Claude API Batch Processing: Multiple Prompts Guide

2026-10-15 · 5 min read · SubToAPI Team

What "batch processing" means for the Claude API

If you're searching for this, you likely have a list of prompts — product descriptions to rewrite, support tickets to classify, documents to summarize — and you need Claude to process all of them without writing a fragile for-loop that takes hours or gets rate-limited halfway through.

There are two real approaches: run requests concurrently with your own code (fast, works today, good for interactive or near-real-time workloads), or use Anthropic's native Message Batches API (asynchronous, cheaper per token, designed for large jobs that can wait hours). This article covers both, plus the practical details — concurrency limits, retries, cost control — that actually determine whether your batch job finishes successfully.

Option 1: Concurrent requests (fast, synchronous-ish)

For a few dozen to a few thousand prompts where you want results within minutes, the simplest approach is firing requests in parallel with a concurrency cap. A naive Promise.all over 500 prompts will blow through your rate limit immediately, so you need a worker pool.

async function processBatch(prompts, concurrency = 5) {
  const results = [];
  let index = 0;

  async function worker() {
    while (index < prompts.length) {
      const i = index++;
      const prompt = prompts[i];
      try {
        const res = await fetch("https://api.anthropic.com/v1/messages", {
          method: "POST",
          headers: {
            "x-api-key": process.env.CLAUDE_API_KEY,
            "anthropic-version": "2023-06-01",
            "content-type": "application/json",
          },
          body: JSON.stringify({
            model: "claude-sonnet-4-5",
            max_tokens: 1024,
            messages: [{ role: "user", content: prompt }],
          }),
        });
        const data = await res.json();
        results[i] = data.content[0].text;
      } catch (err) {
        results[i] = { error: err.message };
      }
    }
  }

  await Promise.all(Array.from({ length: concurrency }, worker));
  return results;
}

This pattern — a shared index, N workers pulling from it — is the standard way to throttle concurrency in Node without a dependency. Tune concurrency based on your rate limit tier; start at 3–5 and increase only after you've confirmed you're not hitting 429s.

Handling rate limits and retries

Batch jobs fail in predictable ways: 429 (rate limited), 529 (overloaded), and occasional timeouts on long completions. Always wrap the request in retry logic with exponential backoff:

async function withRetry(fn, maxAttempts = 5) {
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    try {
      return await fn();
    } catch (err) {
      if (attempt === maxAttempts) throw err;
      const delay = Math.min(1000 * 2 ** attempt, 30000);
      await new Promise((r) => setTimeout(r, delay));
    }
  }
}

Skipping this step is the single most common reason batch jobs silently drop results — a transient 429 on prompt #340 of 1000 kills the whole run if you don't catch it.

Option 2: Anthropic's Message Batches API (large, async jobs)

For truly large volumes — tens of thousands of prompts — Anthropic offers a native batch endpoint that accepts a list of requests, processes them asynchronously (typically within 24 hours), and bills at a reduced rate. You submit a JSON array of individual message requests, each with a custom_id, poll the batch status, and retrieve results once it's complete. This is the right tool when latency doesn't matter and cost per token does — think nightly data enrichment jobs or one-time dataset labeling, not user-facing features.

The tradeoff: no streaming, no immediate response, and you need polling or webhook logic to know when it's done. For anything interactive, stick with concurrent synchronous calls.

Keeping costs and output quality under control

A few things matter more at batch scale than in single-request testing:

Simplifying auth and usage tracking across a batch job

One friction point when running large batch jobs — especially across a team or multiple services — is managing raw provider API keys, watching separate rate limits, and reconciling usage after the fact. SubToAPI sits in front of your Claude access and gives you scoped sub_live_ keys per project, so a batch worker, a staging environment, and a teammate's script can each have their own key with its own usage metadata, without sharing a single provider credential.

The request shape is the same /v1/messages call, just pointed at SubToAPI's endpoint:

curl https://api.subtoapi.app/v1/messages \
  -H "Authorization: Bearer $SUBTOAPI_KEY" \
  -H "content-type: application/json" \
  -d '{
    "model": "claude-sonnet-4-5",
    "max_tokens": 1024,
    "messages": [{"role": "user", "content": "Summarize this ticket: ..."}]
  }'

You can drop this straight into the worker pool pattern above — same concurrency logic, same retry logic, just a different base URL and key. Usage per key shows up in the dashboard, which is useful when you're running batch jobs across multiple projects and need to know which one is actually driving spend. See the quickstart and messages docs for the full request reference, and pricing for plan details if you're scaling this beyond a single key.

Putting it together

For most product and automation use cases, the concurrent-worker-pool pattern with retries covers 90% of "process a list of prompts through Claude" needs — it's simple, synchronous enough to reason about, and fast enough for most pipelines. Reserve the native Message Batches API for genuinely large, latency-insensitive jobs where the cost savings outweigh the added complexity of async polling.

Questions

Can I send multiple prompts in a single Claude API request? No — each /v1/messages call processes one conversation. To handle multiple independent prompts, send separate requests, either concurrently with a worker pool or via Anthropic's asynchronous Message Batches API for very large jobs.

What's the safest concurrency level for batch jobs? Start at 3–5 simultaneous requests and increase gradually while watching for 429 responses. The right number depends on your rate limit tier, not a fixed rule — always pair concurrency with retry/backoff logic.

Is the Message Batches API cheaper than regular requests? Yes, it's priced lower per token in exchange for asynchronous processing (results within hours, not seconds). Use it for bulk, non-interactive jobs; use synchronous requests for anything user-facing.

Turn your Claude access into an HTTPS API

SubToAPI gives you application API keys, streaming, tool use and usage insights on top of your existing Claude access — set up in minutes.

Start free  Read the quickstart →