OpenAI Batch API JSONL Format Guide
Learn how to structure JSONL files for OpenAI's Batch API to save 50% on costs
Last updated: February 2026
What is the OpenAI Batch API?
The OpenAI Batch API allows you to send large volumes of API requests as a single batch job. Instead of making thousands of individual API calls, you upload a JSONL file containing all your requests and OpenAI processes them asynchronously within 24 hours.
The key benefit is cost: batch requests are 50% cheaper than real-time API calls. This makes the Batch API ideal for tasks that don't need immediate responses, such as content generation, data classification, embeddings computation, and evaluation pipelines.
JSONL Request Format
Each line in the batch input JSONL file represents one API request. Every line must contain three required fields and follows a specific structure.
custom_id β A unique identifier for each request. Used to match requests with responses. Can be any string up to 512 characters.method β The HTTP method. Currently only POST is supported.url β The API endpoint path. For chat completions: /v1/chat/completions. For embeddings: /v1/embeddings.body β The request body. Same format as the corresponding API endpoint's request body.{"custom_id": "req-001", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "gpt-4o-mini", "messages": [{"role": "user", "content": "Hello"}]}}
Chat Completions Batch
The most common use case for the Batch API is sending multiple chat completion requests. Each line contains a full request with model, messages, and optional parameters like max_tokens or temperature.
Single Request
Each line contains a complete chat completion request with model, messages, and optional parameters.
{"custom_id": "task-001", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "gpt-4o-mini", "messages": [{"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "Summarize the benefits of renewable energy."}], "max_tokens": 500}}
Multiple Requests JSONL File
A batch file typically contains hundreds or thousands of requests. Here is a file with three different tasks: summarization, classification, and translation.
{"custom_id": "summary-001", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "gpt-4o-mini", "messages": [{"role": "user", "content": "Summarize: Solar energy is a renewable source of power that harnesses sunlight using photovoltaic cells."}], "max_tokens": 200}}{"custom_id": "classify-001", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "gpt-4o-mini", "messages": [{"role": "user", "content": "Classify this review as positive or negative: Great product, works perfectly!"}], "max_tokens": 50}}{"custom_id": "translate-001", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "gpt-4o-mini", "messages": [{"role": "user", "content": "Translate to French: Hello, how are you today?"}], "max_tokens": 100}}
Embeddings Batch
The Batch API also supports embedding requests, which is useful for processing large document collections. Embedding batches use the same JSONL structure but target the /v1/embeddings endpoint.
Embedding requests use a simpler body structure with model and input text.
{"custom_id": "embed-001", "method": "POST", "url": "/v1/embeddings", "body": {"model": "text-embedding-3-small", "input": "JSONL is a text format for storing structured data."}}{"custom_id": "embed-002", "method": "POST", "url": "/v1/embeddings", "body": {"model": "text-embedding-3-small", "input": "Each line contains one valid JSON object."}}{"custom_id": "embed-003", "method": "POST", "url": "/v1/embeddings", "body": {"model": "text-embedding-3-small", "input": "JSONL files use the .jsonl extension."}}
Response Format
When a batch job completes, OpenAI provides an output JSONL file where each line contains the response for one request. The response includes the original custom_id so you can match responses to requests.
Successful Response
A successful response includes the custom_id, response status code, and the full API response body.
{"id": "batch_req_abc123", "custom_id": "task-001", "response": {"status_code": 200, "body": {"id": "chatcmpl-xyz", "object": "chat.completion", "choices": [{"index": 0, "message": {"role": "assistant", "content": "Renewable energy provides numerous benefits including reduced greenhouse gas emissions, lower long-term costs, and energy independence."}}]}}, "error": null}
Error Response
Failed requests include an error object with a code and message explaining what went wrong.
{"id": "batch_req_def456", "custom_id": "task-002", "response": null, "error": {"code": "invalid_request_error", "message": "The model 'gpt-5' does not exist."}}
Complete Batch API Workflow
Here is the complete five-step workflow for using the Batch API with the Python SDK, from creating the JSONL file to downloading and parsing results.
- 1Create a JSONL file with one request per line
- 2Upload the file using the Files API with purpose set to batch
- 3Create a batch job referencing the uploaded file ID
- 4Poll the batch status until it reaches completed, failed, or cancelled
- 5Download and parse the output JSONL file to extract results
from openai import OpenAIimport jsonimport timeclient = OpenAI()# Step 1: Create the JSONL batch fileprompts = ["Summarize the benefits of renewable energy.","Classify this text as positive or negative: Great product!","Translate to French: Hello, how are you?",]requests = [{"custom_id": f"req-{i}","method": "POST","url": "/v1/chat/completions","body": {"model": "gpt-4o-mini","messages": [{"role": "user", "content": prompt}],"max_tokens": 200,},}for i, prompt in enumerate(prompts)]with open("batch_input.jsonl", "w") as f:for req in requests:f.write(json.dumps(req) + "\n")# Step 2: Upload the filebatch_file = client.files.create(file=open("batch_input.jsonl", "rb"),purpose="batch",)# Step 3: Create the batchbatch = client.batches.create(input_file_id=batch_file.id,endpoint="/v1/chat/completions",completion_window="24h",)print(f"Batch created: {batch.id}")# Step 4: Poll for completionwhile True:status = client.batches.retrieve(batch.id)print(f"Status: {status.status}")if status.status in ("completed", "failed", "cancelled"):breaktime.sleep(60)# Step 5: Download resultsif status.output_file_id:content = client.files.content(status.output_file_id)with open("batch_output.jsonl", "wb") as f:f.write(content.read())
Batch API vs Real-time API
Understanding when to use the Batch API versus the standard real-time API helps you optimize both cost and performance.
For details on JSONL format for OpenAI fine-tuning, see our OpenAI JSONL Format Guide.
Prepare Your Batch Files
Use our free tools to create, validate, and inspect your JSONL batch files before submitting to OpenAI.