OpenAI API Gateway
A transparent middleman proxy for https://api.openai.com. Your client keeps speaking the exact OpenAI protocol — you change only the base URL. Requests and responses pass through byte-for-byte, including streaming.
https://openai.mrdisc.ir:9999
Overview
This gateway sits between your application and the OpenAI API. It listens on https://openai.mrdisc.ir:9999 and forwards every request to https://api.openai.com over TLS.
- Transparent pass-through. Method, path, query string, headers (including
Authorization) and the request body are forwarded exactly as you send them. The upstream response is returned exactly as OpenAI produces it — status code, headers, body and SSE event stream. - No registration. You authenticate with your own OpenAI API key. The gateway stores no keys, no accounts and no message contents.
- Location privacy. Because the outbound connection originates from the gateway server, OpenAI only ever sees the gateway's IP address. Caller-identity headers (forwarded-for, cookies, language, referer…) are removed before forwarding — see Location privacy.
- Universal compatibility. Works unchanged with the official OpenAI SDKs (Python and Node.js), LangChain, LlamaIndex, community libraries, and plain
curl— anything that can callapi.openai.com. - Self-documenting. This page is served by the gateway itself at
/and/docs.
Base URL
Replace OpenAI's API origin with the gateway origin. Keep everything else — the /v1 prefix, paths, query strings — exactly the same.
| Direct OpenAI call | Same call via gateway |
|---|---|
https://api.openai.com/v1/chat/completions | https://openai.mrdisc.ir:9999/v1/chat/completions |
https://api.openai.com/v1/embeddings | https://openai.mrdisc.ir:9999/v1/embeddings |
https://api.openai.com/v1/models | https://openai.mrdisc.ir:9999/v1/models |
SDK configuration
| Client | Setting | Value |
|---|---|---|
Python SDK (openai v1+) | base_url | https://openai.mrdisc.ir:9999/v1 |
Node.js SDK (openai) | baseURL | https://openai.mrdisc.ir:9999/v1 |
| Environment variable | OPENAI_BASE_URL | https://openai.mrdisc.ir:9999/v1 |
| Legacy Python SDK | openai.api_base | https://openai.mrdisc.ir:9999/v1 |
/v1 suffix — the same suffix you use with OpenAI's default endpoint. SDKs append the rest of the path automatically.Quick start
1 · Get an OpenAI API key
Create a key at platform.openai.com/api-keys. The gateway does not issue keys — billing, quotas and rate limits all come from your own OpenAI account.
2 · Point your client at the gateway
export OPENAI_API_KEY="sk-..." # your OpenAI key export OPENAI_BASE_URL="https://openai.mrdisc.ir:9999/v1" # the only change
3 · Make a request
curl https://openai.mrdisc.ir:9999/v1/chat/completions \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4o-mini",
"messages": [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Hello!"}
]
}'That's it. The JSON you get back is structurally identical to OpenAI's own response — same id, choices, usage, created fields, same error shapes.
Code examples
Chat completion
curl https://openai.mrdisc.ir:9999/v1/chat/completions \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4o-mini",
"messages": [{"role": "user", "content": "Hello!"}]
}'Streaming
curl -N https://openai.mrdisc.ir:9999/v1/chat/completions \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4o-mini",
"stream": true,
"messages": [{"role": "user", "content": "Write a haiku about proxies."}]
}'List models your key can access
curl https://openai.mrdisc.ir:9999/v1/models \ -H "Authorization: Bearer $OPENAI_API_KEY"
Chat completion
from openai import OpenAI
client = OpenAI(
api_key="sk-...", # your OpenAI API key
base_url="https://openai.mrdisc.ir:9999/v1", # <-- the ONLY change
)
resp = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": "Hello!"}],
)
print(resp.choices[0].message.content)Streaming
stream = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": "Count from 1 to 5."}],
stream=True, # SSE relayed in real time
)
for event in stream:
delta = event.choices[0].delta.content
if delta:
print(delta, end="", flush=True)Embeddings
emb = client.embeddings.create(
model="text-embedding-3-small",
input="The quick brown fox",
)
print(len(emb.data[0].embedding))Chat completion
import OpenAI from "openai";
const client = new OpenAI({
apiKey: "sk-...", // your OpenAI API key
baseURL: "https://openai.mrdisc.ir:9999/v1", // <-- the ONLY change
});
const resp = await client.chat.completions.create({
model: "gpt-4o-mini",
messages: [{ role: "user", content: "Hello!" }],
});
console.log(resp.choices[0].message.content);Streaming
const stream = await client.chat.completions.create({
model: "gpt-4o-mini",
messages: [{ role: "user", content: "Count from 1 to 5." }],
stream: true,
});
for await (const event of stream) {
const delta = event.choices[0]?.delta?.content ?? "";
process.stdout.write(delta);
}Plain HTTP request
import requests
r = requests.post(
"https://openai.mrdisc.ir:9999/v1/chat/completions",
headers={"Authorization": "Bearer sk-..."},
json={
"model": "gpt-4o-mini",
"messages": [{"role": "user", "content": "Hello!"}],
},
timeout=120,
)
r.raise_for_status()
print(r.json()["choices"][0]["message"]["content"])Streaming with raw HTTP
import json
import requests
with requests.post(
"https://openai.mrdisc.ir:9999/v1/chat/completions",
headers={"Authorization": "Bearer sk-..."},
json={"model": "gpt-4o-mini", "stream": True,
"messages": [{"role": "user", "content": "Hi"}]},
stream=True, timeout=300,
) as r:
for line in r.iter_lines():
if not line or not line.startswith(b"data: "):
continue
payload = line[len(b"data: "):]
if payload == b"[DONE]":
break
chunk = json.loads(payload)
delta = chunk["choices"][0]["delta"].get("content", "")
print(delta, end="", flush=True)Supported endpoints
Every path is forwarded verbatim — if OpenAI serves it, it works through the gateway. The commonly used families:
| Family | Path(s) | Notes |
|---|---|---|
| Chat Completions | POST /v1/chat/completions | tools / function calling, vision inputs, JSON mode, logprobs, stream |
| Responses API | POST /v1/responses | fully proxied; server-side state lives on OpenAI |
| Completions (legacy) | POST /v1/completions | |
| Embeddings | POST /v1/embeddings | |
| Images | POST /v1/images/generations · /edits · /variations | base64 or URL results, both pass through |
| Audio → text | POST /v1/audio/transcriptions · /translations | multipart file uploads pass through (OpenAI caps uploads at 25 MB) |
| Text → speech | POST /v1/audio/speech | binary audio response streamed back |
| Files | GET/POST /v1/files · GET /v1/files/{id}/content | downloads stream through the gateway |
| Fine-tuning | GET/POST /v1/fine_tuning/jobs · /{id} · /{id}/cancel… | |
| Batch | POST /v1/batches · GET /v1/batches/{id}… | input/output files ride the Files API |
| Models | GET /v1/models · GET /v1/models/{model} | lists everything your key can access |
| Moderations | POST /v1/moderations | |
| Anything else | any path | forwarded verbatim — new OpenAI endpoints need no gateway update |
/v1/realtime) — it requires WebSocket, and the gateway speaks HTTP + SSE only.Streaming (SSE)
Set "stream": true in the request body, exactly as with OpenAI. The gateway relays server-sent events as they arrive — there is no buffering stage, so time-to-first-token and inter-chunk timing match the direct connection (plus one network hop).
- Each SSE event is forwarded in its own TCP flush.
- The terminal
data: [DONE]marker passes through untouched. - Chunked transfer framing is re-encoded for your client, but the event payload bytes are identical.
- If your client disconnects mid-stream, the upstream leg is cancelled immediately.
See the cURL / SDK tabs in Code examples for ready-to-run streaming snippets.
Authentication
The gateway is a pure middleman — it has no accounts and no keys of its own. You present your OpenAI key exactly as you would to OpenAI:
Authorization: Bearer sk-...4A2c # your OpenAI API key, passed through untouched
- Optional
OpenAI-Organization: org-...andOpenAI-Project: proj-...headers are forwarded as well. - A missing or invalid key produces OpenAI's own
401response, verbatim — the gateway never rewrites or interprets credentials. - Keys are never logged, cached or stored anywhere on the gateway.
Passthrough fidelity
Passed through untouched
| Element | Guarantee |
|---|---|
| HTTP method | identical (GET, POST, PUT, PATCH, DELETE, HEAD) |
| Path + query string | identical, byte-for-byte |
| Request body | identical bytes (JSON, multipart/form-data, binary) |
Authorization + OpenAI-* headers | identical |
| Response status code | identical (200, 401, 429, 500…) |
| Response headers | identical (content-type, x-request-id, openai-*, x-ratelimit-*…) |
| Response body | identical bytes — same JSON structure, same usage, same id values |
| SSE event stream | identical events, relayed live |
| Error responses | OpenAI's exact error JSON, verbatim |
Transport-level adjustments (never alter the API payload)
| Adjustment | Why |
|---|---|
Host header rewritten to api.openai.com | required for TLS and HTTP/1.1 routing to the upstream |
Hop-by-hop headers dropped (Connection, Keep-Alive…) | mandated by RFC 7230 §6.1 for any proxy |
Content-Length recomputed | bookkeeping after body re-framing |
| Chunked transfer re-framing on streamed responses | lets SSE and close-delimited bodies stream to any HTTP/1.1 client |
| Caller-identity headers stripped | location privacy — see below |
| CORS headers added to responses | lets browser apps call the gateway directly — see limits |
Errors
From OpenAI (passed through verbatim)
All OpenAI-generated errors — invalid key, rate limits, context length, content filter, server errors — reach you byte-identical, with OpenAI's original status code and headers:
HTTP/1.1 401 Unauthorized
{
"error": {
"message": "Incorrect API key provided: sk-dummy. You can find your API key at https://platform.openai.com/account/api-keys.",
"type": "invalid_request_error",
"param": null,
"code": "invalid_api_key"
}
}From the gateway (only when the gateway itself fails)
The only errors the gateway generates are connectivity faults between the gateway and OpenAI. They use the same {"error": {...}} envelope so your error handling stays uniform:
HTTP/1.1 502 Bad Gateway
{
"error": {
"message": "Upstream connection failed: ...",
"type": "gateway_error",
"param": null,
"code": "upstream_unreachable"
}
}Codes you can see: upstream_unreachable (cannot reach api.openai.com) and internal_error (unexpected gateway fault). Anything else you receive came from OpenAI itself.
Location privacy
The gateway removes every header that could identify you — your network, region, browser or session — before forwarding the request. OpenAI sees a request coming from the gateway server's IP address and nothing more.
Stripped before forwarding
X-Forwarded-For X-Real-IP X-Forwarded-Host X-Forwarded-Proto X-Forwarded-Port X-Forwarded-Server X-Forwarded-Scheme Forwarded Via True-Client-IP Client-IP X-Client-IP X-Cluster-Client-IP CF-Connecting-IP CF-IPCountry CF-Ray CF-Visitor Fastly-Client-IP X-Country-Code X-Geo-Country X-Geo-Lat / X-Geo-Lon Accept-Language Referer Origin Cookie
Authorizationand request payloads are not touched — only identity/location signals are removed.- The gateway logs one line per request (IP, method, path, status, bytes, duration) for operations — never keys, never bodies.
Limits & notes
| Aspect | Value / behavior |
|---|---|
| You → gateway protocol | plain HTTP on port 9999 (no TLS on a raw IP) — trusted networks only |
| Gateway → OpenAI protocol | always HTTPS (TLS 1.2+) |
| Timeout | 600 s per socket operation — long generations and slow streams are fine |
| Request bodies | buffered in memory before forwarding (OpenAI caps uploads at 25 MB anyway) |
| Streaming | full SSE pass-through, chunk-by-chunk, zero buffering |
| WebSocket / Realtime API | not supported — every REST + SSE endpoint works |
| Rate limits | your own OpenAI account's — 429 responses pass through untouched |
| Concurrency | threaded server; upstream keep-alive connection pool of 16, scales beyond on demand |
| Logging | one line per request (IP, method, path, status, bytes, duration) — never keys or bodies |
| Latency | one extra network hop between you and OpenAI |
| CORS | enabled — browser apps may call the gateway directly; OPTIONS preflight is answered by the gateway. Remember your API key would ship to the browser, so only do this from pages your users trust. |
Health check
A local endpoint (not proxied) for uptime monitors:
curl https://openai.mrdisc.ir:9999/healthz
{"status":"ok","upstream":"api.openai.com"}This documentation page is served at / and /docs. Every other path is proxied to OpenAI.
FAQ
Do I need an account on the gateway?
No. The gateway holds no accounts. You use your own OpenAI API key, and OpenAI's billing, quotas and rate limits apply exactly as if you called them directly.
Does the gateway store my API key or conversations?
No. Keys and request/response bodies are never written to disk or memory beyond the lifetime of the request. The only persistent log is a single metadata line per request (IP, method, path, status, bytes, duration).
Which SDKs and libraries work?
Any client that speaks the OpenAI REST protocol: the official Python and Node.js SDKs, LangChain, LlamaIndex, AutoGen, community libraries, and plain HTTP clients. All you change is the base URL / OPENAI_BASE_URL.
Which models can I use?
Every model your key can access — GET /v1/models lists them. The gateway adds no model filtering or mapping.
Why am I getting a 401?
The gateway does not touch your credentials, so a 401 comes from OpenAI itself. Check that you send Authorization: Bearer <your key> and that the key is valid and has credit.
Is streaming supported?
Yes — SSE is relayed chunk-by-chunk with no buffering. The [DONE] marker and every delta event arrive in real time.
Can I call it from a browser (fetch/JS)?
Yes — CORS is enabled (Access-Control-Allow-Origin: *) and preflight OPTIONS requests are answered by the gateway. Be aware the OpenAI key would be visible in the browser, so only do this for trusted frontends.
Does it work with Azure OpenAI or other providers?
No. This gateway proxies api.openai.com only.
Is the Realtime API available?
Not yet — it needs WebSocket, while the gateway speaks HTTP and SSE only. Every other endpoint works.
What does OpenAI see about me?
Only the gateway server's IP address, the request you sent (minus identity headers), and your API key. Your own IP, region, language, cookies and referrer are stripped.