OpenRouter allows you to batch requests1. Providers discount batch traffic to fill idle capacity, and OpenRouter passes the discount through to the client. The examples use Claude Sonnet 5, where batched requests costs 50% of the regular API pricing.

Synchronous API

PageIn / Out per 1M
Sync$2.00 / $10.00
results = []
for doc in docs:
    response = client.chat.completions.create(
        model="anthropic/claude-sonnet-5",
        messages=[{"role": "user", "content": f"Summarize: {doc}"}],
    )
    results.append(response.choices[0].message.content)

Asynchronous Batch API

PageIn / Out per 1M
Batch$1.00 / $5.00

The batch route bills at exactly half the sync rate.

batch = requests.post(
    "https://openrouter.ai/api/beta/batches",
    headers={"Authorization": f"Bearer {key}"},
    json={
        "endpoint": "/v1/chat/completions",
        "model": "anthropic/claude-sonnet-5",
        "requests": [
            {
                "custom_id": f"doc-{i}",
                "body": {"messages": [{"role": "user", "content": doc}]},
            }
            for i, doc in enumerate(docs)
        ],
    },
)

# Poll GET /api/beta/batches/:id until status == "completed".
# The finished results come back inline, matched by custom_id.

What the same workload costs

For example, classifying 10,000 support tickets at 1,000 input tokens and 200 output tokens each lands us at 10M input tokens and 2M output tokens:

RouteIn $/1MOut $/1MCost (10M in + 2M out)
Sync$2.00$10.00$40.00
Batch$1.00$5.00$20.00

The batch route costs 50% of the sync price and saves $20.00 on one job. Run the same job weekly and batch saves $1,040 a year on this model alone.

Embeddings

The batch endpoint also covers /v1/embeddings, with inputs as strings or token arrays. The Embeddings API reference documents the request and response shape.

In Rust: openrouter-batch

I packaged this flow as openrouter-batch, a small Rust client for the Batch API, structured output, and embeddings (docs.rs).

The demo is two questions, one shared strict JSON Schema, submitted as a batch to a :batch model. The examples/cli.rs binary runs it against the live API:

cargo run --release --example cli -- batch

Output from my run β€” status transitions, counts, usage, then each decoded result line keyed by custom_id:

submitted: batch-1788203224-A92OrCi1hb82JNrfN6M1 status: Validating
status: InProgress
status: Completed
request_counts: Some(RequestCounts { total: 2, completed: 2, failed: 0 })
usage: Some(BatchUsage { prompt_tokens: Some(52), completion_tokens: Some(27), total_tokens: Some(79), cost: Some(2.13e-5), is_byok: Some(false) })
req-1: {"answer": "4", "confidence": 99}
req-2: { "answer": "21", "confidence": 1 }

The whole run cost $0.0000213.

Footnotes

  1. OpenRouter's Batch API Quickstart covers submission, polling, limits, and pricing. ↩