Skip to Content
Proxy Execution

Proxy Execution

Provider-native execution routes for Keel-managed requests.

For most use cases, use the SDK provider wrappers instead of calling proxy endpoints directly. The wrappers are provider-shaped clients for model calls through Keel: they handle permits, usage reporting, and error handling, and they refuse requests that carry tool definitions. They need a provider key stored in Keel and a policy that allows the model.

Use these routes when Keel should execute the provider request and record usage in the same path, and you need direct control over the proxy layer.

If provider-native payloads are not required, compare the execution surfaces in Quickstart.

Official public proxy routes

RouteStreamingCurrent exposed behavior
POST /v1/proxy/openaiYesText generation and streaming. Keel infers image understanding, GPT Image generation, audio transcription and audio generation from the payload shape, but currently refuses those requests before any provider call. Image edits are not supported.
POST /v1/proxy/anthropicYesText messages with sync and streaming support; existing nonstreaming callers receive Keel’s OpenAI-shaped response envelope.
POST /v1/proxy/anthropic/v1/messagesYesOfficial Anthropic SDK Messages path for native text requests and responses. Tool-schema calls and token counting are outside the documented SDK recipe.
POST /v1/proxy/googleYesText generation with sync and streaming support. Image-understanding requests are currently refused before any provider call.
POST /v1/proxy/xaiYesText and chat with sync and streaming support.
POST /v1/proxy/metaYesText generation with sync and streaming support, plus an embeddings subset. Image-understanding requests are currently refused before any provider call.

The five provider proxy families support SSE streaming for text generation; streaming has a current live certification on the OpenAI family only. Pass stream: true in the request payload. Requests that carry tool definitions are refused before dispatch (platform_safety_floor.unknown_action). Embeddings are sync-only. Keel dispatches only operations it can price authoritatively; image and audio operations are currently refused before dispatch (for example unsupported_operation, pricing_not_configured, or dispatch_model_not_authorized for GPT Image generation).

These routes remain provider-specific. Keel still does not expose a provider-neutral request shape here. Use POST /v1/executions when you want one canonical execution contract instead of route-specific proxy request and response shapes.

Proxy routes infer project context from the project API key; the provider-native body should not include project_id.

What the proxy path does

  • authenticates the caller with a client-scoped project API key
  • applies Keel governance before provider dispatch
  • returns the documented shape for the selected route; the Anthropic SDK Messages path returns a native Message, while the original Anthropic nonstreaming route retains its existing OpenAI-shaped envelope
  • enforces the route-specific execution controls that Keel documents publicly
  • records governance, routing, usage, and request state for later readback

Idempotency on proxy routes

  • Keel uses the Idempotency-Key header for replay protection on proxy routes
  • same key plus the same payload can replay a complete stored response without another provider dispatch
  • streaming replay requires the complete original SSE bytes within the bounded response store; if those bytes are unavailable, Keel refuses the retry with 409 rather than returning an empty successful stream or dispatching again
  • historical normalized-only stream caches cannot reconstruct the original SSE and are refused with 409. Do not switch to a new idempotency key to force a redispatch; reconcile the original outcome first.
  • same key plus a different payload returns 409 conflict
  • if the header is omitted, Keel still executes the request, but retries are treated as new executions

Hosted proxy requests require the request-freshness headers documented in Request Freshness, including retries.

Prompt Firewall scope on proxy routes

Prompt Firewall currently runs on the public proxy routes for the prompt-bearing content Keel can extract from those payloads, including:

  • POST /v1/proxy/openai
  • POST /v1/proxy/anthropic
  • POST /v1/proxy/google
  • POST /v1/proxy/xai
  • POST /v1/proxy/meta

That is still a route-dependent inspection boundary, not a claim of full provider parity across every payload field.

API example

curl

curl -i -sS https://api.keelapi.com/v1/proxy/openai \ -H "Authorization: Bearer keel_sk_your_key_here" \ -H "Content-Type: application/json" \ -H "X-Keel-Timestamp: $(date +%s)" \ -H "X-Keel-Nonce: $(openssl rand -hex 16)" \ -H "Idempotency-Key: proxy-001" \ -d '{ "model": "gpt-4o-mini", "messages": [ {"role": "user", "content": "Summarize this text in one sentence."} ], "max_tokens": 200 }'

Proxy responses follow the route-specific shapes in the table above, not the normalized execution envelope. The original Anthropic route returns an OpenAI-shaped nonstreaming response; use its /v1/messages SDK path for a native Anthropic Message. Generate a fresh timestamp and nonce for every request. Hosted Keel requires both headers; see Request Freshness.

Need the route matrix? See Route comparison.

Test this request in the Playground: Try in Playground 

JavaScript

const response = await fetch('https://api.keelapi.com/v1/proxy/openai', { method: 'POST', headers: { Authorization: 'Bearer keel_sk_your_key_here', 'Content-Type': 'application/json', 'X-Keel-Timestamp': Math.floor(Date.now() / 1000).toString(), 'X-Keel-Nonce': crypto.randomUUID(), 'Idempotency-Key': 'proxy-001' }, body: JSON.stringify({ model: 'gpt-4o-mini', messages: [ { role: 'user', content: 'Summarize this text in one sentence.' } ], max_tokens: 200 }) }) const data = await response.json() console.log(data)

Python

import requests import secrets import time response = requests.post( "https://api.keelapi.com/v1/proxy/openai", headers={ "Authorization": "Bearer keel_sk_your_key_here", "Content-Type": "application/json", "X-Keel-Timestamp": str(int(time.time())), "X-Keel-Nonce": secrets.token_hex(16), "Idempotency-Key": "proxy-001", }, json={ "model": "gpt-4o-mini", "messages": [ { "role": "user", "content": "Summarize this text in one sentence.", } ], "max_tokens": 200, }, ) print(response.json())

Response example

{ "id": "chatcmpl-B9MBs8CjcvOU2jLn4n570S5qMJKcT", "object": "chat.completion", "created": 1764104521, "model": "gpt-4o-mini-2024-07-18", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "The text says the team shipped the feature ahead of schedule and will monitor adoption over the next week." }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 21, "completion_tokens": 18, "total_tokens": 39 } }
const requestId = data.id const model = data.model const text = data.choices?.[0]?.message?.content ?? null const finishReason = data.choices?.[0]?.finish_reason ?? null const providerErrorMessage = data.error?.message ?? null

For the canonical route matrix, see Route comparison.

Routing boundary

Routing and fallback controls are route-specific. Not all proxy routes support the same routing and fallback capabilities. See the provider support table for current coverage.

Current non-claims

  • no claim that proxy routes are provider-neutral
  • realtime governance uses /v1/sessions; proxy routes do not carry realtime provider media or replace the customer-operated voice sidecar
  • advanced operation coverage (image generation, audio, embeddings) varies by provider — see the provider support table
  • cost estimation accuracy varies by operation type, with multimodal operations relying on heuristic pre-dispatch estimates
Last updated on Edit this page on GitHub