Docs
Batch API
POST/api/v1/batches
Submit up to 1,000 requests as one asynchronous job and pay 50% less per token for tolerating the wait. Same file and batch shapes as OpenAI, so the SDKs work unchanged.
How it works
- Upload a JSONL file of requests, create a batch pointing at it, poll until the batch reaches a terminal status, download the results file.
- The queue accepts work even while no GPU is serving the model, then drains when one comes up. If a live request would get a 503, a batch is how you leave the work with us anyway.
- The completion window is
24h: whatever hasn't run by then is refunded and the finished part is delivered.
The input file
One JSON object per line, uploaded with purpose batch (limits: 1,000 lines, 5 MB):
{"custom_id": "job-1", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "Qwen/Qwen2.5-7B-Instruct", "messages": [{"role": "user", "content": "Classify: great product"}], "max_tokens": 10}}
{"custom_id": "job-2", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "Qwen/Qwen2.5-7B-Instruct", "messages": [{"role": "user", "content": "Classify: broke in a day"}], "max_tokens": 10}}custom_idmust be unique per line; it keys your results.urlmust be/v1/chat/completions;bodytakes the same fields as the live endpoint, and each line may use a different model.- Validation is all or nothing: one bad line rejects the whole batch with the line number, and nothing is queued or charged.
streamis ignored inside batches; results always arrive as complete responses in the output file.
Example
# 1. upload the JSONL file
curl https://tokenkiln.com/api/v1/files \
-H "Authorization: Bearer tk_..." \
-F purpose=batch \
-F file=@batchinput.jsonl
# -> {"id": "file_...", ...}
# 2. create the batch
curl https://tokenkiln.com/api/v1/batches \
-H "Authorization: Bearer tk_..." \
-H "Content-Type: application/json" \
-d '{
"input_file_id": "file_...",
"endpoint": "/v1/chat/completions",
"completion_window": "24h"
}'
# -> {"id": "batch_...", "status": "in_progress", ...}
# 3. poll until status is terminal
curl https://tokenkiln.com/api/v1/batches/batch_... \
-H "Authorization: Bearer tk_..."
# 4. download results
curl https://tokenkiln.com/api/v1/files/file_.../content \
-H "Authorization: Bearer tk_..."Lifecycle
| Status | Meaning |
|---|---|
| in_progress | Queued or running. New batches start here; requests drain as capacity allows. |
| finalizing | All requests done; output and error files are being written. |
| completed | Done. output_file_id has one response per line, keyed by custom_id. |
| cancelling | Cancel requested; in-flight requests finish, queued ones are refunded. |
| cancelled | Cancelled. Finished results are kept in the output file. |
| expired | The 24h window passed. Finished results kept, unrun requests refunded. |
| failed | The batch could not run. Full refund of the hold. |
Every batch object carries request_counts (total / completed / failed) so a poll loop can report progress. Requests that fail with an engine error land in error_file_id with their custom_id; they cost nothing. Cancel with POST /api/v1/batches/{id}/cancel, or from the Batches page.
Billing
- At creation, the discounted worst case for every line is reserved atomically. If your balance cannot cover the whole batch, creation fails with 402 and nothing is queued.
- Each request settles individually against real token counts as it finishes, at the prices in force when the batch was created. Later catalog repricing never touches queued work.
- Cancellation and expiry refund every request that has not run. Failed requests are never billed.
The reserve shows on your balance as a hold while the batch runs. Size batches to your balance, or top up first; the hold is released line by line as results settle.