OpenAI
Run batches on OpenAI's Batch API — JSONL upload via the Files API, polled batches, file-based results, and native webhook support.
OpenAI’s Batch API is the reference “shape” Batchwork is built around: requests are serialized to a JSONL file, uploaded via the Files API, and referenced by a batch you poll until it finishes — then the output and error files are downloaded and parsed. Batchwork does all of that for you.
| Property | Value |
|---|---|
| Shape | JSONL file upload → create batch |
| Endpoints | /v1/chat/completions, /v1/responses, /v1/completions, /v1/embeddings, /v1/images/generations, /v1/images/edits, /v1/moderations |
| Results | Output + error files (JSONL) |
| Webhooks | Native (batch.completed, batch.failed, …) |
| Env var | OPENAI_API_KEY |
| Package | @ai-sdk/openai |
| Base URL | https://api.openai.com/v1 |
Example
import { batch } from "batchwork";
import { openai } from "@ai-sdk/openai";
const job = await batch({
model: openai.chat("gpt-5.5"),
requests: [
{ customId: "fr", prompt: "Capital of France? One word." },
{ customId: "jp", prompt: "Capital of Japan? One word." },
],
});
How it works
- Build — each request becomes a JSONL line:
{ custom_id, method: "POST", url, body }. - Upload — the JSONL is uploaded to the Files API with
purpose=batch. - Create —
POST /v1/batchesreferences the uploaded file with a 24hcompletion_window. - Poll — Batchwork reads the
statusfield until the batch reaches a terminal state. - Read — the
output_file_idanderror_file_idare streamed and parsed intoBatchResults.
Batchwork validates provider-returned batch and file ids before using them in OpenAI-compatible API paths.
Request shapes
OpenAI exposes several endpoints, and Batchwork mirrors whichever your model implies:
| Model | Batch endpoint |
|---|---|
openai.chat("…") |
/v1/chat/completions |
openai("…") / openai.responses("…") |
/v1/responses |
openai.completion("…") |
/v1/completions |
openai.embeddingModel("…") |
/v1/embeddings |
openai.image("…") |
/v1/images/generations |
"openai/omni-moderation-…" string |
/v1/moderations |
A "openai/…" string defaults to chat completions — see Models. The last three rows are submitted via batch.embeddings(), batch.images(), and batch.moderations() rather than batch().
Embeddings
OpenAI text-embedding models (e.g. text-embedding-3-small) batch through /v1/embeddings — the same upload → create → poll → read flow as chat. Use batch.embeddings():
import { batch } from "batchwork";
import { openai } from "@ai-sdk/openai";
const job = await batch.embeddings({
model: openai.embeddingModel("text-embedding-3-small"),
requests: [{ customId: "a", value: "The quick brown fox." }],
});
Each request embeds one value, and the vector lands on result.embedding. Shorten it with providerOptions.openai.dimensions per request — see Embeddings.
Images
OpenAI image models (e.g. gpt-image-2) batch through /v1/images/generations — same upload → create → poll → read flow as chat, just a different per-line endpoint. Use batch.images():
import { batch } from "batchwork";
import { openai } from "@ai-sdk/openai";
const job = await batch.images({
model: openai.image("gpt-image-2"),
requests: [{ customId: "a", prompt: "A red bicycle against a brick wall." }],
});
Results come back as inline base64 on result.images[].data (with mediaType). Pass size, n, or providerOptions.openai (e.g. quality) per request — see Images.
OpenAI also batches image edits through /v1/images/edits — source images and masks are passed as JSON references (uploaded fileIds or hosted imageUrls), never raw uploads. Use batch.images.edit():
const job = await batch.images.edit({
model: openai.image("gpt-image-2"),
requests: [
{
customId: "a",
prompt: "Make the bicycle blue.",
images: [{ imageUrl: "https://example.com/bicycle.png" }],
},
],
});
Moderations
OpenAI’s omni moderation models (e.g. omni-moderation-latest) batch through /v1/moderations — text and/or image inputs per request. The AI SDK has no moderation model type, so pass the "provider/model" string form to batch.moderations():
import { batch } from "batchwork";
const job = await batch.moderations({
model: "openai/omni-moderation-latest",
requests: [
{ customId: "a", value: "…user-generated content…" },
{ customId: "b", imageUrls: ["https://example.com/upload.png"] },
],
});
The verdict lands on result.moderation (flagged, categories, categoryScores). Note the batch endpoint list does not include /v1/audio/* — see Transcriptions for the providers that batch audio.
Webhooks
OpenAI is the only provider with native batch webhooks. Mount the handler from the server layer to deliver the instant a batch completes — no tick() polling needed for OpenAI batches.
Credentials
Set OPENAI_API_KEY, or pass apiKey / baseURL / headers to batch() to override per call. Install the peer dependency:
bun add @ai-sdk/openai