Client or integration
Direct HTTP/API client (Codex App / Claude Code also affected via the proxy)
Area
Proxy and routing · Provider adapter
Summary
The provider management API and CLI have no way to set or restore the headers field on a provider. PATCH /api/providers accepts only a fixed allowlist of fields (disabled, adapter, baseUrl, defaultModel, authMode, apiKeyTransport, note, allowPrivateNetwork, liveModels, codexAccountMode, setDefault) and ocx provider edit exposes the same set as flags — there is no headers option. If a custom provider's headers block is lost (e.g. the provider entry is re-saved via POST /api/providers without round-tripping it, or a config migration drops it), the only recovery is hand-editing ~/.opencodex/config.json and restarting the proxy.
Concrete failure: the Agent Router gateway (agentrouter.org) rejects requests that carry a valid API key but not the Claude Code CLI client fingerprint (User-Agent, x-app, X-Stainless-*, anthropic-version, anthropic-beta). The openai-chat adapter sends Authorization: Bearer <key> and then merges provider.headers; without the fingerprint headers the gateway returns 401 unauthorized client detected. In this install the headers block on the AGR-OAI provider (present in a 2026-07-29 config backup) was missing from the 2026-08-02 config, and every routed request failed with that 401 until the block was restored by hand.
Expected: PATCH /api/providers and ocx provider edit should accept headers (merge or replace), and any provider save path should round-trip unknown provider fields so custom headers survive.
Reproduction
- Install
@bitkyc08/opencodex 2.10.0 and start the proxy (ocx start).
- Add a custom provider that requires fingerprint headers, e.g. Agent Router, in
~/.opencodex/config.json:
{
"providers": {
"AGR-OAI": {
"adapter": "openai-chat",
"baseUrl": "https://agentrouter.org/v1",
"authMode": "key",
"apiKey": "sk-<redacted>",
"headers": {
"User-Agent": "claude-cli/2.1.219 (external, sdk-cli)",
"anthropic-version": "2023-06-01",
"anthropic-beta": "claude-code-20250219,interleaved-thinking-2025-05-14,effort-2025-11-24",
"x-app": "cli",
"X-Stainless-Retry-Count": "0",
"X-Stainless-Package-Version": "0.94.0"
}
}
}
}
- Try to manage the headers through the management plane:
ocx provider edit AGR-OAI --enabled on # works, headers preserved
ocx provider edit AGR-OAI --headers '{"x-app":"cli"}' # no such flag; exits with usage error
Or via API:
PATCH /api/providers?name=AGR-OAI
{ "headers": { "x-app": "cli" } }
→ 400 {"error":"no recognized fields to update"}
- Simulate headers being lost:
POST /api/providers with a provider payload that omits headers (the field is optional and not validated as required), then send a request with an image-free message:
POST /v1/responses
{ "model": "AGR-OAI/gpt-5.6-sol", "input": [...] }
→ 401 {"error":{"message":"unauthorized client detected, contact support for assistance at https://discord.gg/aYq5B4RW3"},"message":"UNAUTHENTICATED","success":false,"type":"unauthorized_client_error"}
- Observe: only a hand edit of
~/.opencodex/config.json (restoring headers) plus a restart fixes it; the management plane cannot.
Version
2.10.0 (npm @bitkyc08/opencodex); Codex runtime 0.146.0
Operating system
Windows 11 (current), America/Fortaleza timezone
Provider and model
agentrouter.org via custom provider AGR-OAI (openai-chat adapter), model gpt-5.6-sol; same issue applies to any provider needing custom headers (e.g. AGR anthropic adapter uses the same header block)
Logs or error output
Provider error 401: {"error":{"message":"unauthorized client detected, contact support for assistance at https://discord.gg/aYq5B4RW3"},"message":"UNAUTHENTICATED","success":false,"type":"unauthorized_client_error"}
Verified live: GET https://agentrouter.org/v1/models with Authorization: Bearer <key> and no fingerprint headers → 401; with the claude-cli headers added → 200 and the model list is returned.
Redacted configuration
{
"providers": {
"AGR-OAI": {
"adapter": "openai-chat",
"baseUrl": "https://agentrouter.org/v1",
"authMode": "key",
"apiKey": "sk-<redacted>",
"headers": {
"User-Agent": "claude-cli/2.1.219 (external, sdk-cli)",
"anthropic-version": "2023-06-01",
"anthropic-beta": "claude-code-20250219,interleaved-thinking-2025-05-14,effort-2025-11-24",
"anthropic-dangerous-direct-browser-access": "true",
"x-app": "cli",
"X-Stainless-Retry-Count": "0",
"X-Stainless-Timeout": "600",
"X-Stainless-Lang": "js",
"X-Stainless-Package-Version": "0.94.0",
"X-Stainless-OS": "MacOS",
"X-Stainless-Arch": "arm64",
"X-Stainless-Runtime": "node",
"X-Stainless-Runtime-Version": "v26.3.0"
}
}
}
}
Code references
PATCH /api/providers field allowlist: src/server/management/provider-routes.ts — only disabled, adapter, baseUrl, defaultModel, authMode, apiKeyTransport, note, allowPrivateNetwork, liveModels (plus the exclusive codexAccountMode / setDefault paths); unknown fields → 400 "no recognized fields to update".
- CLI flags mirror that allowlist:
src/cli/provider-runtime.ts (ocx provider edit ... has no --headers).
- The adapter applies
provider.headers after the default Authorization header: src/adapters/openai-chat.ts and src/adapters/anthropic.ts.
providerHeadersConfigError in src/config.ts already validates the headers shape, so the schema supports it — only the management-plane mutation paths are missing it.
Suggested fix
- Accept
headers (object) in PATCH /api/providers, merging or replacing per field semantics, validated by providerHeadersConfigError.
- Add a
--headers <json> option to ocx provider edit (or a dedicated management route).
- Ensure
POST /api/providers save paths (GUI/CLI) round-trip unknown provider fields like headers so a provider re-save does not silently drop them.
Checks
Client or integration
Direct HTTP/API client (Codex App / Claude Code also affected via the proxy)
Area
Proxy and routing · Provider adapter
Summary
The provider management API and CLI have no way to set or restore the
headersfield on a provider.PATCH /api/providersaccepts only a fixed allowlist of fields (disabled,adapter,baseUrl,defaultModel,authMode,apiKeyTransport,note,allowPrivateNetwork,liveModels,codexAccountMode,setDefault) andocx provider editexposes the same set as flags — there is noheadersoption. If a custom provider'sheadersblock is lost (e.g. the provider entry is re-saved viaPOST /api/providerswithout round-tripping it, or a config migration drops it), the only recovery is hand-editing~/.opencodex/config.jsonand restarting the proxy.Concrete failure: the Agent Router gateway (agentrouter.org) rejects requests that carry a valid API key but not the Claude Code CLI client fingerprint (User-Agent,
x-app,X-Stainless-*,anthropic-version,anthropic-beta). Theopenai-chatadapter sendsAuthorization: Bearer <key>and then mergesprovider.headers; without the fingerprint headers the gateway returns401 unauthorized client detected. In this install theheadersblock on theAGR-OAIprovider (present in a 2026-07-29 config backup) was missing from the 2026-08-02 config, and every routed request failed with that 401 until the block was restored by hand.Expected:
PATCH /api/providersandocx provider editshould acceptheaders(merge or replace), and any provider save path should round-trip unknown provider fields so custom headers survive.Reproduction
@bitkyc08/opencodex2.10.0 and start the proxy (ocx start).~/.opencodex/config.json:{ "providers": { "AGR-OAI": { "adapter": "openai-chat", "baseUrl": "https://agentrouter.org/v1", "authMode": "key", "apiKey": "sk-<redacted>", "headers": { "User-Agent": "claude-cli/2.1.219 (external, sdk-cli)", "anthropic-version": "2023-06-01", "anthropic-beta": "claude-code-20250219,interleaved-thinking-2025-05-14,effort-2025-11-24", "x-app": "cli", "X-Stainless-Retry-Count": "0", "X-Stainless-Package-Version": "0.94.0" } } } }POST /api/providerswith a provider payload that omitsheaders(the field is optional and not validated as required), then send a request with an image-free message:~/.opencodex/config.json(restoringheaders) plus a restart fixes it; the management plane cannot.Version
2.10.0 (npm
@bitkyc08/opencodex); Codex runtime 0.146.0Operating system
Windows 11 (current), America/Fortaleza timezone
Provider and model
agentrouter.org via custom provider
AGR-OAI(openai-chat adapter), modelgpt-5.6-sol; same issue applies to any provider needing custom headers (e.g.AGRanthropic adapter uses the same header block)Logs or error output
Verified live:
GET https://agentrouter.org/v1/modelswithAuthorization: Bearer <key>and no fingerprint headers → 401; with the claude-cli headers added → 200 and the model list is returned.Redacted configuration
{ "providers": { "AGR-OAI": { "adapter": "openai-chat", "baseUrl": "https://agentrouter.org/v1", "authMode": "key", "apiKey": "sk-<redacted>", "headers": { "User-Agent": "claude-cli/2.1.219 (external, sdk-cli)", "anthropic-version": "2023-06-01", "anthropic-beta": "claude-code-20250219,interleaved-thinking-2025-05-14,effort-2025-11-24", "anthropic-dangerous-direct-browser-access": "true", "x-app": "cli", "X-Stainless-Retry-Count": "0", "X-Stainless-Timeout": "600", "X-Stainless-Lang": "js", "X-Stainless-Package-Version": "0.94.0", "X-Stainless-OS": "MacOS", "X-Stainless-Arch": "arm64", "X-Stainless-Runtime": "node", "X-Stainless-Runtime-Version": "v26.3.0" } } } }Code references
PATCH /api/providersfield allowlist:src/server/management/provider-routes.ts— onlydisabled,adapter,baseUrl,defaultModel,authMode,apiKeyTransport,note,allowPrivateNetwork,liveModels(plus the exclusivecodexAccountMode/setDefaultpaths); unknown fields →400 "no recognized fields to update".src/cli/provider-runtime.ts(ocx provider edit ...has no--headers).provider.headersafter the defaultAuthorizationheader:src/adapters/openai-chat.tsandsrc/adapters/anthropic.ts.providerHeadersConfigErrorinsrc/config.tsalready validates theheadersshape, so the schema supports it — only the management-plane mutation paths are missing it.Suggested fix
headers(object) inPATCH /api/providers, merging or replacing per field semantics, validated byproviderHeadersConfigError.--headers <json>option toocx provider edit(or a dedicated management route).POST /api/providerssave paths (GUI/CLI) round-trip unknown provider fields likeheadersso a provider re-save does not silently drop them.Checks