SLA-aware lanes & routing
Control how BatchRouter places your batch — the 24-hour SLA, routing modes, multi-lane routing, rejection receipts, and privacy tiers explained.
BatchRouter doesn't just forward your batch to one provider — it evaluates every eligible provider/model lane, prices them, and picks placement based on the controls you set. This page explains the SLA every batch gets, the controls you set (routing_mode, privacy_tier), how multi-lane routing works, and how to read the rejection receipts that explain why a lane wasn't used.
Both controls are set per quote and per batch. Set them when you request a quote so the estimate reflects your constraints, then pass the same values (plus the quote_id) to POST /v1/batches.
What a lane is
A lane is one candidate execution path — a specific provider running a specific model that could fulfill some or all of your items. When you request a quote, BatchRouter expands your items into every eligible lane, prices each one, and returns them as quote_lanes. The selected lane(s) carry selected: true; the rest come back with a rejection receipt explaining why they were skipped.
Because different items in one batch can declare different models, a single customer batch can be split across multiple internal lanes — each handling the items it's best suited for. You still get one batch.id, one status to poll, and one merged result set; the per-lane execution is BatchRouter's concern. The completed batch's billing receipt lists the provider_lanes that actually ran and the rejected_lanes that didn't.
Multi-lane routing optimizes for cost, SLA, and live capacity simultaneously. If one provider is at capacity for part of your batch, eligible items can still flow to another lane instead of failing the whole batch.
The SLA (sla_tier)
Every batch has one SLA: BatchRouter targets completion within 24 hours. You don't choose a tier.
The sla_tier field accepts standard, flex, and priority for compatibility, and all three are treated as standard. The value doesn't change the deadline or the price, and the batch reports sla_tier: "standard" whichever one you send. The default is standard, so you can leave the field out.
{ "sla_tier": "standard" }The deadline is surfaced as deadline_at on the batch you poll. A sweep can ask for an earlier deadline with deadline_seconds. The SLA also affects which lanes are eligible: a lane that can't finish the work before the deadline is not selected for that batch.
Routing modes (routing_mode)
routing_mode controls which lanes BatchRouter is allowed to consider and how it ranks them. Default is cheapest.
| Mode | What it does |
|---|---|
cheapest | Lowest total price across all eligible lanes (default). |
sla_aware | Balances price against the lane's ability to comfortably hit the 24-hour SLA. |
public_only | Routes only to public provider lanes (OpenAI, Anthropic, and other public APIs). |
edge_only | Routes only to edge / BatchProviderApi provider lanes. |
hybrid | Considers both public and edge lanes and picks the best fit. |
privacy_constrained | Restricts to lanes that satisfy your privacy requirements (pair with privacy_tier). |
{ "routing_mode": "sla_aware" }Start with cheapest and let the quote show you the lane spread. Switch to sla_aware if a cheap lane is cutting your deadline close, or to public_only / edge_only when you have a hard requirement about where compute runs.
Privacy tiers (privacy_tier)
privacy_tier constrains placement by the privacy tiers each provider declares. Default is standard. Each lane carries a data-privacy proof (declared retention window, output handling, declared privacy tiers). BatchRouter checks the declared tiers against this value. It publishes the declared retention window but does not compare it against your batch.
| Tier | Routing constraint |
|---|---|
standard | No additional data-handling constraint (default). |
confidential | Routes only to providers that declare the confidential tier. Not a zero-data-retention guarantee: the router adds that check only when routing_mode is privacy_constrained, so in every other mode a confidential batch can reach a provider that declares no zero data retention. |
restricted | Only providers that declare the restricted tier are eligible. Like every tier, it is the provider's own declaration, and no built-in provider declares it. |
{ "routing_mode": "privacy_constrained", "privacy_tier": "confidential" }This pairing adds the zero-data-retention check: only lanes whose provider declares data_collection: deny and zero data retention (supports_zdr) stay eligible. No built-in provider declares zero data retention today, so read supports_zdr in the model catalog before you rely on this pairing.
If no eligible lane can satisfy the requested tier, the lanes that fail it come back rejected with privacy_tier_mismatch — and if none qualify, quote creation fails rather than silently routing you somewhere that doesn't meet the constraint.
Rejection receipts
Every non-selected lane in a quote (and every rejected lane in a completed batch's receipt) carries a normalized rejection receipt: a stable rejection_code, a customer-safe rejection_reason, and a rejection_receipt object with the failed eligibility checks. This makes routing auditable — you can always see why a cheaper or different lane wasn't used.
Common rejection codes:
| Code | Meaning |
|---|---|
capacity_full | The lane had no live routable capacity for your SLA/volume. |
stale_heartbeat | The provider's capacity heartbeat was stale, so it wasn't treated as live supply. |
context_window_exceeded | An item exceeds the model's context window on that lane. |
privacy_tier_mismatch | The lane can't satisfy your requested privacy_tier. |
region_unavailable | The lane's provider doesn't match your allowed_regions. A provider that declares the countries it runs in must have every one of them covered by your list. A provider marked global always passes this check, so allowed_regions is not a residency guarantee. See Region matching. |
missing_web_search (and similar missing_<tool>) | The lane's provider doesn't declare a hosted tool you required via required_tools. |
Inspect rejected lanes straight from the quote response:
curl -s https://api.batchrouter.com/v1/quotes/model \
-H "Authorization: Bearer $BATCHROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"models": ["gpt-5.4-mini"],
"routing_mode": "sla_aware",
"items": [
{"customer_item_id":"item-1","operation":"responses","model":"gpt-5.4-mini","input":{"messages":[{"role":"user","content":"Summarize: BatchRouter routes batch-AI workloads across providers."}]}}
]
}' | jq '.quote_lanes[] | {provider, model, selected, rejection_code, rejection_reason}'gpt-5.4-mini is a model id from the live catalog. List the models and the providers/regions/tools each one actually supports via GET /v1/catalog/models before pinning a model or region.
Putting it together
A single batch can combine both controls. For example, "only lanes whose provider declares the restricted tier, denies data collection, and declares zero data retention":
{
"quote_id": "qlock_...",
"routing_mode": "privacy_constrained",
"privacy_tier": "restricted"
}Set the same values on the quote first so the price you're quoted reflects the constrained lane set — then carry them onto the batch.
The router checks those declarations; it does not check that a node is private. No built-in provider declares the restricted tier or zero data retention today, so with built-in providers alone this combination finds no eligible lane.
Next steps
Quotes & pricing
Get a free quote, read the lane spread, and lock a price before you submit.
Models & catalog
List models with per-provider pricing, capacity, regions, retention, and supported tools.
Submit a batch
Create a batch with your chosen routing mode and privacy tier.
API reference
Full schema for quote lanes, rejection receipts, and batch parameters.