Skip to content

ChatGPT Subscription

Canonical source: docs/CHATGPT_SUBSCRIPTION_TRANSPORT.md. This page is refreshed from the Finch repository when the website builds.

Finch’s chatgpt_subscription provider is a Finch-owned HTTP transport. It does not execute Codex, app-server, or any other provider binary, and it never reads another application’s credential store. It is intentionally separate from the OpenAI Platform and generic OpenAI-compatible transports.

The public Responses API create method documents the message, image, function, encrypted reasoning, and streaming item shapes used here; the separate GPT-5.6 Sol model reference documents that model’s public API settings.

ChatGPT subscription routing is a compatibility contract derived from the public OpenAI Codex source at commit 6478a751fde8884b2fdc76486fe23175a8e795d4. Finch records that pin as openai-codex-responses-lite@6478a751fde8884b2fdc76486fe23175a8e795d4. The relevant source files are:

  • codex-rs/codex-api/src/endpoint/responses.rs
  • codex-rs/codex-api/src/endpoint/models.rs
  • codex-rs/codex-api/src/sse/responses.rs
  • codex-rs/codex-api/src/rate_limits.rs
  • codex-rs/core/src/client.rs
  • codex-rs/protocol/src/openai_models.rs

Protocol drift fails closed; it is not silently treated as Platform behavior. Catalog discovery sends client_version=0.160.0, and both catalog and inference requests send version: 0.160.0. That is a released Codex version, not Finch’s application version or a claim that Finch is Codex. It is ahead of the audited source revision (which corresponds to 0.151.0): the catalog served to 0.151.0 omitted GPT-6.1 Sol, so the version was moved before the request-shape audit was redone, and that audit is still owed. Updating either compatibility pin requires auditing the newer public Codex catalog and Responses-Lite contracts, updating both pins together, and rerunning the focused tests plus the explicit live acceptance test.

Only a named ChatgptSubscription credential created by Finch’s device-login flow can select this provider. Its issuer, audience, account, store reference, revision, and generation are revalidated before reuse and after refresh.

The production origin is exactly https://chatgpt.com with these routes:

  • GET /backend-api/codex/models?client_version=0.160.0
  • POST /backend-api/codex/responses

Requests use bearer authorization, ChatGPT-Account-ID, honest originator: finch, the pinned compatibility version, and the pinned protocol revision. Application identity remains separate: both routes use the bounded static client identifier finch/<version> (+https://darwin-finch.github.io/) as their User-Agent, where <version> is Finch’s package version. It contains no username, hostname, Brain/session, account, or credential identifier. This provides honest client identification and project discoverability only; it does not guarantee that OpenAI exposes telemetry or metrics to Finch. Sol requests additionally send x-openai-internal-codex-responses-lite: true. Redirects, custom endpoints, userinfo, fragments, FedRAMP, Platform fallback, and model fallback are rejected.

The account catalog is bounded and cached by account plus credential generation. ETags may revalidate an expired cache, but an entry from another account is never reused. A requested gpt-5.6-sol or gpt-5.6 entry must be explicitly advertised with text, image, API, and Responses-Lite support before inference. Their numeric context_window values are authoritative account-catalog metadata when they fall in the defensive range 1..=10,000,000; Finch does not treat one exact window size as a dialect or authorization discriminator. Missing, non-numeric, zero, and excessive values fail closed without exposing the catalog body or account credentials. The synchronous capability descriptor reports the context window as unknown because it cannot perform credentialed account discovery; the validated catalog retains the exact value for each selectable model. The service may advertise either pinned identifier without advertising both. Finch requires the exact configured/requested identifier to be present and compatible before inference, so an alias is never silently substituted and an unrecognized slug is never accepted.

Every request uses store: false, stream: true, include: ["reasoning.encrypted_content"], and reasoning.context: "all_turns". Reasoning effort is explicit. An omitted profile setting emits medium, matching the documented GPT-5.6 Sol default; explicit low, medium, high, xhigh, and max settings are preserved. The public API also documents none, but Finch does not send it through the separately pinned subscription Responses-Lite route without route-specific conformance evidence. Instructions and tools are Responses-Lite developer items; user/assistant text, validated PNG/JPEG inputs, function calls, and function outputs retain their history order.

The request prefix follows the audited Codex v0.151.0 Responses-Lite shape: ordinary function definitions are nested under the functions namespace, and the additional_tools and developer-instructions items carry deterministic UUID-v5 IDs with at_ and msg_ prefixes. Codex scopes those payload-derived IDs to its thread UUID. Finch does not expose a Codex thread at this provider boundary, so it scopes them to the pinned protocol revision instead; identical visible prefix payloads therefore keep identity across retries without putting a username, Brain, account, credential, or host identifier on the wire. The pin must be re-audited if OpenAI changes the prefix identity contract.

ChatGPT reserves unprefixed collaboration names such as spawn_agent for its own native namespace. Finch advertises its corresponding local primitives with application-owned wire aliases (finch_spawn_agent, finch_await_agent, finch_poll_agent, and finch_cancel_agent) and maps a validated response back to the local name. A returned custom function may identify the advertised functions namespace, use collaboration only with one of those aliases, or omit the namespace as permitted by the observed Responses-Lite shape. Other namespaces, raw native collaboration names, malformed namespace values, unadvertised tools, and attempts to advertise a reserved Finch alias fail closed.

The audited client also sends fields tied to Codex-owned thread and client state, including prompt_cache_key and client_metadata. Finch does not fabricate those values: they remain absent until Finch has an independently defined, reviewed contract for them.

Encrypted reasoning is provider-owned opaque data. Finch bounds it, persists it as an ordered content block through the atomic conversation path, and replays it byte-for-byte. Finch never renders or interprets it. The IPC generation is 8; generation 6 peers reject the typed image and complete-content stream schema before query or stream work.

The SSE parser bounds each line and event and the total response. It validates standard event: names against JSON event types, requires strictly increasing sequence numbers, accumulates completed output items by contiguous output index, and treats validated response.output_item.done items as the authoritative output when they are present. A terminal completion snapshot may omit already-streamed reasoning, but its remaining items must match streamed messages and function calls in order and one-to-one after ignoring only validated passive item metadata. Terminal message/tool omissions, additions, duplicates, reordering, and semantic changes fail closed. Actual-model provenance is optional: when absent Finch reports the validated requested catalog route; when present the bounded serving-model identity may differ from that route but must remain unchanged throughout the response. Unknown fields/events, malformed tool arguments, missing completion, duplicate terminal markers, post-terminal data, partial EOF, idle timeout, receiver drop, and payload-limit violations fail visibly before terminal chunks are published. Unknown-field errors identify only Finch’s static containing-object or event label; response-derived field names and values are never reflected. The pinned Codex source tolerates response.usage.extra as an unknown passive object. A Finch-owned PR acceptance evidence on 2026-09-05 additionally observed an object named response.usage.attribution; this is dated live-service compatibility evidence, not a field declared by the pinned public Codex usage struct. Finch accepts only those two named passive metadata objects. Attribution is bounded to 256 KiB; extra remains bounded by the enclosing stream-event limit. Neither can alter Finch’s validated input/output token accounting, and other usage siblings remain fail-closed.

A separate Finch-owned PR acceptance record on 2026-09-05 requested one spawn_agent custom function call. The service response passed the namespace and advertised-tool checks and rebound to exactly one local spawn_agent call with the requested arguments. The acceptance test parses the call but never executes it.

User dogfood on 2026-09-05 after the collaboration namespace fix exercised the full Finch path: a fresh session advertised and executed three local spawn_agent calls, awaited their results, and produced a final typed Lisp response. This is evidence for that exact tested account and date, not a general entitlement, provider-parity, or release-readiness claim.

Non-success bodies are consumed only to a small bound and discarded. A Responses-Lite rejection retains a typed HTTP status and a compatibility or entitlement hint, never the response body. Tokens, account identifiers, request bodies, image data, tool arguments, reasoning continuations, and response bodies are never placed in provider errors.

Proactive refresh is generation-bound and serialized. A 401 before the stream starts permits one shared refresh, a fresh account catalog check, and one retry. There is no retry after successful stream headers or any response event.

Live auth and inference are never part of normal tests. After independent security review, a user who has explicitly completed Finch’s own device login can run:

Terminal window
FINCH_LIVE_CHATGPT_ACCEPTANCE=1 \
FINCH_LIVE_CHATGPT_CONFIG="$HOME/.finch/config.toml" \
FINCH_LIVE_CHATGPT_OAUTH_ROOT="$HOME/.finch/oauth" \
CARGO_BUILD_JOBS=2 \
./.agents/skills/finch-backlog/scripts/with-cargo-slot \
./scripts/test_brains.sh cargo test --lib \
providers::chatgpt_subscription::tests::live_chatgpt_subscription_acceptance_is_explicitly_opt_in \
-- --ignored --exact

The explicit paths let the supervised test read Finch’s real configuration and use Finch’s production OAuth store while all other test state remains in the supervisor’s disposable home. The configuration file is not modified. The OAuth store retains production behavior: it creates its normal lock and may atomically refresh the credential when it is near expiry or the service returns 401. The test selects a Finch-owned named credential and requires non-empty model provenance plus the exact requested static response text. It does not print tokens or response bodies. Until that opt-in test is run, live-service acceptance—including current account entitlement and server-side compatibility with the pinned revision—remains intentionally unverified.

The same reviewed environment can verify the collaboration-tool binding without executing the returned tool:

Terminal window
FINCH_LIVE_CHATGPT_ACCEPTANCE=1 \
FINCH_LIVE_CHATGPT_CONFIG="$HOME/.finch/config.toml" \
FINCH_LIVE_CHATGPT_OAUTH_ROOT="$HOME/.finch/oauth" \
CARGO_BUILD_JOBS=2 \
./.agents/skills/finch-backlog/scripts/with-cargo-slot \
./scripts/test_brains.sh cargo test --lib \
providers::chatgpt_subscription::tests::live_chatgpt_subscription_collaboration_tool_is_explicitly_opt_in \
-- --ignored --exact