Batches (end-to-end)
This page shows a practical end-to-end flow:
- Create a JSONL input file
- Upload it with
purpose: "batch" - Create a Batch pointing at the uploaded file
- Poll Batch status
- Download and parse the output JSONL
See Batch JSONL input format and Batches API.
1) Create an input JSONL file
Each line is a request object with custom_id, method, url, and body.
jsonl
{"custom_id":"req-1","method":"POST","url":"/v1/responses","body":{"model":"gpt-4.1","input":"Say hi in one sentence."}}
{"custom_id":"req-2","method":"POST","url":"/v1/responses","body":{"model":"gpt-4.1","input":"What is 2+2?"}}Save it as input.jsonl.
2) Upload the JSONL as a File (purpose=batch)
bash
curl https://api.fastapi.ai/v1/files \
-H "Authorization: Bearer $FAST_API_KEY" \
-F purpose="batch" \
-F file="@input.jsonl"javascript
import fs from "node:fs";
const form = new FormData();
form.append("purpose", "batch");
const file = new Blob([fs.readFileSync("input.jsonl")], { type: "application/jsonl" });
form.append("file", file, "input.jsonl");
const res = await fetch("https://api.fastapi.ai/v1/files", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.FAST_API_KEY}` },
body: form,
});
console.log(await res.json());python
import os
import requests
resp = requests.post(
"https://api.fastapi.ai/v1/files",
headers={"Authorization": f"Bearer {os.environ['FAST_API_KEY']}"},
files={"file": ("input.jsonl", open("input.jsonl", "rb"), "application/jsonl")},
data={"purpose": "batch"},
)
print(resp.json())go
package main
import (
"bytes"
"fmt"
"io"
"mime/multipart"
"net/http"
"os"
)
func main() {
var buf bytes.Buffer
w := multipart.NewWriter(&buf)
_ = w.WriteField("purpose", "batch")
file, _ := os.Open("input.jsonl")
defer file.Close()
fw, _ := w.CreateFormFile("file", "input.jsonl")
_, _ = io.Copy(fw, file)
_ = w.Close()
req, _ := http.NewRequest("POST", "https://api.fastapi.ai/v1/files", &buf)
req.Header.Set("Authorization", "Bearer "+os.Getenv("FAST_API_KEY"))
req.Header.Set("Content-Type", w.FormDataContentType())
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
}java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Files;
import java.nio.file.Path;
public class Main {
public static void main(String[] args) throws Exception {
String boundary = "----FastAPIBoundary";
byte[] fileBytes = Files.readAllBytes(Path.of("input.jsonl"));
String part1 =
"--" + boundary + "\r\n" +
"Content-Disposition: form-data; name=\"purpose\"\r\n\r\n" +
"batch\r\n";
String part2Header =
"--" + boundary + "\r\n" +
"Content-Disposition: form-data; name=\"file\"; filename=\"input.jsonl\"\r\n" +
"Content-Type: application/jsonl\r\n\r\n";
String partEnd = "\r\n--" + boundary + "--\r\n";
byte[] body = concat(part1.getBytes(), part2Header.getBytes(), fileBytes, partEnd.getBytes());
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.fastapi.ai/v1/files"))
.header("Authorization", "Bearer " + System.getenv("FAST_API_KEY"))
.header("Content-Type", "multipart/form-data; boundary=" + boundary)
.POST(HttpRequest.BodyPublishers.ofByteArray(body))
.build();
HttpResponse<String> resp = HttpClient.newHttpClient().send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(resp.body());
}
private static byte[] concat(byte[]... parts) {
int len = 0;
for (byte[] p : parts) len += p.length;
byte[] out = new byte[len];
int pos = 0;
for (byte[] p : parts) {
System.arraycopy(p, 0, out, pos, p.length);
pos += p.length;
}
return out;
}
}The response includes a file_id (for example, file-abc123).
3) Create the batch
bash
curl https://api.fastapi.ai/v1/batches \
-H "Authorization: Bearer $FAST_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"input_file_id": "file-abc123",
"endpoint": "/v1/responses",
"completion_window": "24h"
}'javascript
const res = await fetch("https://api.fastapi.ai/v1/batches", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.FAST_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
input_file_id: "file-abc123",
endpoint: "/v1/responses",
completion_window: "24h",
}),
});
console.log(await res.json());python
import os
import requests
resp = requests.post(
"https://api.fastapi.ai/v1/batches",
headers={
"Authorization": f"Bearer {os.environ['FAST_API_KEY']}",
"Content-Type": "application/json",
},
json={
"input_file_id": "file-abc123",
"endpoint": "/v1/responses",
"completion_window": "24h",
},
)
print(resp.json())go
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
)
func main() {
payload := map[string]any{
"input_file_id": "file-abc123",
"endpoint": "/v1/responses",
"completion_window": "24h",
}
b, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", "https://api.fastapi.ai/v1/batches", bytes.NewReader(b))
req.Header.Set("Authorization", "Bearer "+os.Getenv("FAST_API_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
}java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Main {
public static void main(String[] args) throws Exception {
String body = "{\"input_file_id\":\"file-abc123\",\"endpoint\":\"/v1/responses\",\"completion_window\":\"24h\"}";
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.fastapi.ai/v1/batches"))
.header("Authorization", "Bearer " + System.getenv("FAST_API_KEY"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse<String> resp = HttpClient.newHttpClient().send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(resp.body());
}
}The response includes a batch_id (for example, batch_abc123).
4) Poll for completion
bash
curl https://api.fastapi.ai/v1/batches/batch_abc123 \
-H "Authorization: Bearer $FAST_API_KEY"javascript
const batchId = "batch_abc123";
while (true) {
const res = await fetch(`https://api.fastapi.ai/v1/batches/${batchId}`, {
headers: { Authorization: `Bearer ${process.env.FAST_API_KEY}` },
});
if (!res.ok) throw new Error(`HTTP ${res.status}: ${await res.text()}`);
const batch = await res.json();
console.log("status:", batch.status);
if (["completed", "failed", "cancelled", "expired"].includes(batch.status)) break;
await new Promise((r) => setTimeout(r, 5000));
}python
import os
import time
import requests
batch_id = "batch_abc123"
while True:
resp = requests.get(
f"https://api.fastapi.ai/v1/batches/{batch_id}",
headers={"Authorization": f"Bearer {os.environ['FAST_API_KEY']}"},
)
resp.raise_for_status()
batch = resp.json()
print("status:", batch.get("status"))
if batch.get("status") in ("completed", "failed", "cancelled", "expired"):
break
time.sleep(5)go
package main
import (
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"time"
)
func main() {
batchID := "batch_abc123"
for {
req, _ := http.NewRequest("GET", "https://api.fastapi.ai/v1/batches/"+batchID, nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("FAST_API_KEY"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
body, _ := io.ReadAll(resp.Body)
resp.Body.Close()
var batch map[string]any
_ = json.Unmarshal(body, &batch)
fmt.Println("status:", batch["status"])
status, _ := batch["status"].(string)
if status == "completed" || status == "failed" || status == "cancelled" || status == "expired" {
break
}
time.Sleep(5 * time.Second)
}
}java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Main {
public static void main(String[] args) throws Exception {
String batchId = "batch_abc123";
HttpClient client = HttpClient.newHttpClient();
while (true) {
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.fastapi.ai/v1/batches/" + batchId))
.header("Authorization", "Bearer " + System.getenv("FAST_API_KEY"))
.GET()
.build();
HttpResponse<String> resp = client.send(req, HttpResponse.BodyHandlers.ofString());
String body = resp.body();
System.out.println("status: " + body);
if (body.contains("\"status\":\"completed\"") ||
body.contains("\"status\":\"failed\"") ||
body.contains("\"status\":\"cancelled\"") ||
body.contains("\"status\":\"expired\"")) {
break;
}
Thread.sleep(5000);
}
}
}When the batch is completed, the batch object typically includes output_file_id. If it failed, check error_file_id.
5) Download and parse output JSONL
See Batch outputs (download + parse JSONL) for multi-language parsing examples.
Minimal example (Python):
python
import json
import os
import requests
output_file_id = "file-OUTPUT"
resp = requests.get(
f"https://api.fastapi.ai/v1/files/{output_file_id}/content",
headers={"Authorization": f"Bearer {os.environ['FAST_API_KEY']}"},
)
resp.raise_for_status()
for line in resp.text.splitlines():
row = json.loads(line)
custom_id = row.get("custom_id")
status = row.get("response", {}).get("status_code")
body = row.get("response", {}).get("body")
print(custom_id, status, body)