Govern
Documentation

Version Latest

AI Gateway

How the Neural Inverse Govern model gateway decides every model request, its OpenAI- and Anthropic-compatible endpoints, request and response headers, and refusal codes.

The model gateway is where Govern enforces model access. Every model request from the Neural Inverse apps, your applications, agents and routed coding tools goes through it, and it decides each one against your organisation's policy before anything reaches a provider. It runs inside the Govern server, next to the database, so budgets and rate limits hold across any number of replicas and provider keys never leave the process that holds the vault.

Pages in this part

TaskPage
Connect a provider, approve models and assign themModel access
Gateway keys, keyless workload identity, coding tool tokens, authorizersGateway keys and workload identity
Spend and token budgets, rate limitsBudgets and rate limits
Routes, fallbacks, retries, circuit breaker and response cacheRouting and caching
DLP and guardrails on prompts and answersGuardrails and DLP
Request logs, provider health and attributionRequest logs and observability

Where to configure it

The console has two services for this:

  • Models: Providers and keys, Model catalog, Routing, Budgets, Assistant, and a Gateway group with Gateway endpoints, Connect a coding tool, Routes and strategies, Response cache, Guardrails, Rate limits, Request log settings and Provider health. Request logs, LLM traces and Model usage are under Monitor.
  • AI Gateway: Gateways, Endpoints and domains, Gateway keys, Workload identity, Authorizers, Protection, Usage plans, Policies, Routing and reliability, Regions, Self-hosted nodes, governance pages and observability pages.

The in-server gateway described in these docs is working. The AI Gateway service also manages dedicated gateways with their own host names served by a separate data plane; the deployment of that data plane is recorded as partial in the source, and self-hosted gateway nodes are partial too. These docs describe the in-server gateway.

How a request is decided

Every request to /api/v1/models/gateway/v1/* goes through the same steps, in order:

  1. Authenticate the caller (models:read) and parse the body.
  2. Resolve the caller's teams, project, classification, policy, catalog, assignments, settings and routes in one read-only transaction.
  3. Find the candidates: the named model and its fallback chain, or the targets of the named route. Each candidate must be usable by the caller for the request's use and classification.
  4. Apply DLP to the prompt at the level the classification requires: redact or refuse.
  5. Check rate limits, then the response cache.
  6. Dispatch to each candidate in turn: skip it while its circuit is open, check its rate limits, reserve the worst case on every budget, call the provider, retry transient failures.
  7. Relay the answer in the caller's wire format, settle actual usage, audit the attempt, store the answer in the cache when allowed.

Steps 1 to 4 fail closed. Caching, retries and routing only save or repeat a provider call; none of them can let through a request that steps 1 to 4 refuse.

Endpoints

The base URL is your API URL followed by /api/v1/models/gateway. Anthropic clients use the base URL as it is; OpenAI clients add /v1.

Method and pathFormat
POST /api/v1/models/gateway/v1/chat/completionsOpenAI chat completions
POST /api/v1/models/gateway/v1/completionsOpenAI legacy completions
POST /api/v1/models/gateway/v1/embeddingsOpenAI embeddings
POST /api/v1/models/gateway/v1/responsesOpenAI Responses API
GET /api/v1/models/gateway/v1/modelsModels and routes the caller may use
POST /api/v1/models/gateway/v1/messagesAnthropic Messages
POST /api/v1/models/gateway/v1/messages/count_tokensAnthropic token counting
POST /api/v1/models/gateway/v1/prompts/{prompt}/chat/completionsPrompt library template, OpenAI format
POST /api/v1/models/gateway/v1/prompts/{prompt}/messagesPrompt library template, Anthropic format
POST /api/v1/models/gateway/v1/rerankRerank (openai_compatible and ollama connections)
POST /api/v1/models/gateway/v1/images/generationsOpenAI image generation
POST /api/v1/models/gateway/v1/audio/transcriptionsOpenAI transcription
POST /api/v1/models/gateway/v1/audio/speechOpenAI text to speech

GET /api/v1/models/gateway/endpoints lists the same table as your deployment serves it, with full URLs. Request bodies are limited to 32 MiB. The Responses API accepts only function tools: tools the provider runs itself (web search, file search, code execution, remote MCP servers, computer use) are refused, because their traffic would never pass through DLP and the guardrails.

Provider-native paths are available for clients pinned to a provider's own API: POST /api/v1/models/gateway/anthropic/v1/messages and POST /api/v1/models/gateway/openai/v1/chat/completions (also /v1/completions, /v1/embeddings, /v1/responses). They run through the same checks and are off until an administrator turns them on; see Gateway keys and workload identity.

Example

curl -sS "$KEYSTONE_URL/api/v1/models/gateway/v1/chat/completions" \
  -H "Authorization: Bearer $GATEWAY_KEY" \
  -H "X-Keystone-Project: $PROJECT_ID" \
  -H "X-Keystone-Use: chat" \
  -H 'Content-Type: application/json' \
  -d '{"model": "claude-sonnet-5-5", "messages": [{"role": "user", "content": "Summarise this change."}]}'

The model field is a model key from your catalog or a route key.

Who can call it

The gateway accepts every Govern credential: a signed-in person's token, OAuth access tokens, API keys and agents, as long as the caller holds models:read. It adds its own:

CredentialFor
Gateway keysApplications. A key that can call the gateway and nothing else, with its own scope, models, budgets and limits.
Workload identityWorkloads that exchange a token they already have (Kubernetes, CI, a Govern agent, a client certificate) for a short-lived gateway key.
Gateway tokensCoding tools used by a person: a short-lived token bound to the person's session or enrolled device.
AuthorizersPer-route decisions by JWT, a custom HTTP or CEL authorizer, or none, for traffic without a Govern credential.

See Gateway keys and workload identity.

Request headers

HeaderEffect
X-Keystone-ProjectDecide the request in this project: its classification, policies, assignments and budgets
X-Keystone-Usechat, agent, completion or embedding; the rerank, image and audio endpoints use rerank, image and audio
X-Keystone-ClassificationRaise the request's classification; it can never lower it
X-Keystone-MetadataA JSON object of attribution, at most 16 keys and 8192 bytes
X-Keystone-TagsUp to 10 tags
X-Keystone-RetriesLower the retries of this request
X-Keystone-Cache-Controlno-cache, no-store
X-Keystone-ClientThe calling app and version, for the audit trail (advisory)
X-Keystone-Context-Request-IdThe context retrieval this request used, linked in the evidence chain

Metadata and tags are DLP-scanned like the prompt and never sent to the provider.

Response headers

HeaderValue
X-Keystone-Request-IdThe request id (later attempts are <id>.<n>)
X-Keystone-ModelThe catalog model that answered
X-Keystone-RouteThe route, when the request named one
X-Keystone-AttemptsUpstream attempts made (0 for a cache hit)
X-Keystone-Cachehit, semantic_hit, miss, bypass or off
X-Keystone-Budget-WarningA budget passed its warning threshold or a soft limit
X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-ResetWhen a rate limit rule applied
Retry-AfterWith circuit_open and rate_limited
Server-Timinggw;dur=<ms>: the gateway's own time before the response headers

Refusal codes

Refusals use each wire format's own error shape and carry X-Keystone-Request-Id.

CodeMeaning
model_not_found, model_not_allowed, use_not_supportedThe model or route is unknown, not assigned to the caller, or not for this use
classification_not_allowed, region_not_allowedThe model may not serve this classification or region
project_forbidden, project_requiredThe caller is not in the project, or the organisation requires one
dlp_blocked, dlp_unavailableDLP refused the prompt or answer, or could not run
guardrail_blockedA guardrail refused the prompt or answer
budget_exceeded, plan_limitA hard budget or the plan's limit would be crossed
rate_limitedA rate limit rule refused the request
circuit_openEvery candidate's circuit is open
no_eligible_model, provider_disabled, provider_unavailable, provider_auth_failed, key_unavailableNo usable model or provider
gateway_suspendedThe organisation's gateway was suspended by the AI security kill switch
invalid_request, service_unavailableMalformed request, or a dependency could not be reached

A provider's own error body never reaches the caller, because it can quote the prompt. The caller gets a generic refusal and the request id; operators get the body with DLP redaction applied.

For the Neural Inverse apps

The Editor and the Agents app fetch a signed view of what the person may use from GET /api/v1/models/resolved?project=<project id> and verify it with the public keys at /.well-known/neuralinverse-models-keys.json. The manifest only shapes what the app offers; the gateway decides every request again. The manifest signing key is set with NI_AUTH_MODELS_SIGNING_KEY_FILE (or _PEM) and NI_AUTH_MODELS_SIGNING_KEY_ID; without it the endpoint answers 503 models.signing_unavailable and no unsigned manifest is served.

Audit

Every attempt is audited as models.gateway.request with the decision, model, classification, tokens, cost, route and attribution, but no prompt content. Refusals are audited with their code. Configuration changes are audited in their own transaction.

Last reviewed 17 October 2026View as Markdown

AI Gateway · Docs · Neural Inverse