n4nAI

GPT-5 batch API access through an inference gateway

Practical guide to GPT-5 batch API gateway access: setup, code, routing, cost metering, and tradeoffs versus calling OpenAI's batch endpoint directly.

n4n Team4 min read799 words

Audio narration

Coming soon — every post will get a voice note here.

If you need to process thousands of GPT-5 completions without real-time latency constraints, the GPT-5 batch API gateway access pattern gives you async throughput and provider resilience that direct OpenAI calls can’t match on their own. This guide walks through standing up batch jobs against an OpenAI-compatible gateway, with the tradeoffs you should weigh before routing production traffic.

1. What the batch API actually buys you

OpenAI’s batch endpoint accepts a file of requests and processes them within a 24-hour window at a 50% token discount. Direct integration means you manage file uploads, job polling, and per-organization rate limits yourself. A gateway sits in front of that flow and normalizes it behind a single API surface, often adding fallback and unified metering.

The core primitives are unchanged:

  • Upload a JSONL file with purpose="batch".
  • Create a batch referencing that file and an endpoint.
  • Poll status until completed.
  • Download the output file before it expires (24h after completion).

2. Point an OpenAI-compatible client at the gateway

Most gateways expose an OpenAI-compatible REST surface so you can reuse the official SDK. You only swap base_url and api_key.

from openai import OpenAI

client = OpenAI(
    base_url="https://gateway.example.com/v1",  # gateway endpoint
    api_key="your-gateway-key",
)

# Verify model availability
models = client.models.list()
print([m.id for m in models if "gpt-5" in m.id])

A gateway like n4n.ai exposes one OpenAI-compatible endpoint that addresses 240+ models and will automatically fall back when a provider is rate-limited or degraded, so your batch submission doesn’t sit in a dead queue. That matters for batch because a stuck job misses the 24h SLA and you eat the redo cost.

3. Build a correct JSONL input

Each line is a self-contained request. The url must match the batch endpoint you declare later. For chat completions:

{"custom_id": "job-001", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "gpt-5", "messages": [{"role": "user", "content": "Extract key clauses from: {{contract_text}}"}], "max_tokens": 512, "temperature": 0}}
{"custom_id": "job-002", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "gpt-5", "messages": [{"role": "user", "content": "Summarize: {{report_text}}"}], "max_tokens": 256, "temperature": 0}}

Common pitfalls:

  • Model name drift: gateway may map gpt-5 to a specific provider snapshot. Pin the exact string the gateway returns from models.list().
  • Missing max_tokens: batch jobs fail silently per-line if a param is out of range.
  • Oversized lines: keep each request body under 100KB; large prompts belong in prompt-cache, not inline repetition.

4. Upload and submit the batch

Upload the file, then create the batch. The completion_window is always "24h" for OpenAI-compatible batch.

import time

with open("batch_requests.jsonl", "rb") as f:
    file_obj = client.files.create(file=f, purpose="batch")

batch = client.batches.create(
    input_file_id=file_obj.id,
    endpoint="/v1/chat/completions",
    completion_window="24h",
)

print(f"Submitted batch {batch.id}, status {batch.status}")

Tradeoff: the gateway adds one network hop on submission, but submission is a tiny fraction of total batch latency. Don’t optimize for it.

5. Route explicitly when you need provider pinning

Some gateways honor client routing directives via headers or body extensions. If you need GPT-5 from a specific provider (e.g., for compliance), set the header your gateway documents. Forwarding provider cache-control hints is also critical—if your prompt prefix is stable across the batch, the gateway should pass cache_control so the provider caches it.

# Example with a routing header (check your gateway's spec)
batch = client.batches.create(
    input_file_id=file_obj.id,
    endpoint="/v1/chat/completions",
    completion_window="24h",
    extra_headers={"x-router-prefer": "openai"},
)

If you skip this, the gateway may load-balance across providers. That’s fine for throughput, but not if you need deterministic provider behavior for eval reproducibility.

6. Poll without burning cycles

Batch completion is async. Poll on a coarse interval; don’t hit the API every second.

while True:
    status = client.batches.retrieve(batch.id)
    if status.status in ("completed", "failed", "expired"):
        break
    time.sleep(120)  # 2-minute polling is plenty

if status.status != "completed":
    raise RuntimeError(f"Batch ended with {status.status}")

When a provider is degraded mid-job, a gateway with automatic fallback—n4n.ai does this—will shift remaining requests to a healthy route without you re-submitting. Direct OpenAI has no such escape hatch; you wait or cancel.

7. Retrieve and parse results

Output is a JSONL file keyed by custom_id. Download it promptly; OpenAI expires completed batch files after 24h, and gateways rarely extend that.

result = client.files.content(status.output_file_id)
with open("batch_output.jsonl", "wb") as f:
    f.write(result.read())

# Parse
import json
with open("batch_output.jsonl") as f:
    for line in f:
        rec = json.loads(line)
        if rec["error"]:
            print(f"{rec['custom_id']} failed: {rec['error']}")
        else:
            print(rec["custom_id"], rec["response"]["body"]["choices"][0]["message"]["content"][:80])

Per-line errors don’t fail the whole batch. You must scan for them.

8. Cost tracking and per-token metering

Batch discounts apply at the provider, but reconciling which team burned tokens is messy with direct invoices. A gateway that provides per-token usage metering lets you attribute cost by API key or tag without post-processing provider bills.

The response bodies include usage objects:

{"custom_id": "job-001", "response": {"body": {"usage": {"prompt_tokens": 120, "completion_tokens": 45, "total_tokens": 165}}}}

Aggregate those locally or rely on the gateway’s metering endpoint. Tradeoff: gateway markup (if any) is visible as a slight per-token premium over direct, but you buy resilience and observability.

9. Gateway vs OpenAI direct: the real tradeoffs

Dimension Direct OpenAI batch Via gateway
Setup Native SDK, no extra hop Change base_url, learn routing headers
Resilience No fallback; org limits hard-stop Fallback on rate-limit/degrade
Model coverage Only OpenAI models 240+ models behind same API
Cost clarity Provider invoice only Per-token metering, unified
Data path Direct to OpenAI Extra proxy; review compliance

If you’re all-in on OpenAI and never hit rate limits, direct is simpler. If you run batches at scale and can’t afford a 24h job to stall, GPT-5 batch API gateway access is the safer architecture.

10. Actionable checklist

  1. Confirm gateway model string for gpt-5 via client.models.list().
  2. Write JSONL with explicit max_tokens and stable custom_id.
  3. Upload with purpose="batch".
  4. Create batch with endpoint="/v1/chat/completions" and completion_window="24h".
  5. Set routing header only if provider pinning is required.
  6. Poll every 2 minutes; handle failed/expired states.
  7. Download output within 24h; scan every line for error.
  8. Sum usage.total_tokens per tag for cost allocation.

Follow that order and you’ll have a reproducible batch pipeline that survives provider hiccups without rewriting your client.

Tagsgpt-5batch-apigatewayopenai

Written by

n4n Team

The team building n4n — a single OpenAI-compatible API in front of 240+ models, with automatic fallback, load balancing and pay-per-token metering.

More from n4n Team →

All accessing gpt-5 via gateway vs openai direct posts →