Providers
Connect any LLM provider to Ingate. Auto-detection routes requests by path, or use explicit headers for full control. Bring your own keys or let Ingate manage them.
Supported Providers
Ingate works with any LLM provider that exposes an HTTP API. Three providers have optimized, built-in implementations with automatic auth header injection:
| Provider | Base URL | Auth Header | Auth Format |
|---|---|---|---|
openai | https://api.openai.com | Authorization | Bearer {key} |
anthropic | https://api.anthropic.com | x-api-key | {key} |
ollama | http://localhost:11434 | none | none |
| Any HTTP endpoint | You configure | Configurable | Configurable |
Any HTTP endpoint
Adding a Provider
Navigate to Dashboard → Providers → Add Provider. Give your provider a name, set its base URL, and choose an auth mode:
API Key Mode
Ingate encrypts your provider API key with AES-256-GCM and stores it securely. On each request, Ingate decrypts the key and injects it into the upstream request as the correct auth header for that provider. Your client never needs to hold or transmit the provider key.
# Client sends only the Ingate key. Provider key is injected server-side
curl https://api.ingateai.com/v1/chat/completions \
-H "X-Ingate-Key: sk-ingate-your-key" \
-H "Content-Type: application/json" \
-d '{"model": "gpt-4o", "messages": [{"role": "user", "content": "Hello"}]}'Auth Passthrough Mode
Set auth_passthrough: true on a provider and Ingate does not inject a key. Your client's own credentials (OAuth tokens, subscription tokens, personal API keys) pass through untouched to the upstream provider. Ingate still handles routing, logging, budgets, and guardrails.
# Client sends its own provider credentials. Ingate passes them through.
curl https://api.ingateai.com/v1/chat/completions \
-H "X-Ingate-Key: sk-ingate-your-key" \
-H "Authorization: Bearer sk-proj-your-openai-key" \
-H "Content-Type: application/json" \
-d '{"model": "gpt-4o", "messages": [{"role": "user", "content": "Hello"}]}'When to use each mode
- API Key mode: your team shares a single provider key managed by Ingate. Best for centralized billing and key rotation.
- Auth Passthrough: each developer or service uses their own provider credentials. Best for subscription-based plans and coding agents.
Auto-Detection
Ingate automatically detects the target provider from the request path. You don't need to set a header for standard API paths:
| Request Path | Detected Provider | API |
|---|---|---|
/v1/chat/completions | openai | Chat Completions |
/v1/completions | openai | Completions (legacy) |
/v1/embeddings | openai | Embeddings |
/v1/models | openai | Model listing |
/v1/responses | openai | Responses API |
/v1/messages | anthropic | Messages |
/api/chat | ollama | Chat |
/api/generate | ollama | Generate |
Priority Chain
When Ingate receives a request, it resolves the provider in this order:
- Explicit header:
X-Ingate-Provider: anthropicalways wins - Path auto-detection: matched against the table above
- Default provider: the org's configured fallback provider
- Error:
400if no provider can be resolved
# Auto-detected as openai (path: /v1/chat/completions)
curl https://api.ingateai.com/v1/chat/completions \
-H "X-Ingate-Key: sk-ingate-your-key" \
-H "Content-Type: application/json" \
-d '{"model": "gpt-4o-mini", "messages": [{"role": "user", "content": "Hello"}]}'
# Auto-detected as anthropic (path: /v1/messages)
curl https://api.ingateai.com/v1/messages \
-H "X-Ingate-Key: sk-ingate-your-key" \
-H "Content-Type: application/json" \
-d '{"model": "claude-sonnet-4-20250514", "max_tokens": 1024, "messages": [{"role": "user", "content": "Hello"}]}'
# Explicit header overrides auto-detection
curl https://api.ingateai.com/v1/chat/completions \
-H "X-Ingate-Provider: azure-gpt4" \
-H "X-Ingate-Key: sk-ingate-your-key" \
-H "Content-Type: application/json" \
-d '{"model": "gpt-4o", "messages": [{"role": "user", "content": "Hello"}]}'Drop-in replacement
https://api.ingateai.com and it just works with no code changes beyond adding the X-Ingate-Key header.Auth Passthrough
Auth Passthrough (auth_passthrough: true) is designed for teams where each developer or agent has their own provider credentials: subscription plans, OAuth tokens, or API keys they manage themselves. Ingate forwards the client's auth headers to the provider as-is, with no key injection, just observation and logging. This is the mode to use for subscription-authenticated tools like Claude Code on a Pro or Max plan, where the tool authenticates with its own OAuth token.
How it works
- Configure the provider in the dashboard with auth mode set to Passthrough (or
auth_passthrough: truein a self-hosted config) - Clients include their own provider auth header alongside
X-Ingate-Key - Ingate authenticates the client via
X-Ingate-Key, then forwards the request with the client's original auth header intact
Use cases
| Scenario | Auth Header Passed Through |
|---|---|
| Claude Code Pro / Max subscriptions | Authorization: Bearer <OAuth token> |
| Cursor Pro with own OpenAI key | Authorization: Bearer sk-proj-... |
| OAuth-protected inference endpoints | Authorization: Bearer eyJ... |
| Custom internal services with tokens | Any header your service expects |
# Developer uses their own Anthropic subscription through Ingate
curl https://api.ingateai.com/v1/messages \
-H "X-Ingate-Key: sk-ingate-your-key" \
-H "x-api-key: sk-ant-your-personal-key" \
-H "Content-Type: application/json" \
-d '{"model": "claude-sonnet-4-20250514", "max_tokens": 1024, "messages": [{"role": "user", "content": "Hello"}]}'Ingate features still apply
Custom Providers
Any provider beyond the built-in three can be added with full configuration control. Specify auth headers, path prefixes, static query parameters, and extra headers:
| Field | Description |
|---|---|
base_url | Upstream API base URL (required) |
api_key | Authentication credential (API Key mode only) |
auth_header | Custom auth header name (default: Authorization) |
auth_scheme | Prefix before the key value (default: Bearer) |
path_prefix | Prepended to every request path |
query_params | Static query parameters appended to every request |
headers | Static HTTP headers added to every request |
enabled | Whether this provider is active (default: disabled) |
Example: Azure OpenAI
Azure uses a different auth header (api-key), deployment-based paths, and a mandatory api-version query parameter:
| Field | Value |
|---|---|
| Name | azure-gpt4 |
| Base URL | https://myorg.openai.azure.com |
| Auth Header | api-key |
| Auth Scheme | (empty, no prefix) |
| Path Prefix | /openai/deployments/gpt-4o |
| Query Params | api-version=2024-02-01 |
# Request to Azure OpenAI through Ingate
# Ingate builds: https://myorg.openai.azure.com/openai/deployments/gpt-4o/chat/completions?api-version=2024-02-01
curl https://api.ingateai.com/v1/chat/completions \
-H "X-Ingate-Provider: azure-gpt4" \
-H "X-Ingate-Key: sk-ingate-your-key" \
-H "Content-Type: application/json" \
-d '{"messages": [{"role": "user", "content": "Hello"}]}'Example: vLLM / Self-Hosted Models
Local or self-hosted inference servers need only a base URL, no auth configuration:
# Name: local-llama
# Base URL: http://gpu-server:8000
# No API key needed for local endpoints
curl https://api.ingateai.com/v1/chat/completions \
-H "X-Ingate-Provider: local-llama" \
-H "X-Ingate-Key: sk-ingate-your-key" \
-H "Content-Type: application/json" \
-d '{"model": "llama-3-70b", "messages": [{"role": "user", "content": "Hello"}]}'Example: Together AI / Fireworks / OpenAI-Compatible
# Together AI uses standard Bearer auth with a different base URL
# Name: together
# Base URL: https://api.together.xyz
# Auth Header: Authorization (default)
# Auth Scheme: Bearer (default)
curl https://api.ingateai.com/v1/chat/completions \
-H "X-Ingate-Provider: together" \
-H "X-Ingate-Key: sk-ingate-your-key" \
-H "Content-Type: application/json" \
-d '{"model": "meta-llama/Llama-3-70b-chat-hf", "messages": [{"role": "user", "content": "Hello"}]}'Example: Custom Endpoint with Static Headers
Internal services often need a custom auth header plus fixed headers on every request:
# Name: internal-llm
# Base URL: https://llm.internal.corp.com
# Auth Header: X-Service-Token
# Auth Scheme: (empty, no prefix)
# Headers: X-Team=backend, X-Environment=production
curl https://api.ingateai.com/v1/chat/completions \
-H "X-Ingate-Provider: internal-llm" \
-H "X-Ingate-Key: sk-ingate-your-key" \
-H "Content-Type: application/json" \
-d '{"messages": [{"role": "user", "content": "Hello"}]}'Default Provider
One provider can be marked as the default for your organization. The default is used when a request has no X-Ingate-Provider header and the path doesn't match any auto-detection rule.
Set the default in Dashboard → Providers → ⋯ → Set as Default (or with default: true on the provider in a self-hosted config), or via the API:
curl -X PUT https://api.ingateai.com/api/v1/providers/default \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"provider_name": "openai"}'Resolution order reminder
400 error. The default provider is the last fallback before an error is returned.Provider Fallback
Enterprise feature
When a primary provider returns a retryable error (429, 500, 502, 503, 504), Ingate automatically retries the request against a configured backup provider. Configure fallback chains in the dashboard under Providers → Fallback.
How it works
- Request goes to the primary provider
- Primary returns a retryable status code
- Ingate retries against the next provider in the fallback chain
- Process continues until a provider succeeds or the chain is exhausted
Both the primary and fallback providers must be configured and enabled. This is validated at startup, so a misconfigured fallback fails fast rather than at request time.
The response includes the X-Ingate-Served-By header showing which provider actually served the request:
# Response header shows which provider handled the request
# X-Ingate-Served-By: anthropic
# (primary was openai, but it returned 429)Model compatibility
Format Translation
Send OpenAI-format requests to Anthropic models. Add the X-Ingate-Translate: true header and Ingate translates the request and response format automatically. Your application sees only OpenAI-shaped responses. Currently supported: OpenAI → Anthropic.
What gets translated
- OpenAI
messagesarray → Anthropicmessagesformat - OpenAI
systemmessage → Anthropicsystemparameter - OpenAI response shape → Anthropic response shape (and back)
- Token usage fields mapped between formats
# Send OpenAI-format request, Ingate translates to Anthropic format
curl https://api.ingateai.com/v1/chat/completions \
-H "X-Ingate-Provider: anthropic" \
-H "X-Ingate-Translate: true" \
-H "X-Ingate-Key: sk-ingate-your-key" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-sonnet-4-20250514",
"messages": [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Hello"}
]
}'Combine with fallback