The AI gateway for your AI gateways. Finally.
Gateway Gateway is a functional joke and a small OpenAI-compatible meta-proxy. Put it in front of OpenRouter, LiteLLM, Portkey, Vercel AI Gateway, Helicone, a Cloudflare AI Gateway endpoint, or any other gateway that accepts OpenAI-shaped JSON.
It gives you one more base URL, because the missing piece in your AI stack was another layer.
- Proxies POST requests below
/v1/* - Supports streaming responses without buffering successful upstreams
- Routes by priority, random selection, or best-effort in-memory round robin
- Falls back on network errors, timeouts, 408, 409, 425, 429, and 5xx responses
- Selects a gateway with
x-gateway-gateway: openrouter - Selects a gateway in the model name with
openrouter::openai/gpt-4o-mini - Rewrites
gateway-gateway/autoto each gateway's configured default model - Adds the extremely important
x-gateway-gateway-governance: ISO-42069-pendingheader - Never forwards the caller's authorization header to an upstream
It does not translate proprietary, non-OpenAI request formats. “All gateways” means all gateways that can be described by a base URL, auth header, and OpenAI-compatible request body. Satire has limits; HTTP has more.
Set GATEWAY_GATEWAY_API_KEY to a random secret. Clients send it as Authorization: Bearer ... or x-api-key: ....
👉 Add GATEWAY_GATEWAY_API_KEY here: https://www.val.town/x/stevekrouse/gateway-gateway/environment-variables?key=GATEWAY_GATEWAY_API_KEY
This example uses OPENROUTER_API_KEY.
👉 Add OPENROUTER_API_KEY here: https://www.val.town/x/stevekrouse/gateway-gateway/environment-variables?key=OPENROUTER_API_KEY
Set GATEWAY_GATEWAY_CONFIG to JSON:
{ "strategy": "cascade", "defaultGateway": "openrouter", "gateways": [ { "name": "openrouter", "baseUrl": "https://openrouter.ai/api/v1", "apiKeyEnv": "OPENROUTER_API_KEY", "defaultModel": "openai/gpt-4o-mini", "priority": 1, "timeoutMs": 45000 } ] }
👉 Add GATEWAY_GATEWAY_CONFIG here: https://www.val.town/x/stevekrouse/gateway-gateway/environment-variables?key=GATEWAY_GATEWAY_CONFIG
Each gateway accepts:
| Field | Meaning |
|---|---|
name | Routing name; letters, numbers, _, and - |
baseUrl | OpenAI-compatible base URL, usually ending in /v1 |
apiKeyEnv | Name of the Val environment variable containing its credential |
authHeader | Header name; defaults to authorization |
authScheme | Prefix; defaults to Bearer |
defaultModel | Used by the gateway-gateway/auto model |
extraHeaders | Static values or env references such as {"x-key":"$OTHER_SECRET"} |
priority | Lower runs first in cascade mode |
timeoutMs | Per-gateway timeout; defaults to 45 seconds |
enabled | Set to false for a strategic pause |
For every $OTHER_SECRET or apiKeyEnv you name, add that key in the val's environment-variable settings.
Endpoint:
https://stevekrouse--019f9097610472099669fc1af7725c68.web.val.run/v1
curl https://stevekrouse--019f9097610472099669fc1af7725c68.web.val.run/v1/chat/completions \ -H "Authorization: Bearer $GATEWAY_GATEWAY_KEY" \ -H "x-gateway-gateway: openrouter" \ -H "Content-Type: application/json" \ -d '{ "model": "openai/gpt-4o-mini", "messages": [{"role": "user", "content": "Why did we do this?"}] }'
Or leave out x-gateway-gateway and let the configured strategy make an executive decision.
Useful read-only routes:
GET /health— operational statusGET /api/status— status for the landing pageGET /v1/models— synthetic model listGET /v1/gateways— safe gateway metadata; never secret values
Portkey-style credentials can use a custom header:
{ "name": "portkey", "baseUrl": "https://api.portkey.ai/v1", "apiKeyEnv": "PORTKEY_API_KEY", "authHeader": "x-portkey-api-key", "authScheme": "" }
A self-hosted LiteLLM proxy generally uses the defaults:
{ "name": "litellm", "baseUrl": "https://litellm.example.com/v1", "apiKeyEnv": "LITELLM_API_KEY", "defaultModel": "gpt-4o-mini" }
👉 Add PORTKEY_API_KEY here: https://www.val.town/x/stevekrouse/gateway-gateway/environment-variables?key=PORTKEY_API_KEY
👉 Add LITELLM_API_KEY here: https://www.val.town/x/stevekrouse/gateway-gateway/environment-variables?key=LITELLM_API_KEY
Add those credential keys before enabling the entries.
The relay refuses all proxy traffic until an inbound API key is configured. Secrets stay in encrypted Val environment variables. Caller cookies and authorization are not forwarded. Successful upstream responses stream through, while retryable error bodies are buffered so another gateway can be tried.
Gateway URLs are trusted configuration. Anyone who can edit the val's encrypted configuration can choose an internal URL, so treat editor access as privileged.
See AGENTS.md for the current file map.
Built on Val Town. Regrettably real.