Workflow products
A workflow product lets you buy a finished job shape instead of choosing a model. Rather than naming gpt-4o-mini and a routing mode yourself, you pick a curated outcome — classify, extract, summarize, and so on — and BatchRouter selects the model and provider lanes that satisfy that contract. You describe the job; BatchRouter handles the infrastructure choices.
This is the outcome-contract alternative to the model-quote path. Both end at the same place — a quote_id you pass to POST /v1/batches — but they differ in who picks the model.
When to use a workflow product
Section titled “When to use a workflow product”A workflow product is a curated, versioned outcome contract plus a preset manifest (input shape, output shape, SLA, route policy). It is not a general DAG, pipeline, or multi-step orchestration engine — it is a single curated job outcome that BatchRouter knows how to route well.
Reach for a workflow product when:
- You care about the result shape (a clean classification, a structured extraction, a summary) more than which model produces it.
- You want BatchRouter to balance fit, validation history, and cost rather than always taking the cheapest model.
- You’d rather not track model slugs, capabilities, or provider lanes yourself.
Use the model-quote path instead when you need a specific model, an explicit fallback list, or fine control over routing_mode.
Browse the catalog
Section titled “Browse the catalog”List the available workflow products to discover slugs and their default SLA tier.
curl https://api.batchrouter.com/v1/catalog/workflow-products \ -H "Authorization: Bearer $BATCHROUTER_API_KEY"const res = await fetch("https://api.batchrouter.com/v1/catalog/workflow-products", { headers: { Authorization: `Bearer ${process.env.BATCHROUTER_API_KEY}` },});const { data } = await res.json();import os, requests
res = requests.get( "https://api.batchrouter.com/v1/catalog/workflow-products", headers={"Authorization": f"Bearer {os.environ['BATCHROUTER_API_KEY']}"},)data = res.json()["data"]Each entry carries a slug, display_name, description, sla_tier, and a latest_version_id. Fetch a single product by slug to inspect its details before quoting:
curl https://api.batchrouter.com/v1/catalog/workflow-products/classify \ -H "Authorization: Bearer $BATCHROUTER_API_KEY"const res = await fetch( "https://api.batchrouter.com/v1/catalog/workflow-products/classify", { headers: { Authorization: `Bearer ${process.env.BATCHROUTER_API_KEY}` } },);const { product } = await res.json();res = requests.get( "https://api.batchrouter.com/v1/catalog/workflow-products/classify", headers={"Authorization": f"Bearer {os.environ['BATCHROUTER_API_KEY']}"},)product = res.json()["product"]Quote a workflow product
Section titled “Quote a workflow product”POST /v1/quotes/workflow quotes a curated workflow product and returns model-agnostic provider lanes that satisfy the contract. Send the workflow slug plus your input(s). You can quote a single item with input, or a representative set with inputs (each entry takes a customer_item_id and an input object).
curl https://api.batchrouter.com/v1/quotes/workflow \ -H "Authorization: Bearer $BATCHROUTER_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "workflow": "classify", "inputs": [ { "customer_item_id": "item-1", "input": { "messages": [ { "role": "user", "content": "Summarize: BatchRouter routes batch-AI workloads across providers." } ] } } ] }'const res = await fetch("https://api.batchrouter.com/v1/quotes/workflow", { method: "POST", headers: { Authorization: `Bearer ${process.env.BATCHROUTER_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ workflow: "classify", inputs: [ { customer_item_id: "item-1", input: { messages: [ { role: "user", content: "Summarize: BatchRouter routes batch-AI workloads across providers." }, ], }, }, ], }),});const { quote_id, pricing_estimate, quote_lanes } = await res.json();res = requests.post( "https://api.batchrouter.com/v1/quotes/workflow", headers={ "Authorization": f"Bearer {os.environ['BATCHROUTER_API_KEY']}", "Content-Type": "application/json", }, json={ "workflow": "classify", "inputs": [ { "customer_item_id": "item-1", "input": { "messages": [ {"role": "user", "content": "Summarize: BatchRouter routes batch-AI workloads across providers."} ] }, } ], },)quote = res.json()quote_id = quote["quote_id"]The response is the same QuoteResponse shape as a model quote: a quote_id, a pricing_estimate, and the quote_lanes BatchRouter would route to. The difference is that you never named a model — BatchRouter chose lanes that satisfy the workflow’s outcome contract.
Pin a workflow version
Section titled “Pin a workflow version”Workflow products are versioned. Passing the bare slug uses the latest version. To pin a specific version for reproducibility, send workflow as an object with slug plus either version_id or version_number:
{ "workflow": { "slug": "classify", "version_number": 3 }, "input": { "messages": [{ "role": "user", "content": "…" }] }}Constrain cost and tools
Section titled “Constrain cost and tools”max_pricecaps the quote — see the API reference for theMoneyshape.required_toolsforces provider-hosted tools (such asweb_searchorpython_execution) onto every lane. Quote-levelrequired_toolsare merged with any per-input requirements, and lanes whose provider doesn’t declare every required tool are rejected with atool_supportfailure. If no eligible lane remains, the quote fails rather than routing to a lane that lacks the tools.
How it differs from a model quote
Section titled “How it differs from a model quote”The two quote endpoints converge on a quote_id but invert who owns model selection.
Model quote (POST /v1/quotes/model) | Workflow quote (POST /v1/quotes/workflow) | |
|---|---|---|
| You choose | model / models, routing_mode | a workflow slug (and optional version) |
| BatchRouter chooses | the cheapest eligible lane for your model(s) | the model + provider mix that satisfies the contract |
| Input | items[] (each names a model) | input or inputs[] (model-agnostic) |
| Best when | you need a specific model or routing mode | you care about the outcome, not the model |
| Returns | quote_id, pricing_estimate, quote_lanes | quote_id, pricing_estimate, quote_lanes |
From quote to batch
Section titled “From quote to batch”Once you have a quote_id, the rest of the flow is identical to any other batch.
-
Create the batch — pass the
quote_idtoPOST /v1/batcheswith anIdempotency-Keyheader. The active quote snapshot reserves credits; final cost settles from actual provider token usage. -
Poll —
GET /v1/batches/{batchId}until a terminal status (completed, orfailed | cancelled | expired). -
Fetch results — page
GET /v1/batches/{batchId}/results, or pull the signed bundle fromGET /v1/batches/{batchId}/artifact-url.
See Submit a batch for the full create-poll-results walkthrough.