Gateway API
Provon exposes an OpenAI-compatible inference API plus project-scoped discovery and Provider Key management endpoints. The configured runtime is the source of truth for endpoint and feature availability.
Base URLs#
For hosted Provon:
| Route group | Base URL |
|---|---|
| Gateway inference | https://gateway.provon.dev/v1 |
| Gateway control API | https://api.provon.dev/v1/gateway |
| Workbench | https://app.provon.dev |
For the local Node runtime:
| Route group | Base URL |
|---|---|
| Explicit Gateway inference | http://127.0.0.1:3000/gateway/v1 |
| OpenAI-compatible aliases | http://127.0.0.1:3000/v1 |
| Gateway control API | http://127.0.0.1:3000/v1/gateway |
Use the Gateway URL as the SDK base URL for model traffic. Use the API URL for discovery,
Provider Key management, and other management routes. In a one-origin self-hosted deployment,
/gateway/v1 keeps model traffic distinct from Provon's management API and OTLP routes.
export PROVON_GATEWAY_URL="https://gateway.provon.dev/v1"
export PROVON_API_URL="https://api.provon.dev/v1"Authentication#
Send a Provon project API key as a Bearer token:
Authorization: Bearer <PROVON_API_KEY>Relevant API-key capabilities:
| Capability | Grants |
|---|---|
gateway:invoke |
Model inference through the Gateway /v1/* routes or local /gateway/v1/* |
workspace:read |
Provider catalog, capability matrix, model selection, and Provider Key reads |
gateway:manage |
Provider Key and model-binding writes |
Workbench sessions use project permissions instead of these API-key capabilities.
Provider credentials are not valid Gateway client credentials. They remain attached to project-scoped Provider Keys.
First Request#
curl "$PROVON_GATEWAY_URL/chat/completions" \
-H "Authorization: Bearer $PROVON_API_KEY" \
-H "Content-Type: application/json" \
-H "x-otel-gen-ai-conversation-id: conversation-123" \
-d '{
"model": "openai/gpt-5-mini",
"messages": [{"role": "user", "content": "Hello"}]
}'The request and response follow the selected Gateway endpoint shape. Provider adapters may translate that shape to a native upstream protocol and translate the result back.
Model Values#
| Shape | Example | Behavior |
|---|---|---|
| Provider-qualified | openai/gpt-5-mini |
Pins provider resolution to openai |
| Plain model | gpt-5-mini |
Applies a matching Model Policy, then registry inference |
| Auto Router | provon/auto |
Selects an eligible mapped Provider Key model when enabled |
Provider-qualified values are the safest integration default because provider intent is explicit.
Plain names are useful when the project owns a stable logical model name. provon/auto is useful
when target selection should consider request fit, health, latency, and estimated cost.
Request Context#
Gateway context headers become OpenTelemetry attributes on the root and attempt spans. They do not change provider routing unless a separately configured policy uses the same value.
| Header | Trace attribute |
|---|---|
x-otel-gen-ai-conversation-id |
gen_ai.conversation.id |
x-otel-user-id |
user.id |
x-otel-user-hash |
user.hash |
x-otel-user-name |
user.name |
x-otel-user-full-name |
user.full_name |
x-otel-user-email |
user.email |
x-otel-session-id |
session.id |
x-otel-gen-ai-agent-id |
gen_ai.agent.id |
x-otel-gen-ai-agent-name |
gen_ai.agent.name |
x-otel-gen-ai-agent-version |
gen_ai.agent.version |
x-otel-gen-ai-workflow-name |
gen_ai.workflow.name |
Values are trimmed and limited to 512 characters. Use stable pseudonymous user IDs when raw identity is not required. Never send secrets in context headers.
Every header above is caller context: it says who is calling, not what the inference call did.
Caller context is recorded on every span of the request — the synthesized trace root, the SERVER
span for the request, and the outbound CLIENT span — so a span can always be traced back to the
conversation, agent, workflow and user it belongs to. Some of these attributes are named gen_ai.*
because that is what the OTel GenAI conventions call them; the name is not what decides the role.
What the gateway measures itself — model, token usage, cost, response, message content — is
inference telemetry and stays on the outbound CLIENT span, reported as gen_ai.* there and
mirrored as gateway.* on the SERVER span.
For multi-turn diagnostics, x-otel-gen-ai-conversation-id is the most important field: it also
sets the trace boundary, so every request carrying the same value joins one trace.
Trace Boundary#
trace_id resolves in this order:
x-otel-trace-id— explicit trace boundary.x-otel-gen-ai-conversation-id— conversation-scoped trace boundary.- the request id — one trace per request (default when neither header is sent).
A trace is a span tree, so a trace covering several requests needs a span that parents them.
For the first two cases Gateway synthesizes that root itself, marks it provon.trace.root=true,
and parents each request's SERVER span to it, giving one connected tree for the whole conversation.
Its span id is derived from the trace id, so a stateless Gateway computes the same value on every
request and the repeated writes converge onto a single row. The third case adds no such span,
because a single-request trace is already rooted by its own SERVER span.
Endpoint Discovery#
Gateway recognizes these endpoint families (the GatewayProviderEndpoint union):
chat-completions responses messages
embeddings rerank
image-generations image-edits image-variations
audio-transcriptions audio-speech moderations
batches files fine-tuning
vector-stores realtime video-extensions
video-edits videos classify
pipelineRecognition does not imply that every provider supports every family. Query the project capability matrix:
curl "$PROVON_API_URL/gateway/capability-matrix?includeDisabled=false" \
-H "Authorization: Bearer $PROVON_API_KEY"The response distinguishes:
native: the provider exposes the endpoint shape directly;translated: Provon adapts the Gateway shape to a provider-native endpoint;bridged: the public endpoint is implemented through another provider endpoint family;unsupported: the provider cannot serve that endpoint;availableordisabled: project Provider Key availability.
Inspect eligible model targets for one endpoint and feature set:
curl \
"$PROVON_API_URL/gateway/model-selection?endpoint=chat-completions&features=streaming,tool-calling" \
-H "Authorization: Bearer $PROVON_API_KEY"Supported feature filters are:
streaming tool-calling parallel-tool-calls
json-mode structured-outputs reasoning
vision-input audio-input audio-output
prompt-caching cache-read cache-write
reasoning-tokens usage-metadata native-passthrough
custom-base-urlList the provider catalog:
curl "$PROVON_API_URL/gateway/providers" \
-H "Authorization: Bearer $PROVON_API_KEY"Control API#
Project API keys with workspace:read can inspect Gateway configuration:
| Method | Path | Result |
|---|---|---|
GET |
/v1/gateway/providers |
Runtime provider catalog |
GET |
/v1/gateway/capability-matrix |
Provider and Provider Key capabilities |
GET |
/v1/gateway/model-selection |
Eligible models for endpoint/features |
GET |
/v1/gateway/provider-keys |
Project Provider Keys without raw secrets |
GET |
/v1/gateway/provider-keys/:keyId/capabilities |
One Provider Key and its model mappings |
Keys with gateway:manage can write provider targets, credentials, and model mappings:
| Method | Path | Operation |
|---|---|---|
POST |
/v1/gateway/providers |
Create a custom project-defined provider target |
PATCH |
/v1/gateway/providers/:keyId |
Update a custom provider target |
DELETE |
/v1/gateway/providers/:keyId |
Delete a custom provider target and its stored credentials |
POST |
/v1/gateway/providers/test-connection |
Validate a custom provider endpoint before saving |
POST |
/v1/gateway/provider-keys |
Attach a credential to a target and set its model mappings |
PATCH |
/v1/gateway/provider-keys/:keyId |
Update settings or rotate the stored credential secret |
DELETE |
/v1/gateway/provider-keys/:keyId |
Remove the credential and its model mappings |
POST |
/v1/gateway/provider-keys/:keyId/capabilities |
Create or update a model mapping |
DELETE |
/v1/gateway/provider-keys/:keyId/capabilities/:capabilityId |
Delete a model mapping |
PATCH |
/v1/gateway/provider-keys/:keyId/enabled |
Enable or disable a target without rotating its secret |
Note
Built-in catalog providers are listed by GET /v1/gateway/providers but are not
created, patched, or deleted through this API and do not take caller-supplied upstream
keys. The write endpoints above provision and manage only custom project-defined
providers (providerKind: "custom") together with their credentials and mappings.
Signed-in Workbench routes also expose project-qualified variants under
/v1/projects/:projectId/gateway/*. Prefer the unqualified paths for project API-key
clients because the project is already derived from the key. Reordering provider target
preference (POST /v1/projects/:projectId/gateway/provider-keys/reorder) is
project-qualified only.
Custom Providers use a project-scoped provider ID and a static driverId. An exact endpoint URL
is never extended with a protocol path:
{
"provider": "internal-kimi",
"providerKind": "custom",
"driverId": "openai-compatible",
"displayName": "Internal Kimi",
"endpointConfig": {
"mode": "exact-url",
"endpointUrls": {
"chat-completions": "https://models.example/custom/chat"
},
"endpointBridges": {
"responses": "chat-completions"
}
},
"authScheme": { "kind": "bearer" },
"apiKey": "..."
}endpointBridges.responses = "chat-completions" exposes /responses for an upstream that only
implements Chat Completions. Provon performs stateless request, response, and SSE translation.
Omit the bridge and configure a native responses endpoint URL when the upstream implements the
Responses API directly.
Common Inference Paths#
Append these operation paths to the Gateway base URL:
| Operation | Path |
|---|---|
| Chat Completions | /chat/completions |
| Responses | /responses |
| Messages, including Anthropic native passthrough | /messages |
| Embeddings | /embeddings |
| Rerank | /rerank |
| Image generation | /images/generations |
| Audio transcription | /audio/transcriptions |
| Audio speech | /audio/speech |
| Realtime client secret | /realtime/client_secrets |
| Realtime WebSocket | /realtime?model=<provider/model> |
This table lists common inference paths. The endpoint-family list above is the capability
discovery taxonomy, not a guarantee that every family has a hosted /v1/* alias. Less common or
provider-native path forms include /reranking, /realtime/calls,
/realtime/transcription_sessions, /videos/*, /classification, and /inference. MCP tool
calls are a separate Provon gateway with its own routes, not a Gateway inference path. Use the
capability matrix and the selected deployment's Gateway base URL before integrating one of these
paths.
Streaming#
For OpenAI-compatible streaming endpoints, send the normal request field:
{
"model": "openai/gpt-5-mini",
"stream": true,
"messages": [{ "role": "user", "content": "Write one sentence." }]
}The candidate target must declare streaming. Provon streams the provider-compatible response
while collecting final attempt, usage, guardrail, and trace evidence where available.
Request IDs#
Successful and failed inference responses include x-provon-request-id after request context is
established. Log this value with the application request and use it to correlate:
- the client failure;
- the Gateway root trace ID;
- upstream attempt spans;
- usage-policy and guardrail evidence.
Clients may send x-provon-request-id, but generated IDs are safer unless the caller guarantees
uniqueness.
Error Shape#
Gateway-owned errors use a JSON envelope:
{
"error": {
"code": "GATEWAY_PAUSED",
"message": "gateway is paused for this project",
"details": {}
}
}| Status | Code | Meaning |
|---|---|---|
401 |
UNAUTHORIZED |
Missing or invalid project API key |
403 |
FORBIDDEN |
Key lacks gateway:invoke or the required control capability |
404 |
UPSTREAM_NOT_CONFIGURED |
No eligible target for the requested model |
409 |
PROVON_GATEWAY_GUARD_TRIGGERED |
A configured guardrail blocked the request |
413 |
BODY_TOO_LARGE |
Request body exceeds the configured Gateway limit |
415 |
UNSUPPORTED_CONTENT_ENCODING |
Compressed request bodies are rejected |
429 |
rate_limit_exceeded |
Per-key rate-limit policy rejected the request |
429 |
gateway_budget_exceeded |
Per-key usage budget policy rejected the request |
501 |
GATEWAY_PROVIDER_KEY_MANAGER_UNAVAILABLE |
Management not configured in this runtime |
503 |
GATEWAY_PAUSED |
The project Gateway is paused |
Usage-policy rejections return 429 together with Retry-After, RateLimit-Limit,
RateLimit-Remaining, and RateLimit-Reset headers. Upstream provider errors keep their
provider-compatible shape where possible and are classified in the Gateway trace.
Transport Limits#
Runtime defaults are:
- 4 MiB for JSON request bodies;
- 8 MiB for other supported request bodies (for example
multipart/form-dataaudio or image uploads); - no compressed Gateway request body;
- a 60-second overall Gateway request deadline;
- 2 MiB maximum response body capture for telemetry.
These limits apply to the Gateway's dedicated /gateway/v1/* origin. That origin does not sit
under the platform-wide /v1/ body middleware (the middleware ignores any path that does not begin
with /v1/), so the values above are the effective ones there.
The Gateway also registers OpenAI-compatible /v1/... aliases (for example /v1/chat/completions,
/v1/responses, /v1/embeddings, /v1/messages, /v1/realtime, /v1/realtime/client_secrets,
and GET /v1/models). Because these alias paths begin with /v1/, they also sit under the
platform-wide body middleware and are capped at 1 MiB per request body before reaching the
Gateway. For larger payloads (audio, images, long prompts) send them to /gateway/v1/... rather
than the /v1/ aliases.
Deployments can override these limits. A provider may impose stricter limits.