Batches
The Batches endpoint runs many requests asynchronously. You upload a JSONL file of requests, start a batch, and collect the results within 24 hours. Batch requests cost 50% of the standard price. It is OpenAI-compatible and works with /v1/responses, /v1/chat/completions and /v1/embeddings.
Run a batch
Upload the input file
Build the JSONL with toBatchJSONL() and upload it with purpose batch.
Create the batch
Wait for it to finish
Download the results
With curl, upload the file and create the batch like this:
JSONL format
The input file has one JSON request per line. Each line is a BatchRequestLine:
Glexir checks the file when you upload it. The rules:
- The file name ends in
.jsonland the file is at most 20 MB. Split larger jobs across several batches. - At most 50,000 lines. Blank lines are ignored.
custom_idis a string, unique within the file.methodis"POST".urlis/v1/responses,/v1/chat/completionsor/v1/embeddings, and every line uses the same one.- Every line uses the same
body.model. bodyis an object, withoutstream: true.bodypasses the same model and tool checks as a live request. It can't useprevious_response_idorconversation.
A line that breaks a rule fails the upload with 400, param file, and a message that names the line, for example Batch line 3: a batch may only use one model.
Output lines come back in any order, so match them to your requests by custom_id. The output and error files use OpenAI's batch output format, unchanged: each line has id, custom_id, response (status_code, request_id, body) and error.
toBatchJSONL()
Serializes request lines into a File named batch.jsonl (type application/jsonl), ready for files.create({ purpose: "batch" }). method defaults to "POST". Each line is written with JSON.stringify, and the file ends with a newline.
Pricing
Batch requests are billed at the batch rate, which is 50% of the standard rate for input, cached input and output tokens, and for embedding tokens. The long-context rates are halved the same way. You pay only for requests that complete. A failed batch, or one that expires with no completed requests, costs nothing. See Pricing for standard rates.
Batch holds
When you create a batch, Glexir reserves credit for the whole batch at once as a hold. OpenAI bills completed requests even if the batch later expires or is cancelled, so the full amount must be available up front.
The hold is sized from an estimate Glexir made when you uploaded the file, summed over every line, at batch rates:
- Input: roughly 1 token per 3 bytes of request text, with fixed allowances for images and files.
- Output: each line's
max_output_tokens(Responses) ormax_completion_tokens/max_tokenstimesn(Chat Completions). A line with no cap is counted as 32,000 output tokens. - Embeddings: input only.
Keep the hold small
Set max_output_tokens or max_completion_tokens on every line. Without a cap, each line reserves 32,000 output tokens, and a large batch can need far more credit than it will use.
If your available balance can't cover the hold, batches.create() fails with 402 and code credit_balance_exhausted (or spend_limit_exceeded if it would pass a monthly limit). Add credit or split the batch.
The hold lasts 26 hours, longer than the 24-hour window. When the batch reaches completed, failed, expired or cancelled, Glexir charges the actual usage reported on the batch and frees the rest. Glexir learns the final status from OpenAI's notifications, or when you call batches.retrieve() or batches.cancel(). While a hold is open it counts as one in-flight request toward your concurrency limit. See Credits & billing and Rate limits & spend limits.
The 24-hour window
completion_window must be "24h". OpenAI aims to finish within that window. Requests not finished in time are not run, and the batch ends as expired. Completed requests from an expired batch are still billed, and their results are in output_file_id.
Batch statuses (BatchStatus):
| Status | Meaning |
|---|---|
validating | The input file is being checked. |
failed | Validation failed. See errors. |
in_progress | Requests are running. |
finalizing | Results are being written. |
completed | Done. Results are in output_file_id, failed requests in error_file_id. |
expired | The 24-hour window ran out. |
cancelling | Cancel requested. Can last up to 10 minutes. |
cancelled | Cancelled. |
Cancel a batch
The batch stays cancelling for up to 10 minutes, then becomes cancelled. Requests that completed before that are still billed.
List batches
You only see batches created with your organization. See Pagination.
Methods
All methods take options?: RequestOptions as the last argument. See Client configuration.
glexir.batches.create()
POST /batches.
input_file_idstringrequired- A .jsonl file uploaded through Glexir with purpose batch. One model per file, at most 50,000 requests.
endpointBatchEndpointrequired- /v1/responses, /v1/chat/completions or /v1/embeddings. Must match the url in the file.
completion_window"24h"required- Always 24h.
metadataMetadata | nulloptional- Up to 16 string key/value pairs. Keys at most 64 characters, values at most 512.
output_expires_after{ anchor: "created_at"; seconds: number }optional- When the output and error files expire.
glexir.batches.retrieve()
GET /batches/{batch_id}.
glexir.batches.list()
GET /batches.
afterstringoptional- Return batches after this batch ID. The SDK sets it for you when paging.
limitnumberoptionaldefault20- Page size.
glexir.batches.cancel()
POST /batches/{batch_id}/cancel.
Batch object
idstringrequired- The batch ID.
object"batch"required- Always batch.
endpointstringrequired- The endpoint every request uses.
input_file_idstringrequired- The input file.
completion_windowstringrequired- 24h.
statusBatchStatusrequired- See the status table above.
created_atnumberrequired- Unix timestamp in seconds.
output_file_idstringoptional- Results of successful requests. Download with files.content().
error_file_idstringoptional- Results of failed requests.
errors{ object?; data?: Array<{ code?; line?; message?; param? }> }optional- Validation errors when the batch failed.
request_counts{ total: number; completed: number; failed: number }optional- Progress.
usageobjectoptional- input_tokens, input_tokens_details.cached_tokens, output_tokens, output_tokens_details.reasoning_tokens, total_tokens. Glexir bills from this.
modelstringoptional- The model used.
metadataMetadata | nulloptional- What you sent on create.
in_progress_at, finalizing_at, completed_at, failed_at, expired_at, expires_at, cancelling_at, cancelled_atnumberoptional- Unix timestamps for each stage.
_request_idstring | nulloptional- SDK only. The x-request-id header.
custom_idstringrequired- Unique within the file. Use it to join output lines to requests.
method"POST"required- Always POST.
urlBatchEndpointrequired- The endpoint for this line.
bodyTBodyrequired- The request body, as you would send it to the endpoint.
Errors
| Status | Code | When |
|---|---|---|
| 400 | none | input_file_id is missing, the file was not uploaded through Glexir with purpose batch, endpoint doesn't match the file, or completion_window is not 24h. |
| 402 | credit_balance_exhausted, spend_limit_exceeded | The hold for the whole batch can't be reserved. |
| 403 | model_not_priced | The file's model is not sold on Glexir. |
| 404 | none | The input file or batch doesn't exist or isn't yours. |
| 429 | concurrency_limit_exceeded | Too many requests and batches in flight. |
See HTTP error codes for the full list.