Public
Remixed
The AI gateway for your AI gateways. Finally.
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.

Gateway Gateway™

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.

What it actually does

  • 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/auto to each gateway's configured default model
  • Adds the extremely important x-gateway-gateway-governance: ISO-42069-pending header
  • 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.

Setup

1. Protect the inbound endpoint

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

2. Add your downstream credential

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

3. Configure the board of gateways

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:

FieldMeaning
nameRouting name; letters, numbers, _, and -
baseUrlOpenAI-compatible base URL, usually ending in /v1
apiKeyEnvName of the Val environment variable containing its credential
authHeaderHeader name; defaults to authorization
authSchemePrefix; defaults to Bearer
defaultModelUsed by the gateway-gateway/auto model
extraHeadersStatic values or env references such as {"x-key":"$OTHER_SECRET"}
priorityLower runs first in cascade mode
timeoutMsPer-gateway timeout; defaults to 45 seconds
enabledSet to false for a strategic pause

For every $OTHER_SECRET or apiKeyEnv you name, add that key in the val's environment-variable settings.

Use it

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 status
  • GET /api/status — status for the landing page
  • GET /v1/models — synthetic model list
  • GET /v1/gateways — safe gateway metadata; never secret values

Configuration examples

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.

Security notes

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.

Files

See AGENTS.md for the current file map.

Built on Val Town. Regrettably real.