OpenRouter integration
Run OpenRouter traffic through the ACE gateway: endpoint, the headers a call sets, what passes through untouched, and a runnable example.
OpenRouter is the openai channel pointed at https://openrouter.ai/api/v1, and it works today. The ACE key is the SDK's api_key; the OpenRouter key rides on x-ace-openai-key and is used for that call only. Model slugs and OpenRouter's own body fields (models, provider, transforms) reach OpenRouter as sent, and x-ace-served-by names the channel (openai), not the host. Storing the OpenRouter key as the tenant's openai vendor key, with https://openrouter.ai/api/v1 as its endpoint, replaces both headers. The cURL form is under Provider Integrations → OpenAI; the AI SDK form is in the Vercel AI SDK guide.
Endpoint: https://engine.acefleet.dev/v1/chat/completions · also https://engine.acefleet.dev/v1/responses. ACE credential: Authorization: Bearer ace_dev_....
| Topology | Shape |
|---|---|
| ACE in front | Client → ACE → https://openrouter.ai/api/v1, as the openai channel pointed at OpenRouter. |
| ACE behind | Not offered. |
| Header | Required | Description |
|---|---|---|
| x-ace-openai-key | Yes | The OpenRouter key (sk-or-v1-...), used for this call only. |
| x-ace-openai-base-url | Yes | https://openrouter.ai/api/v1. |
| x-ace-provider | Situational | openai, so a slug such as anthropic/claude-sonnet-4.5 is not resolved to the Anthropic channel. |
Passed through untouched
- the model slug, verbatim
- body fields
models,provider,transforms
Storing the OpenRouter key as the openai vendor key with endpoint https://openrouter.ai/api/v1 replaces x-ace-openai-key and x-ace-openai-base-url.
OpenRouter through ACE (Python)
from openai import OpenAI
client = OpenAI(
base_url="https://engine.acefleet.dev/v1",
api_key="ace_dev_<your-dev-key>",
default_headers={
"x-ace-provider": "openai",
"x-ace-openai-base-url": "https://openrouter.ai/api/v1",
"x-ace-openai-key": "sk-or-v1-...", # OpenRouter key, used for this call only
},
)
response = client.chat.completions.create(
model="anthropic/claude-sonnet-4.5", # OpenRouter's own slug, sent verbatim
messages=[{"role": "user", "content": "Summarise the failing checks."}],
# OpenRouter routing fields are relayed as written.
extra_body={
"models": ["anthropic/claude-sonnet-4.5", "openai/gpt-4o"],
"provider": {"sort": "price"},
},
)
print(response.choices[0].message.content)