Codex and Claude Code Through an API Relay: Pin the Provider Before Auto-Routing

·12 min read

The agent has read the files, run the tests and found the failing function. You ask it to continue. Instead, it repeats earlier work or stops on a tool call. The difficult part is not the failure itself: it is working out whether the code, the model or the connection failed.

Automatic merchant selection, model switching and retries can add several moving parts to that investigation. A terminal error rarely tells you which route handled each attempt.

When connecting Codex or Claude Code to an API relay for project work, I would start with a fixed model and provider route, establish a working baseline, and then evaluate automatic routing. That reduces diagnostic variables. It does not mean a pinned provider guarantees reliability or that routing necessarily loses context.

Documentation checked September 16, 2026. This is a configuration and troubleshooting guide, not a provider uptime test or ranking. Client versions, gateway implementations and merchant policies differ.

A coding task crosses more than one boundary
  1. 01Coding client

    Builds context from project work, history and tool results

  2. 02Relay / gateway

    Handles credentials, protocol forwarding, routing and billing

  3. 03Selected merchant / upstream

    Processes requests and returns text and tool calls

Schematic: pinning a merchant constrains routing. It does not replace client context management or guarantee an unchanged upstream inside that merchant.

Find out what “auto” actually changes

A service may keep the model fixed while choosing an upstream, choose a different model for the task, or switch only after a failure. Those are different policies even when the interface calls all three “smart routing.”

Identify who controls model selection, merchant selection and fallback. Does pinning a merchant still permit overrides? When the chosen model is unavailable, does the request fail visibly or run on another model? A dedicated API key is not evidence of a dedicated upstream.

The merchant may itself operate a resource pool. Pinning its public route need not pin a machine or an account behind it. Request-level routing records are more useful than an unqualified reliability badge.

Context, cache and stored state are different

Context is the information supplied for the current generation. Caching reuses computation for repeated input. Stored state may instead be referenced by an identifier. A cache miss is not missing conversation history.

Claude Code's caching documentation describes how subsequent requests carry conversation context again. A compatible backend does not inherently forget the project simply because it did not serve the previous request. Summarization, compaction and whether a file was reread can also change what is available.

A stateful continuation is different. The OpenAI conversation-state guide documents references such as previous_response_id. If a destination cannot resolve that reference and the gateway cannot restore the necessary state, continuation can fail. This is an implementation boundary to test, not a claim that every Codex request uses that mechanism.

Claude's cache rules include organization or workspace isolation and prefix matching. Moving outside the applicable cache scope can change latency and charges without losing input content. Pinning a merchant cannot guarantee hits either. Check cache usage and invoices rather than judging the backend from its writing style.

A successful greeting is not a coding-agent test

Agent work is a sequence of model requests, tool calls, execution results and further edits. A proxy that forwards plain chat may not preserve the protocol needed for that sequence.

At the verification date, the Codex configuration reference lists responses for custom-provider wire_api. Verify support for the Responses requests and tool events used by your client version, not just an “OpenAI-compatible” label.

For Claude Code, check the selected connection format, required headers and streaming behavior. The gateway compatibility guide discusses buffering and keep-alive forwarding. A stalled terminal does not necessarily mean the model is still thinking, and HTTP 200 does not establish that the stream finished.

The Claude tool-call specification requires correctly matched tool IDs and message ordering. Inspect the client, translation layer and upstream when that exchange fails. One malformed tool result is not proof of model substitution.

Pin a verifiable route, not a local label

Select the model, merchant or group on the relay side and confirm which rules apply to the credential. Disable untested fallbacks where the platform provides that control. Send small requests and inspect the actual routing records. If those records are unavailable, the strength of the pin remains unverified.

The following illustrates a Codex CLI custom-provider configuration. It contains placeholders, not a working service address, and does not itself pin an upstream. Obtain the supported model ID, API base and route-bound credential from the provider. Preserve existing settings instead of replacing the entire configuration.

model = "REPLACE_WITH_SUPPORTED_MODEL_ID"
model_provider = "project_relay"

[model_providers.project_relay]
name = "Project relay"
base_url = "https://relay.example.com/v1"
env_key = "CODEX_RELAY_API_KEY"
wire_api = "responses"

env_key names an environment variable containing the credential. The local label project_relay does not impose a gateway routing policy. See the custom-provider documentation for the connection fields.

For Claude Code, configure ANTHROPIC_BASE_URL and the authentication method your gateway specifies: ANTHROPIC_AUTH_TOKEN for Bearer authentication or ANTHROPIC_API_KEY for x-api-key. Do not set conflicting credentials indiscriminately. Check the effective base URL and credential source with /status; CLI, desktop and editor surfaces differ. Follow the gateway connection guide for your surface.

Use a separately issued API credential, not personal ChatGPT or Claude login-session credentials. Establish code retention and data-use conditions before sending commercial work. A pinned route does not establish data compliance, and domain verification is not a service-quality test.

Test a small change from reading to repair

Use a small project without secrets or customer data. Ask the agent to read two files, change a function, add a test, run it and repair a failure. That exercises more of the actual workflow than asking for a code snippet.

Start with five smoke runs for obvious incompatibilities. Then try a set of twenty small tasks on the primary and candidate backup routes, each from a separate clean copy. Keep the client version, model, reasoning settings and acceptance criteria consistent. These are suggested starting sizes, not statistical evidence of long-term uptime.

  • Completion: did the change pass its tests, rather than merely claim success?
  • Continuity: did tool exchanges, longer input and resumption work?
  • Time: how long until acceptance, including retries?
  • Cost: can charges, cache usage and retry attempts be reconciled?

Different code from the same model is not proof that a route changed. Compare accepted outcomes, reproducible failures and routing records.

Follow the symptom to evidence

Investigation starting points, not diagnoses from symptoms alone.
SymptomInspect firstNext step
Chat works; tools failTool IDs, result order, supported features and translationReproduce one tool round trip on a pinned route
Missing context or failed continuationSent history, compaction, limits and state-reference errorsConfirm the missing information actually reached this request
Output starts, then stallsStream completion, buffering, disconnects and keep-alivesDistinguish client, gateway and upstream timeouts
429s or intermittent timeoutsLimit source, concurrency, time, route and retriesReduce concurrency, respect backoff, then test a qualified backup
Unexpectedly higher chargesInput size, cache usage, model tier and billed attemptsReconcile each task with billing and refund rules

A useful support report includes time and timezone, client version, model ID, redacted route information, error text and request IDs. Keep an upstream request ID too when available. Do not post source code, secrets or authentication headers in a public support channel.

Compare completed work, not just the rate card

Automatic routing does not inherently imply fraudulent billing. A gateway can consolidate records across providers; a single merchant can still make reconciliation difficult.

Investigate what happened before retrying: was the original request already processed upstream, did another billable attempt occur, and how are those records linked? Check failure-billing policies. Similar-looking entries alone do not establish duplicate charging.

A useful comparison is total test charges divided by accepted tasks, with human debugging time recorded separately. In an arithmetic example, CNY 2 for five accepted tasks is CNY 0.40 each; CNY 3 for fifteen is CNY 0.20 each. The higher total spend can buy cheaper completed work. These numbers are illustrative, not provider measurements.

Use the relay provider directory and our relay-versus-official price comparison to build a shortlist. Then use actual development tasks to choose a route. A price table cannot complete the second step for you.

Independent creative work is a useful routing workload

Twenty product descriptions or separate script drafts can each carry their own brief. An application can submit these independently, while a router distributes requests among qualified channels with available capacity. One queue need not hold up the entire batch when another eligible route can accept work.

The application or scheduler creates concurrency; the router assigns requests. Auto-routing does not break one article into parallel tasks, nor does it necessarily broadcast a request to every merchant. Client concurrency, gateway quotas, upstream capacity and retry overhead still constrain results.

Other candidates include separate document summaries, translations and isolated code-analysis tasks. Dependent edits in the same project need different handling: preserve session and file boundaries rather than letting uncoordinated agents overwrite shared files.

Interactive work may prioritize responsiveness, long-form batches may prioritize generation speed, and cost-sensitive work may choose among acceptable prices. For a concrete implementation, OpenRouter's provider-routing documentation describes load balancing, price or performance ordering, provider restrictions and fallback. These policies do not necessarily operate simultaneously; other gateways and clients may not expose the same controls.

Use separate policies for continuous coding sessions and independent creative batches. Establish a pinned baseline for the former, and evaluate a qualified pool for the latter. Measure total completion time, accepted outputs and total charges—not one unusually fast response.

Build a bounded provider pool for overnight work

Pinning has a tradeoff: when that route fails, work may stop. The aim is not permanent rejection of automation. It is a debuggable single-route baseline followed by controlled multi-route operation.

Prepare a separately configured backup and validate its tools and context requirements. Preserve changes and test results before switching; check for running commands and requests. If an earlier outcome is uncertain, inspect files and external side effects before replaying work. Manually changing a key does not make server-side state references portable.

After candidate routes pass acceptance tests, evaluate automated fallback with explicit model restrictions, cost ceilings and error records. For long sessions, ask about session affinity: keeping a conversation on the same path when necessary. Test restoration separately for stateful continuations. These are capabilities to verify, not controls every platform necessarily offers.

A practical compromise is a separate development route or preset containing two or three merchants that passed your own tests, with a dedicated credential and billing records. An allowlist must constrain fallback too, not merely express which providers to try first. Keep the model fixed when switching merchants; create an explicit model allowlist only for tasks that permit model changes.

This can reduce interruption from one failed route. It cannot, by itself, prevent an unattended task from looping and spending. Establish enforceable limits before leaving it running:

  • Spend: enforce a project or credential budget and per-request output limit. A maximum token unit price is not a total spending cap; in-flight concurrent work may still incur charges after a stop.
  • Attempts: cap retries, provider switches and total task steps. Client and gateway retry loops can multiply attempts.
  • Time: limit request duration, total task runtime and time without useful progress. Repeating an error is not progress.
  • Recovery: save files, logs and checkpoints, then stop on repeated failure, a budget boundary or uncertain tool state.
  • Authority: preserve approval boundaries for publishing, payments and destructive operations. A fallback must not blindly replay side effects.

These controls may span the platform, client and scheduler. A spending alert is not a hard stop. If a service cannot enforce the pool or limits, use a gateway or scheduler that can; otherwise do not treat important unattended work as safely managed.

Evaluate accepted tasks, route changes, failures stopped in time and actual charges. The promise is not that everything finishes while you sleep. It is that eligible work can continue, failures have a stopping point, and the next morning you can see what completed and what it cost.

Related

← Back to Blog