API / add-requests-to-a-batch-via-jsonl

API

Add Batch API requests from a JSONL file

Add Batch API requests from a JSONL file

For scripted or pipeline-built Batch jobs, upload a JSONL file through the Files API, then create the batch with input_file_id. Each line is one request. Caps: 200 MB and 50,000 requests. File-based batches are sealed — you cannot call AddBatchRequests afterward. Overview of create / poll / results: Run a Batch API job.

Line format

Each line is a JSON object with four fields:

Field Rule
custom_id Unique in the file; maps to batch_request_id on results
method Always "POST"
url Endpoint path (/v1/responses, /v1/chat/completions, /v1/images/generations, …)
body Payload for that endpoint

You can mix endpoints in one file. Each line is routed on its own.

{"custom_id": "chat-1", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "grok-4.3", "messages": [{"role": "user", "content": "Classify: The product exceeded my expectations!"}]}}
{"custom_id": "search-1", "method": "POST", "url": "/v1/responses", "body": {"model": "grok-4.3", "tools": [{"type": "web_search"}, {"type": "x_search"}], "input": [{"role": "user", "content": "What are the latest SpaceX launches?"}]}}
{"custom_id": "img-1", "method": "POST", "url": "/v1/images/generations", "body": {"model": "grok-imagine-image-2.0", "prompt": "A futuristic city skyline at sunset"}}

Check each model page — unsupported models reject batch lines. Prefer a Batch-listed model such as grok-4.3 when the docs say grok-4.5 is unsupported for Batch.

Upload, then create

# 1) Upload the JSONL
curl -X POST https://api.x.ai/v1/files \
  -H "Authorization: Bearer $XAI_API_KEY" \
  -F file="@batch_requests.jsonl"

# 2) Create the batch with that file id
curl -X POST https://api.x.ai/v1/batches \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $XAI_API_KEY" \
  -d '{"name": "sentiment_analysis", "input_file_id": "file-abc123"}'
import os
from xai_sdk import Client

client = Client(api_key=os.getenv("XAI_API_KEY"))
file = client.files.upload(file=open("batch_requests.jsonl", "rb"))
batch = client.batch.create(batch_name="sentiment_analysis", input_file_id=file.id)
print(batch.batch_id)

If any line is invalid, the batch is cancelled with an error. Poll and fetch results the same way as inline batches. Pricing: Batch API Pricing.

Pitfalls

  • Duplicate custom_id values in the file.
  • Calling AddBatchRequests on a file-based batch — sealed after create.
  • Leaving Imagine result URLs un-downloaded (they expire about an hour after completion).