# Batches

Many decisions as one background job: a backlog to classify, a nightly re-scoring, a golden set of your own.

```bash
# JSON Lines: one /v1/systemone body per line, with an optional custom_id
curl -s $JERS_BASE_URL/v1/batches -H "Authorization: Bearer $JERS_API_KEY" \
  -H "Content-Type: application/x-ndjson" --data-binary @requests.jsonl
```

or `{"requests": [...]}` as JSON. Up to 5,000 requests and 16 MB. The answer is the job: `id`, `status`, `total`.

- `GET /v1/batches/<id>`: `status` (`queued`, `running`, `done`, `stopped: no credit left`, or `failed` with `error` when the job itself broke), `total`, `done`, `succeeded`, `failed`, `cost`. `GET /v1/batches` lists your jobs.
- `GET /v1/batches/<id>/results`: JSON Lines in the order sent, each `{"custom_id", "status", "response"}` or `{"custom_id", "status", "error"}`. A request that is a JSON object but a bad decision request fails alone with its status (422); the rest go on. A line that is not a JSON object, or a `custom_id` that repeats or is not 1 to 64 letters, digits or `. _ : -`, refuses the whole upload with 422. Without a `custom_id`, a request's id is its position, counted from 0.
- When the credit runs out, the job stops: the remaining lines get status 402 and the job says `stopped: no credit left`.
- Jobs survive a gateway restart and resume where they were.

Each request is billed like a single call. Python: `client.batch_upload("requests.jsonl")`, `client.batch_wait(id)`, `client.batch_results(id)`. TypeScript: `batchUpload`, `batchWait`, `batchResults`.
