# 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 $JEPELA_BASE_URL/v1/batches -H "Authorization: Bearer $JEPELA_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`, `stopped: account suspended`, `stopped: key revoked`, 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`. A suspended account stops its jobs the same way, with 403 and `stopped: account suspended`, and so does revoking the key that uploaded the batch, with 401 and `stopped: key revoked`: every line checks the key before it is answered.
- Jobs survive a gateway restart and resume where they were.
- A batch is kept 30 days from the upload (`expires` says when), then deleted with its requests and results; a job still running then stops. Download the results before. `POST /v1/decisions/delete` deletes every batch at once, and so does deleting the account. `POST /v1/memory/delete` takes the subject's requests (`subject` in the request) and their results out of every batch; the other requests keep their ids and results, the job's `removed` counts what was taken out, and a job left with none is deleted.

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`.
