Skip to main content
Run a Reflex over many texts in one job instead of a request per row. Two modes share the same row shape — pick by volume and how soon you need the labels. See the Reflexes overview for what a Reflex is, and Train a Custom Reflex to make your own. Every row carries its own id (echoed back so you can map results to your records), a model, and the text to classify. A row can name several models to run all of them over the same text at once. Handing this to a coding agent? Paste this prompt:
Prompt for your coding agent

Synchronous batch

One request in, every label back in the same response. Runs on the realtime engine so the call returns in seconds, but bills at the discounted batch rate. Capped at 300 rows per call, processed with internal concurrency. Reach for it to label a page of results, a form submission, or any small set where you want the answer inline.
Each result echoes your id, carries one prediction per model on that row, and reports prefill_tokens (the input length charged once for the row). A prediction mirrors the /predict response — a mode and one classes entry per label, with the winner marked "selected": true.
A row that fails validation (e.g. empty text) comes back as { "id": ..., "error": { "type", "message" } } instead of predictions — other rows still return normally, so check for error per row. One exception: naming a model that doesn’t exist is rejected up front and fails the whole request with 404 model_not_found (no partial results), so validate model names before you batch.

Asynchronous batch

For larger or cost-sensitive jobs, upload the rows and pick up results later. This is the discounted batch tier: rows queue durably, a background worker drains them, and you poll for progress. Three calls — upload, poll, fetch.
model must be an array here, even for a single model (["jailbreak"]) — a bare string is rejected. It’s the one shape difference from the synchronous endpoint.
1

Upload the batch

POST /v1/reflex/asynchronous_batches/upload. Up to 10,000 rows, each id unique, each text350,000 characters. Returns immediately with a batch_id once the rows are queued — it does not wait for classification.Pass an Idempotency-Key header to make retries safe — replaying the same key returns the existing batch (with 200 instead of 201), never a duplicate.
2

Poll for progress

GET /v1/reflex/asynchronous_batches/{batch_id}. Same shape as upload, with request_counts advancing as the worker drains the queue. status moves queued → in_progress → completed.
cURL
The queue drains at a steady, throttled rate (~2 rows/sec) so batch work never competes with realtime predictions. Small batches finish in seconds; a full 10,000-row batch takes roughly 80 minutes. Poll on an interval — don’t hold a request open waiting.
3

Fetch results

GET /v1/reflex/asynchronous_batches/{batch_id}/results. Returns the status block plus a results array — one entry per row, keyed by your id, as inline JSON (not a file to download).
cURL
A row is completed (carries predictions, one per model), failed (carries an error), or still pending if you fetch before the batch finishes.

Upload, poll, and collect

The whole loop end to end — upload, poll until done, fetch, then map results back to your records by id.
Python

Classifying traces

The most common batch job is labeling a backlog of agent traces — scanning past conversations for jailbreaks, guardrail violations, loops, or leaked thinking. Run it without code from the Traces dashboard: select conversations, pick the Reflexes to run, and the labels land back on each trace. Under the hood that’s an asynchronous batch over the text of each turn.

Errors

OpenAI-shaped: { "error": { "message", "type", "param", "code" } }param appears only on invalid_request_error, and code is null for the validation cases below. These are request-level failures; an individual row that fails to classify is reported per row in results (see above), not as a request error.

Reflexes overview

What a Reflex is, the default classifiers, and realtime /predict.

Train a Custom Reflex

Bring labeled examples or synthesize a dataset; get a classifier in ~30s.