OpenAI compatibility
Point an existing OpenAI Batch client at BatchRouter by changing base_url and the API key. The file-then-batch flow on the /v1/openai/v1/* surface.
BatchRouter exposes an OpenAI-Batch-compatible API under /v1/openai/v1/. If you already have code built against the openai SDK's Files and Batches resources, you can route those workloads through BatchRouter by changing two things: the base URL and the API key. No request reshaping required. The short version is OpenAI Batch in five minutes.
Behind that familiar surface, BatchRouter is a routing and aggregation layer, not a passthrough proxy to OpenAI. Your batch is quoted, funding-gated, and dispatched across BatchRouter's provider lanes using the same pipeline as the native /v1/batches surface — and the responses you download are projected back into OpenAI's shape so your client doesn't notice the difference.
When to use this surface
Use the compatible surface when you want a drop-in migration: minimal code changes to send existing OpenAI Batch jobs through BatchRouter.
Use the native /v1/batches surface when you want BatchRouter's full feature set — free pre-submission quotes, routing_mode selection, privacy_tier controls, and routing/billing receipts. The OpenAI surface deliberately keeps the OpenAI request shape, so those BatchRouter-specific knobs aren't expressed in the request body.
Both surfaces operate on the same underlying batches. A batch created through /v1/openai/v1/batches is a real BatchRouter batch — it appears in your dashboard, counts against your credits and billing controls, and can also be inspected through the native API.
Base URL and authentication
Point your OpenAI client's base_url at:
https://api.batchrouter.com/v1/openai/v1For the test environment, use https://test.api.batchrouter.com/v1/openai/v1.
Authenticate with a BatchRouter API key (prefixed br_live_) as the bearer token — exactly where the OpenAI SDK already puts OPENAI_API_KEY. Create a key in the dashboard (POST /v1/auth/account/api-keys) or via POST /v1/auth/agent-register. Keys are shown once.
from openai import OpenAI
client = OpenAI(
base_url="https://api.batchrouter.com/v1/openai/v1",
api_key="br_live_...", # your BatchRouter key, not an OpenAI key
)This is a routing layer, not OpenAI. Your br_live_ key bills against your BatchRouter credit balance, and the model you name in each request row is resolved against BatchRouter's catalog (GET /v1/catalog/models) and routed to whichever provider lane serves it — which may not be OpenAI at all.
The compatible endpoints
These are the operations exposed under the OpenAI-compatible surface. They mirror the openai SDK's client.files.* and client.batches.* methods.
| Method & path | OpenAI SDK equivalent |
|---|---|
POST /v1/openai/v1/files | client.files.create({ file, purpose: "batch" }) |
GET /v1/openai/v1/files/{fileId} | client.files.retrieve(id) |
GET /v1/openai/v1/files/{fileId}/content | client.files.content(id) |
POST /v1/openai/v1/batches | client.batches.create({ input_file_id, endpoint, completion_window }) |
GET /v1/openai/v1/batches | client.batches.list() |
GET /v1/openai/v1/batches/{batchId} | client.batches.retrieve(id) |
POST /v1/openai/v1/batches/{batchId}/cancel | client.batches.cancel(id) |
For the full request/response field reference, see the interactive API reference or the raw spec.
The file-then-batch flow
The flow matches OpenAI's Batch API exactly: upload a JSONL input file, create a batch from it, poll, then download the output file.
-
Upload the input file. Send your OpenAI-Batch JSONL with
purpose: "batch"toPOST /v1/openai/v1/files(multipart/form-data). Each JSONL row is{ custom_id, method, url, body }. BatchRouter converts each row into a native item —urlselects the operation,body.modelselects the model, and the rest ofbodybecomes the item input. Invalid rows are rejected with an OpenAI-shaped error. You get back an OpenAI File object; keep itsid. -
Create the batch.
POST /v1/openai/v1/batcheswith{ input_file_id, endpoint, completion_window }. Theendpointis the OpenAI endpoint your rows target —/v1/chat/completions,/v1/responses, or/v1/embeddings. Chat-completions and responses route to BatchRouter'sresponsesoperation; embeddings route toembeddings.completion_windowis"24h". The call is quote-free to you — BatchRouter quotes and funding-gates internally using the same pricing and billing controls as the native pipeline. You get back a bare OpenAI Batch object. -
Poll the batch.
GET /v1/openai/v1/batches/{batchId}untilstatusis terminal:completed,failed,expired, orcancelled. (In-flight statuses are OpenAI'svalidating→in_progress→finalizing;cancellingis the in-progress cancel state.) -
Download the results. When
completed, readoutput_file_id(anderror_file_idfor failures) from the Batch object and fetch the bytes withGET /v1/openai/v1/files/{fileId}/content. Result rows are projected to OpenAI's per-line shape{ id, custom_id, response: { status_code, request_id, body }, error }, keyed by yourcustom_id.
Upload (step 1)
The OpenAI SDK handles the multipart upload for you.
input_file = client.files.create(
file=open("requests.jsonl", "rb"),
purpose="batch",
)A JSONL row looks like the OpenAI Batch format — for example:
{"custom_id":"item-1","method":"POST","url":"/v1/responses","body":{"model":"gpt-5.4-mini","input":{"messages":[{"role":"user","content":"Summarize: BatchRouter routes batch-AI workloads across providers."}]}}}gpt-5.4-mini is a model id from the live catalog. The models available to you come from GET /v1/catalog/models — see the API reference.
Create, poll, and download (steps 2–4)
import time
batch = client.batches.create(
input_file_id=input_file.id,
endpoint="/v1/responses",
completion_window="24h",
)
while batch.status not in ("completed", "failed", "expired", "cancelled"):
time.sleep(30)
batch = client.batches.retrieve(batch.id)
if batch.status == "completed":
output = client.files.content(batch.output_file_id)
print(output.text) # OpenAI-shaped JSONL, one object per lineResponse body format: normalized vs raw
Because BatchRouter routes across many providers, the per-line response.body you download is, by default, BatchRouter's normalized cross-provider output. If you need each provider's raw API response where it was captured, request raw:
- Per batch — pass
body_format(normalized|raw, defaultnormalized) when creating the batch viaPOST /v1/openai/v1/batches. - Per download — pass
?body_format=rawonGET /v1/openai/v1/files/{fileId}/contentto override for that one download.
The effective format is echoed in the x-batchrouter-body-format response header.
If you need provider-portable output, keep the default normalized — it gives you a consistent shape regardless of which lane served the row. Use raw only when your downstream code depends on a specific provider's exact response structure.
Errors and expiry
- Errors are returned in OpenAI's envelope. On insufficient funds, batch creation returns an OpenAI-shaped
{ "error": { "type": "insufficient_quota" } }— top up in the dashboard. - Output and error files are subject to BatchRouter's retention. A file whose bytes have been reclaimed reports
status: "expired"in its metadata and returns 410 from/content(distinct from a 404 for a file that never existed). See credits and billing and the API reference for retention details.
Migrating to the native surface
Once you're routing through BatchRouter, the native /v1/batches API unlocks capabilities the OpenAI shape can't express:
- Free quotes before you commit (
POST /v1/quotes/model,POST /v1/quotes/workflow). routing_mode—cheapest(default),sla_aware,public_only,edge_only,hybrid, orprivacy_constrained.privacy_tier—standard,confidential, orrestricted.- Receipts — routing and billing receipts (
GET /v1/batches/{batchId}/billing-receipt).
These two surfaces operate on the same batches, so you can adopt the native API incrementally — keep the OpenAI client for existing jobs and reach for the native endpoints where you need more control.
Next steps
Submit a batch (native API)
The full BatchRouter flow with quotes, routing modes, and receipts.
API reference
Every endpoint, request field, and response schema.
Interactive API reference
Try the OpenAI-compatible and native endpoints live in Scalar.
Credits and billing
How credits, funding gates, and retention work.