Skip to content
OpenRelay is in early access, and the /v1 API is stable. New capabilities ship in the changelog.
GuidesInference APIsBatch API

Files

Upload batch input files as JSONL (a direct multipart upload for smaller files, a presigned URL for large ones), then read file metadata and content.

Batch input and result files are JSONL blobs held by the gateway. Input files carry purpose: "batch"; result files are produced by the batch itself, and a batch create that rejects records writes a rejections file. Files are limited to 200 MB and 50,000 records, and are retained for 30 days.

There are two ways to upload an input file:

  • Direct multipart (POST /v1/files): one request, best for files you send from a server.
  • Presign + complete (POST /v1/files/presign then POST /v1/files/{id}/complete): upload the bytes straight to storage with a signed URL, then register the file. Use this for large files or browser uploads.

The file object returned by every endpoint below is:

FieldTypeDescription
idstringThe file id (file_…). Pass it as input_file_id when creating a batch.
objectstringAlways "file".
bytesintegerFile size in bytes.
created_atintegerUnix seconds when the file was registered.
expires_atintegerUnix seconds when the file is deleted (30 days after creation).
filenamestringA server-assigned name.
purposestring"batch" for input files, "batch_output" and "batch_error" for a batch's result files, and "batch_rejections" for the records a create rejected.

Upload a file (direct)

POST https://inference.openrelay.inc/v1/files

A multipart/form-data body with two parts: purpose (must be batch) and file (the JSONL).

curl https://inference.openrelay.inc/v1/files \
  -H "Authorization: Bearer $OPENRELAY_API_KEY" \
  -F "purpose=batch" \
  -F "file=@requests.jsonl"
{
  "id": "file-a1b2c3d4e5f6a7b8c9d0e1f2",
  "object": "file",
  "bytes": 412,
  "created_at": 1752460800,
  "expires_at": 1755052800,
  "filename": "file-a1b2c3d4e5f6a7b8c9d0e1f2.jsonl",
  "purpose": "batch"
}

A file over 200 MB returns 413; a file with more than 50,000 records (blank lines are not records), a missing or empty file part, or a purpose other than batch returns 400. If image inputs push you over the size limit, compress them first; see Best practices.

The upload checks only that the file is JSONL. A file that is not returns 400 with code: "invalid_file" and a message saying why: it contains a NUL byte (a binary file, or text saved as UTF-16 or UTF-32), it starts with a UTF-16 or UTF-32 byte-order mark (save it as UTF-8), it has no records, or none of its lines is valid JSON (lines over 64 KiB are not checked here). The records themselves are checked when you create a batch from the file, which rejects the invalid ones and runs the rest. CLI: orl files upload requests.jsonl streams the same multipart upload.

An upload takes no Idempotency-Key: repeating one stores a second file with a new id, which costs nothing until a batch runs it. The batch create does take one; see Retry a create safely.

Upload a file (presigned)

For large files, or when uploading from a browser, get a signed URL, PUT the bytes to it, then register the file.

1. Presign

POST https://inference.openrelay.inc/v1/files/presign
FieldTypeDescription
bytesinteger (required)The exact size of the file you will upload, 1 to 200 MB.
filenamestringOptional; ignored by the server (parity with direct upload).
curl https://inference.openrelay.inc/v1/files/presign \
  -H "Authorization: Bearer $OPENRELAY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "bytes": 5242880 }'
{
  "file_id": "file-a1b2c3d4e5f6a7b8c9d0e1f2",
  "put_url": "https://…signed-url…",
  "expires_at": 1752461701
}

The put_url is valid for 15 minutes. No file is registered yet.

2. PUT the bytes

Upload the raw JSONL to put_url with an HTTP PUT:

curl -X PUT "$PUT_URL" --upload-file requests.jsonl

3. Complete

POST https://inference.openrelay.inc/v1/files/{id}/complete

Registers the uploaded object. The gateway checks it as the direct upload checks a file (the size, the record count, and that it is JSONL) and returns the file object. This call is idempotent: completing an already-registered id returns its existing file object.

curl https://inference.openrelay.inc/v1/files/file-a1b2c3d4e5f6a7b8c9d0e1f2/complete \
  -H "Authorization: Bearer $OPENRELAY_API_KEY" \
  -X POST
{
  "id": "file-a1b2c3d4e5f6a7b8c9d0e1f2",
  "object": "file",
  "bytes": 5242880,
  "created_at": 1752460900,
  "expires_at": 1755052900,
  "filename": "file-a1b2c3d4e5f6a7b8c9d0e1f2.jsonl",
  "purpose": "batch"
}

Complete returns 404 if nothing was uploaded to the id, and 400 if the object is empty, over 200 MB, over 50,000 records, or not JSONL (invalid_file); the object is discarded in those cases. It returns 429 when too many uploads are being processed at once: retry shortly.

Get file metadata

GET https://inference.openrelay.inc/v1/files/{id}
curl https://inference.openrelay.inc/v1/files/file-a1b2c3d4e5f6a7b8c9d0e1f2 \
  -H "Authorization: Bearer $OPENRELAY_API_KEY"

Returns the file object, or 404 if the id is unknown to your organization.

Download file content

GET https://inference.openrelay.inc/v1/files/{id}/content

Streams the raw file bytes (application/octet-stream). Use it to read a batch's output_file_id or error_file_id, a create's rejected_records_file_id, or to read back an input file.

curl https://inference.openrelay.inc/v1/files/file-batch_9f8e7d6c5b4a-output/content \
  -H "Authorization: Bearer $OPENRELAY_API_KEY" \
  -o results.jsonl

On this page