---
title: "Batch API · OpenAI-compatible bulk jobs processed in the EU"
description: "Run thousands of chat or embedding requests as one asynchronous job with an OpenAI-compatible batch API. Upload JSONL, collect results, all in the EU."
canonical: "https://inference.eu/api/batches/"
language: "en"
---

POST /v1/batches

# Batch API: run large jobs asynchronously, processed in the EU

The batch endpoint runs many requests as one background job. You upload a JSONL file of chat completions or embeddings requests, create a batch, and collect a results file when it finishes. It is the right tool for work nobody is waiting on: classifying a ticket backlog, embedding a document archive, or running an evaluation set overnight.

[Contact sales](https://inference.eu/contact/)[Example request](#example)

1.  01API format: OpenAI
2.  02EU data centres
3.  03Covered by one DPA

POST /v1/batches

```
# ticket-classification.jsonl, one request per line:
# {"custom_id": "ticket-1042", "method": "POST", "url": "/v1/chat/completions",
#  "body": {"model": "gpt-oss-120b", "messages": [{"role": "user", "content": "Classify: ..."}]}}

curl https://api.inference.eu/v1/batches \
  -H "Authorization: Bearer $INFERENCE_EU_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "input_file_id": "file-7f3c2a",
    "endpoint": "/v1/chat/completions",
    "completion_window": "24h",
    "metadata": {"job": "ticket-backlog-2026-11"}
  }'

# Check progress
curl https://api.inference.eu/v1/batches/batch_91d0e4 \
  -H "Authorization: Bearer $INFERENCE_EU_API_KEY"
```

## What the endpoint does

`POST /v1/batches` creates a job from a file you have already uploaded with `purpose` `batch`. Pass its `input_file_id`, the `endpoint` that every line targets, such as `/v1/chat/completions`, `/v1/responses` or `/v1/embeddings`, and `completion_window`, which is `24h`. Optional `metadata` lets you tag the job with your own labels.

The response is a batch object with an `id` and a `status`. The job runs in the background, separate from your interactive traffic, so a large backlog does not compete with requests your users are waiting for. The requests and results never leave European data centres.

## Status and results

Poll `GET /v1/batches/{batch_id}` to follow progress. `status` moves from `validating` to `in_progress` and `finalizing`, then ends as `completed`, `failed`, `expired` or `cancelled`. `request_counts` shows `total`, `completed` and `failed` so you can display progress.

When the batch is `completed`, `output_file_id` points to a JSONL file. Each line has the `custom_id` from your input and a `response` with the `status_code` and the normal response `body`. Lines are not in input order, so match on `custom_id`. Failed requests go to a separate file referenced by `error_file_id`. `POST /v1/batches/{batch_id}/cancel` stops a job, and `GET /v1/batches` lists your jobs.

## A batch workflow that holds up in production

Generate the input file from your database, with a `custom_id` that is the record's primary key. Validate every line locally, upload the file, create the batch, and store the batch `id` against the job in your own system. A scheduled task checks the status every few minutes rather than holding a connection open.

When the batch completes, download the output, write the results back by `custom_id`, and collect any errors into a new, smaller input file to retry. Then delete the input and output files. Running a test batch of fifty lines first catches prompt or schema problems before you spend a large job on them.

## Errors and edge cases

A batch that fails validation, because of malformed JSON, a missing `custom_id`, duplicate ids or lines that target a different endpoint, ends with `status` `failed` and an `errors` list naming the problem and line. Fix the file and submit a new batch.

Individual requests can fail inside an otherwise successful batch, for example when one prompt exceeds the context window; those appear in the error file and do not stop the rest. If a batch is not finished within the window it becomes `expired`, and results for completed requests are still available. Batch size limits and throughput depend on your plan, and we confirm them with you.

## Batches

Endpoint

POST /v1/batches

Category

Endpoints

API format

OpenAI

Base URL

api.inference.eu/v1

Processing

EU data centres

Training on your data

Never

## Batches: common questions

The questions buyers, developers and legal teams ask us most. Something missing? Ask us directly.

Yes. The JSONL input format, the \`POST /v1/batches\` request, the batch object, its statuses and the output file format follow OpenAI's Batch API. \`client.batches.create\`, \`retrieve\`, \`list\` and \`cancel\` in the OpenAI SDKs work with the inference.eu base URL and key.

You can batch \`/v1/chat/completions\`, \`/v1/responses\` and \`/v1/embeddings\` requests. All lines in one input file must target the endpoint you name in the \`endpoint\` field when you create the batch. Use one batch per endpoint, and usually one model per batch.

Batches complete within the \`completion\_window\` of 24 hours, and many finish much sooner. How fast depends on the size of the job, the model and overall demand. If you need a guaranteed turnaround for a regular job, talk to us about your plan.

Use a batch when no one is waiting for the answer: overnight classification, bulk summaries, embedding an archive, generating product descriptions or running evaluations. Batches avoid managing concurrency and retries yourself, and they keep bulk work away from your interactive limits. Use normal requests for anything a user sees straight away.

Every output line contains the \`custom\_id\` you gave the input line. Results are not returned in input order, so join them on \`custom\_id\`, ideally the primary key of the record in your database. Make each \`custom\_id\` unique within the file.

The batch still completes, and \`request\_counts.failed\` tells you how many failed. Those requests are written to the file referenced by \`error\_file\_id\`, each with its \`custom\_id\` and error. Fix the cause, build a new input file from the failed lines and submit it as a new batch.

Yes. Call \`POST /v1/batches/{batch\_id}/cancel\`. The status becomes \`cancelling\` and then \`cancelled\`. Requests that finished before cancellation are still available in the output file, so you keep the work that was already done.

Input and output files are stored in European data centres, are accessible only with your organisation's keys and are never used to train models. Delete them through the files API once the job is complete; retention for files you do not delete is set out in your contract.

[Ask a question](https://inference.eu/contact/)

## Related

[API overview](https://inference.eu/api/)

-   [FilesUpload, list, download and delete files with an OpenAI-compatible files API. Use them for batch jobs and tools; stored in EU data centres.Endpoints](https://inference.eu/api/files/)
-   [EmbeddingsTurn text into vectors for search, RAG and clustering with an OpenAI-compatible embeddings API. Open embedding models, processed in EU data centres.Endpoints](https://inference.eu/api/embeddings/)
-   [Chat completionsSend chat messages to open-weight models with the OpenAI chat completions format. Requests are processed in EU data centres and never used for training.Endpoints](https://inference.eu/api/chat-completions/)
-   [Rate limits and errorsHow rate limits and errors work on the inference.eu API. HTTP status codes, the error object, rate-limit headers and a retry pattern that holds up.Guides](https://inference.eu/api/rate-limits-and-errors/)

## Move your AI workloads to EU infrastructure

Tell us which models you use and roughly how much traffic you have. We reply within one working day with pricing and next steps.

-   Reply within one working day
-   Pricing for your volume
-   DPA ready to sign
