# OpenAI Gateway An OpenAI-compatible proxy mounted at `/openai/v1`. It forwards requests to a configured upstream using the gateway's own credentials, so no DevPlace key is required - but an administrator must enable the `openai` service first. Point any OpenAI-compatible client at `https://devplace.net/openai/v1`. This gateway is the **single point of truth for AI** on the platform. Every other DevPlace service (news, bots, Devii) calls it by default instead of an external provider, sends the generic model name `molodetz`, and authenticates with an internal key that is auto-generated on first boot. The real provider URLs, models, and keys (DeepSeek, OpenRouter) live only here, so an operator switches providers or backends in one place. `DEEPSEEK_API_KEY` and `OPENROUTER_API_KEY` are migrated into the editable settings on boot and the value in use is shown. Because `Force model` is on by default, the upstream always receives the configured model regardless of what a client (or `molodetz`) requests. The gateway also performs **vision** augmentation: when a request includes an image, the gateway describes the image with a configured vision model and rewrites it to text, so a vision-less upstream still works. The vision model, URL, and key are configured alongside the other gateway settings. The gateway additionally serves **text embeddings** at `/openai/v1/embeddings`. Clients request the generic model `molodetz~embed`, which the gateway maps to the configured embedding model (OpenRouter's Qwen3 8B embedding model by default). Usage and cost are tracked per call exactly like chat and vision. The gateway also serves **image generation** at `/openai/v1/images/generations`. Clients request the generic model `molodetz-img-small`, which the gateway maps to the configured image model (OpenRouter's Flux 1.1 Pro by default). Cost is tracked per call with a flat per-image price when the upstream returns no native cost. ## Quick start Copy the command below and paste it into a terminal. If you are signed in the `YOUR_API_KEY` and `user-app-v-13.37.0` placeholders are already filled in with your own values; otherwise replace them with the API key from your [profile](/profile) page and any application identifier. ```bash curl -X POST "https://devplace.net/openai/v1/chat/completions" -H "Authorization: Bearer YOUR_API_KEY" -H "X-App-Reference: user-app-v-13.37.0" -H "Content-Type: application/json" -d '{ "model": "molodetz", "messages": [{"role": "user", "content": "Hello, how are you?"}] }' ``` The response carries `X-Gateway-*` headers with token counts and dollar cost for the call. For streaming, add `"stream": true` to the JSON body. ## Model routing and providers On top of the single default upstream above, an administrator can register additional named **providers** and map any number of requested **model names** onto them, so one gateway can front many models across many backends. A model route binds a source model name (what a client sends) to a target provider and upstream model, and carries: - its **own pricing economy** (input, output, and cache-hit / cache-miss prices per million tokens), used to compute that call's cost when the upstream returns no native cost; - an optional **vision model**, which turns on the image-to-text merge for that route (so a text-only model can answer about images); - an optional **context window** used for the context-utilization header. Resolution is transparent to clients: when the requested `model` matches an active route, the gateway forwards to that route's provider and target model and meters the call against the route's economy. When it matches no route, the request falls through to the default upstream unchanged (so `molodetz`, `molodetz~embed`, and any existing client keep working exactly as before). Providers and routes are managed by administrators on the **Gateway** page (`/admin/gateway`). ## Per-call cost and usage headers Every gateway response - chat, embeddings, and passthrough, on both success and error - carries `X-Gateway-*` response headers describing that single call, so a client can read its own token usage and dollar cost directly from the response with no extra request: | Header | Meaning | |--------|---------| | `X-Gateway-Model` | Upstream model actually used for the call | | `X-Gateway-Backend` | Backend that served it: `chat`, `embed`, `image`, or passthrough | | `X-Gateway-Prompt-Tokens` | Input (prompt) tokens | | `X-Gateway-Completion-Tokens` | Output (completion) tokens | | `X-Gateway-Total-Tokens` | Total tokens (prompt + completion) | | `X-Gateway-Cache-Hit-Tokens` | Prompt tokens served from the upstream prompt cache | | `X-Gateway-Cache-Miss-Tokens` | Prompt tokens not served from cache | | `X-Gateway-Reasoning-Tokens` | Reasoning tokens, when the model reports them | | `X-Gateway-Cost-USD` | Total cost of the call in US dollars | | `X-Gateway-Input-Cost-USD` | Input portion of the cost in US dollars | | `X-Gateway-Output-Cost-USD` | Output portion of the cost in US dollars | | `X-Gateway-Cost-Native` | `1` if the dollar cost is the upstream's own reported cost, `0` if computed from the configured per-million pricing | | `X-Gateway-Tokens-Per-Second` | Output tokens per second for the call | | `X-Gateway-Upstream-Latency-Ms` | Upstream round-trip latency in milliseconds | | `X-Gateway-Total-Latency-Ms` | Full end-to-end gateway time for the call in milliseconds | | `X-Gateway-Gateway-Overhead-Ms` | Gateway processing time minus the upstream and queue wait, in milliseconds | | `X-Gateway-Queue-Wait-Ms` | Time spent waiting on the concurrency semaphore before dispatch, in milliseconds | | `X-Gateway-Connect-Ms` | Upstream connection establishment time in milliseconds | | `X-Gateway-Context-Window` | The model's context window in tokens, when known | | `X-Gateway-Context-Utilization` | Total tokens as a fraction of the context window, when known | Dollar costs use the upstream's native `cost` field when it returns one (`X-Gateway-Cost-Native: 1`); otherwise they are computed from the per-million prices of the matched model route, falling back to the prices configured on the `openai` service when no route matches. The denied paths that make no upstream call (embeddings or image generation disabled) return no usage headers. ## Request header `X-App-Reference` Clients **SHOULD** send an `X-App-Reference` header to identify themselves for cost attribution. The value is a free-form slug (max 30 characters, letters, digits, `_`, `.`, `-`). When missing or invalid, the gateway defaults to `default`. The value is recorded in every usage ledger row and can be queried alongside owner-kind and owner-id to attribute spending per application. ``` X-App-Reference: devplace-devii-v-1-0-0 ``` Administrators enable and configure this gateway under [Background Services](/docs/services.html) (the `openai` service). The gateway is exempt from rate limiting, but every other endpoint follows the shared [Conventions & Errors](/docs/conventions.html); see [Authentication](/docs/authentication.html) for signing DevPlace's own requests.
POST /openai/v1/chat/completions Minimal role: Public

Chat completions

OpenAI-compatible chat completion. Supports streaming.

POST /openai/v1/embeddings Minimal role: Public

Embeddings

OpenAI-compatible text embeddings. Request model molodetz~embed.

POST /openai/v1/images/generations Minimal role: Public

Image generation

OpenAI-compatible image generation. Request model molodetz-img-small.

POST /openai/v1/{path} Minimal role: Public

Passthrough

Any other /v1 path is forwarded to the upstream as-is.