Skip to content

OpenAI compatibility

BatchRouter speaks the OpenAI Batch contract: the same JSONL request shape, file uploads, and batch lifecycle you already use. Point your batch workflow at BatchRouter with a br_live_ key and BatchRouter routes each job across many providers (with SLA-aware lanes and routing receipts) instead of pinning you to one.

This guide shows what carries over unchanged, what to swap, and the BatchRouter-only extras you can opt into.

If you already run OpenAI batch jobs, these map directly onto BatchRouter:

  • The JSONL / item input shape. Each item’s input accepts the OpenAI-Batch-compatible body — messages, input, or an embeddings input field. You can keep your existing line shape.
  • Files + batches. Upload large JSONL inputs with POST /v1/files, then reference the returned file_id as input_file_id when you create the batch — the same two-step flow as the OpenAI Batch API.
  • The lifecycle. Create a batch, poll it to a terminal status, then fetch results — conceptually identical to create → poll → retrieve.

Here is the canonical BatchRouter item. It is the same JSONL you would build for OpenAI batch, with a customer_item_id so you can join results back to your rows (model is illustrative — list real models via GET /v1/catalog/models):

{"customer_item_id":"item-1","operation":"responses","model":"gpt-4o-mini","input":{"messages":[{"role":"user","content":"Summarize: BatchRouter routes batch-AI workloads across providers."}]}}

There are two changes: the base URL and the API key.

  1. Create a BatchRouter API key. Generate a br_live_… key in the dashboard (or with POST /v1/auth/account/api-keys). Keys are shown once — store it server-side as BATCHROUTER_API_KEY. See Authentication.

  2. Swap the base URL to https://api.batchrouter.com (or https://test.api.batchrouter.com for staging). All public endpoints live under /v1.

  3. Swap the key for your br_live_… key, sent as Authorization: Bearer br_live_….

If your client points at the OpenAI Batch base URL today, the change is the base URL and the credential — your JSONL stays the same.

from openai import OpenAI
# Before — OpenAI
# client = OpenAI(api_key="sk-...")
# After — BatchRouter
client = OpenAI(
base_url="https://api.batchrouter.com/v1",
api_key="br_live_your_key_here", # or os.environ["BATCHROUTER_API_KEY"]
)

The file-then-batch flow mirrors OpenAI Batch. Upload your JSONL, then create a batch from the file.

  1. Upload the input file with POST /v1/files. Send the raw body with Content-Length, Content-Type, X-BatchRouter-Filename, and X-BatchRouter-Purpose: model_input. You get back a file_id.

  2. Create the batch with POST /v1/batches, passing input_file_id and an Idempotency-Key header (8–128 chars) so retries are safe. You get back 202 with the batch id (bat_…).

Terminal window
# 1. Upload the JSONL input file
FILE_ID=$(curl -s https://api.batchrouter.com/v1/files \
-H "Authorization: Bearer $BATCHROUTER_API_KEY" \
-H "Content-Type: application/jsonl" \
-H "Content-Length: $(wc -c < input.jsonl)" \
-H "X-BatchRouter-Filename: input.jsonl" \
-H "X-BatchRouter-Purpose: model_input" \
--data-binary @input.jsonl | jq -r '.file_id')
# 2. Create the batch from the uploaded file
curl -s https://api.batchrouter.com/v1/batches \
-H "Authorization: Bearer $BATCHROUTER_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: import-2026-06-18-001" \
-d "{\"input_file_id\":\"$FILE_ID\",\"sla_tier\":\"standard\"}"

You can also submit items inline (items: [...]) instead of uploading a file — see Submit a batch.

BatchRouter accepts the OpenAI input contract but adds a routing layer on top. The differences are additive — ignore them and you get sensible defaults; opt in for more control.

  • It routes across providers, not just one. BatchRouter picks a lane per the routing policy, applies the GTM discount on native OpenAI/Anthropic lanes, and writes a routing/rejection receipt. Unselected lanes come back with reasons (capacity_full, context_window_exceeded, privacy_tier_mismatch, …).
  • Quotes are free and first. Call POST /v1/quotes/model to get a binding price (quote_id, qlock_…) and lane breakdown before you commit. Pass the quote_id on create to lock that estimate. OpenAI has no equivalent step.
  • SLA tiers. sla_tier is standard (24h, default), flex (up to 48h, cheaper), or priority. Choose the speed/cost trade-off per batch.
  • Routing modes. routing_mode is cheapest (default), sla_aware, public_only, edge_only, hybrid, or privacy_constrained — control which lanes are eligible.
  • Privacy tiers + per-batch webhooks. Set privacy_tier (standard/confidential/restricted) and a signed webhook directly on create. Webhook events carry an X-BatchRouter-Signature (HMAC-SHA256) header.
  • One unified result surface. However a job is routed, results come back in a single BatchRouter schema — fetch per-item output (with customer_item_id, status, output, error) from GET /v1/batches/{batchId}/results, or get a signed JSONL artifact URL from GET /v1/batches/{batchId}/artifact-url for large batches. You poll the same way regardless of which provider lane ran each item.

To stay maximally OpenAI-like, omit the extras: BatchRouter defaults to sla_tier: "standard", routing_mode: "cheapest", and privacy_tier: "standard", and you can poll for results without configuring a webhook.

{"input_file_id":"file_abc123","sla_tier":"flex","routing_mode":"sla_aware","quote_id":"qlock_..."}