// Message Batches lifecycle with the official TypeScript SDK. // STATUS: LIVE_VERIFIED 2026-09-18 (identical HTTP sequence executed via scripts/live.py; SDK calls map 1:1). // Model: claude-haiku-4-5-20251001, max_tokens 8 (~$0.0001 at 50 % batch pricing). // Run: node --env-file=.env --experimental-strip-types examples/anthropic/batch/batch_lifecycle.ts import Anthropic from "@anthropic-ai/sdk"; const MODEL = "claude-haiku-4-5-20251001"; const client = new Anthropic(); // reads ANTHROPIC_API_KEY const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms)); const req = (custom_id: string, model: string) => ({ custom_id, params: { model, max_tokens: 8, messages: [{ role: "user" as const, content: "Reply with OK." }] }, }); // 1. create — invalid model is accepted here and becomes an `errored` result let batch = await client.messages.batches.create({ requests: [req("ok-1", MODEL), req("bad-model-1", "claude-does-not-exist-1")] }); console.log("created", batch.id, batch.processing_status, batch.request_counts); // 2. list (auto-paginating async iterator) / retrieve for await (const b of client.messages.batches.list({ limit: 1 })) { console.log("list ->", b.id); break; } // 3. poll (every 20 s, ≤ 5 min). Observed ~100 s for 2 requests. const t0 = Date.now(); while (batch.processing_status !== "ended" && Date.now() - t0 < 300_000) { await sleep(20_000); batch = await client.messages.batches.retrieve(batch.id); console.log(` ${Math.round((Date.now() - t0) / 1000)}s ${batch.processing_status}`, batch.request_counts); } // 4. results — JSONL stream, unordered for await (const entry of await client.messages.batches.results(batch.id)) { const r = entry.result; if (r.type === "succeeded") console.log(entry.custom_id, "succeeded", r.message.usage.service_tier); else if (r.type === "errored") console.log(entry.custom_id, "errored", r.error.error.type); else console.log(entry.custom_id, r.type); // canceled | expired } // 5. delete (400 while in_progress/canceling) console.log("delete", (await client.messages.batches.delete(batch.id)).type); // 6. cancel path let b2 = await client.messages.batches.create({ requests: [req("cancel-1", MODEL)] }); b2 = await client.messages.batches.cancel(b2.id); console.log("cancel ->", b2.processing_status, b2.cancel_initiated_at); const t1 = Date.now(); while (b2.processing_status !== "ended" && Date.now() - t1 < 240_000) { await sleep(15_000); b2 = await client.messages.batches.retrieve(b2.id); } console.log("after cancel", b2.request_counts); console.log("delete #2", (await client.messages.batches.delete(b2.id)).type);