codex-backend-sdk
Unofficial Python SDK for building independent harnesses and integrations on top of the backend capabilities available to an authenticated Codex/ChatGPT subscriber.
The package intentionally separates three kinds of API:
| Surface | Purpose | Typical stability |
|---|---|---|
client.* |
OpenAI-shaped inference and media primitives exposed by Codex | Most familiar and typed |
client.codex.* |
Codex-specific account, cloud, search, and Remote Control capabilities | Product-specific |
client.chatgpt.* |
ChatGPT product surfaces observed in the official Desktop client | Broadest, often raw |
Requirements: a ChatGPT Plus, Pro, or Enterprise subscription. Authentication uses the official Codex OAuth client and stores compatible credentials in
~/.codex/auth.json.
Independent project: this library reverse-engineers undocumented backend contracts. It is not affiliated with, endorsed by, or supported by OpenAI. Availability can vary by plan, workspace, rollout, and backend revision.
Install
git clone https://github.com/B4PT0R/codex-backend-sdk.git
cd codex-backend-sdk
pip install -e .
Quickstart
from codex_backend_sdk import OpenAI
client = OpenAI().authenticate()
response = client.responses.create(
model="gpt-5.4",
input="Explain quicksort in one paragraph.",
)
print(response.output_text)
authenticate() reuses existing Codex credentials when possible and otherwise
opens the browser OAuth flow. Most examples below assume an authenticated
client created this way.
Choose the right surface
Direct client: inference and reusable primitives
Start here for the common building blocks of an agent or application:
client.responses # text/reasoning/tool inference, parsing, compaction
client.models # Codex model catalog
client.files # upload files for Apps/MCP parameters
client.images # Codex-backed image generation and editing
client.audio # ChatGPT-backed transcription
client.embeddings # OpenAI embeddings endpoint through OAuth
client.realtime # WebRTC call creation and Realtime connection headers
These resources follow openai-python conventions where the backend overlaps
with the public OpenAI API. Backend-specific restrictions remain explicit.
See the compatibility matrix for the audited
signatures, transport adaptations, and intrinsic OAuth/backend boundaries.
client.codex: Codex product capabilities
Use this namespace for capabilities owned by Codex rather than the general Responses API:
client.codex.web_search # structured search/page/weather/etc. commands
client.codex.usage # quota plus detailed usage
client.codex.tasks # Codex cloud tasks and turns
client.codex.environments # cloud environments and machines
client.codex.repositories # repository and branch discovery
client.codex.remote_control # Remote Control server and host discovery
client.codex.config # managed Codex settings/configuration
client.codex.profile # Codex profile
client.codex.memories # account memories and trace summarization
client.codex.worktree_snapshots # cloud-task archive uploads
client.chatgpt: Desktop-observed product APIs
Use this namespace when an integration needs ChatGPT product state or hosted Apps rather than Codex inference:
client.chatgpt.conversations # ChatGPT history and streaming conversation API
client.chatgpt.projects # projects, files, saves, connector scopes
client.chatgpt.files # file library, attachments, downloads, processing
client.chatgpt.search # cross-product indexed search
client.chatgpt.apps # hosted Apps/MCP transports and widgets
client.chatgpt.plugins # plugin catalogs, skills, bundles, sharing
client.chatgpt.connectors # connector discovery, linking, external actions
client.chatgpt.models # ChatGPT and third-party model catalogs
client.chatgpt.voice # voices, dictation metadata, read-aloud speech
client.chatgpt.account # account metadata and explicit preferences
These private product schemas evolve more often. The SDK therefore returns raw dictionaries or raw streams when imposing a stable model would be misleading.
Common workflows
Generate a response
response = client.responses.create(
model="gpt-5.4",
instructions="Be concise.",
input="Summarize the CAP theorem.",
reasoning={"effort": "medium", "summary": "auto"},
)
print(response.output_text)
print(response.reasoning_summary)
The backend always streams internally. Without stream=True, the SDK collects
events and returns a typed Response.
Stream output
stream = client.responses.create(
input="Write a short limerick about Linux.",
stream=True,
)
for event in stream:
if event.type == "response.output_text.delta":
print(event.delta, end="", flush=True)
For long-lived integrations, the alternate WebSocket transport keeps one connection reusable across sequential turns:
with client.responses.websocket.connect() as ws:
for event in ws.create({"model": "gpt-5.4", "input": "Say hello."}):
if event.get("type") == "response.output_text.delta":
print(event.get("delta", ""), end="")
Maintain a multi-turn conversation
The Codex backend does not expose previous_response_id; preserve prior items
in the next request:
history = [{"role": "user", "content": "My name is Alice. Say OK."}]
first = client.responses.create(input=history)
history.extend(first.output)
history.append({"role": "user", "content": "What is my name?"})
print(client.responses.create(input=history).output_text)
Compact a long context
compacted = client.responses.compact(
model="gpt-5.4",
instructions="Preserve task-critical decisions and unresolved work.",
input=history,
)
history = compacted.output
Compaction items are opaque encrypted backend state. Replay them as input; do not parse or modify their contents.
Call a function
import json
tools = [{
"type": "function",
"name": "get_weather",
"description": "Get the current weather for a city.",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"],
"additionalProperties": False,
},
}]
first = client.responses.create(
input="What is the weather in Paris?",
tools=tools,
)
call = first.tool_calls[0]
second = client.responses.create(
input=[
call,
{
"type": "function_call_output",
"call_id": call["call_id"],
"output": json.dumps({"temperature": 18, "unit": "celsius"}),
},
],
tools=tools,
)
print(second.output_text)
Parse structured output
from pydantic import BaseModel
class Person(BaseModel):
name: str
age: int
result = client.responses.parse(
input="Extract: Ada is 37 years old.",
text_format=Person,
)
print(result.output_parsed)
Discover available models
for model in client.models.list():
print(model.id, model.context_window, model.supported_reasoning_levels)
model = client.models.retrieve("gpt-5.4")
Upload a file
uploaded = client.files.upload("report.csv")
print(uploaded.uri) # sediment://file_...
The helper creates ChatGPT file metadata, uploads to the backend-issued signed URL, and finalizes the file for Apps/MCP file parameters.
Transcribe audio
with open("meeting.wav", "rb") as audio:
transcript = client.audio.transcriptions.create(
model="gpt-4o-mini-transcribe",
file=("meeting.wav", audio, "audio/wav"),
)
print(transcript.text)
Generate or edit an image
import base64
image = client.images.generate(
model="gpt-image-2",
prompt="A cheerful blue robot holding a red flower",
)
with open("robot.png", "wb") as output:
output.write(base64.b64decode(image.data[0].b64_json))
edited = client.images.edit(
image=open("robot.png", "rb"),
mask=open("mask.png", "rb"),
prompt="Add a small red star in the center",
)
Codex workflows
Structured web search
result = client.codex.web_search.search(
id="search-session-1",
model="gpt-5-search-api",
commands={
"search_query": [{"q": "Python packaging PEP 735"}],
"response_length": "short",
},
)
print(result["output"])
continuation = result.get("encrypted_output")
The same transport supports page operations, image search, finance, weather, sports, and time commands. See the API reference for command validation.
Inspect quota and detailed usage
quota = client.codex.usage()
daily = client.codex.usage_details.daily_token_breakdown()
credits = client.codex.usage_details.credit_events()
print(quota.get("rate_limit", {}).get("primary_window"))
Work with Codex cloud tasks
tasks = client.codex.tasks.list(limit=10)
task = client.codex.tasks.retrieve(tasks["items"][0]["id"])
turns = client.codex.tasks.turns.list(task["task"]["id"])
logs = client.codex.tasks.turns.logs(task["task"]["id"], turns[0]["id"])
environments = client.codex.environments.list()
repositories = client.codex.repositories.search(
"codex",
connector_id="github-connector-id",
)
Creation, cancellation, environment updates, cache resets, and pull-request operations are explicit mutations; discovery methods never invoke them.
Run a Remote Control server
server = client.codex.remote_control.enroll(
name="My workstation",
installation_id="stable-installation-id",
os="linux",
arch="x86_64",
app_server_version="0.147.0",
)
pairing = client.codex.remote_control.pairing.start(server, manual_code=True)
print(pairing.manual_pairing_code)
with client.codex.remote_control.connect(
server,
installation_id="stable-installation-id",
server_name="My workstation",
) as connection:
for envelope in connection:
print(envelope)
The transport deliberately leaves protocol-v3 envelopes raw. A bridge must preserve client, stream, sequence, ACK, chunk, and cursor semantics. Never log pairing codes or Remote Control tokens.
ChatGPT product workflows
Search and retrieve ChatGPT history
page = client.chatgpt.conversations.list(limit=20)
matches = client.chatgpt.conversations.search("release notes")
conversation = client.chatgpt.conversations.retrieve("conv_...")
global_matches = client.chatgpt.search.global_search(
"release notes",
sources=("conversation",),
limit=20,
)
ChatGPT conversations are product history, not Codex App Server threads and not Responses API state.
Browse projects and files
projects = client.chatgpt.projects.list_all()
project = client.chatgpt.projects.retrieve(projects[0]["id"])
project_conversations = client.chatgpt.projects.conversations(projects[0]["id"])
library = client.chatgpt.files.list_library_files()
content = client.chatgpt.files.download("file_...")
Download helpers can return bytes, BytesIO, a persisted Path, or the raw
HTTP response. OAuth is retained for ChatGPT URLs and omitted from signed CDN
URLs.
Use hosted Apps/MCP
tools = client.chatgpt.apps.list_tools()
result = client.chatgpt.apps.call_tool("connector_tool_name", {"query": "..."})
with client.chatgpt.apps.connect_hosted_mcp() as mcp:
hosted_tools = mcp.list_tools()["tools"]
resources = mcp.list_resources()["resources"]
Hosted tools may mutate external services. The calling harness must inspect tool annotations and own user confirmation; the SDK never auto-invokes tools.
Discover plugins and skills
plugins = client.chatgpt.plugins.list_all(scope="GLOBAL")
installed = client.chatgpt.plugins.installed_all()
suggested = client.chatgpt.plugins.suggested()
skill = client.chatgpt.plugins.skill("plugins~...", "skill-name")
checkout = client.chatgpt.plugins.bundles.extract_plugin(
"plugins~...",
"./plugins/example",
)
Bundle helpers enforce HTTPS, download limits, archive limits, safe relative paths, manifest checks, and atomic extraction. Signed download URLs never receive the user's OAuth bearer.
Discover connectors safely
connectors = client.chatgpt.connectors.directory.list_all()
detail = client.chatgpt.connectors.retrieve(
connectors[0]["id"],
include_actions=True,
)
links = client.chatgpt.connectors.links.list_accessible()
Read-only discovery is separate from
client.chatgpt.connectors.authentication and
client.chatgpt.connectors.external_actions. Linking, email, contacts, and
Google Drive conversion require explicit method calls and caller-owned approval.
Generate subscription-backed speech
speech = client.chatgpt.voice.synthesize_pronunciation(
text="Bonjour Baptiste",
pronunciation_language="fr-FR",
)
speech.write_to_file("bonjour.mp3")
The ChatGPT read-aloud service is smaller than the public speech API: it exposes
language and playback speed, not arbitrary model and voice selection. It can
return a typed in-memory object, bytes, BytesIO, a data URI, or a file path.
Advanced transports
Realtime voice
answer = client.realtime.calls.create_v3(
sdp=offer_sdp,
session={
"model": "gpt-live-1-codex",
"instructions": "Speak naturally and stay concise.",
},
)
print(answer.answer_sdp)
Live probes confirmed gpt-live-1-codex and
gpt-live-1-boulder-alpha. They are Codex Realtime v3 snapshots, not aliases
for the public gpt-realtime family. The call response exposes call_id; join
its OAuth-authenticated control and delegation channel with:
sideband = client.realtime.sideband.connect(
call_id=answer.call_id,
session_id="voice-session",
)
sideband.send({"type": "delegation.context.append", "content": []})
event = sideband.recv()
sideband.close()
The SDK intentionally exposes only the ChatGPT-authenticated v3 transport. It does not retain the separately billed API-key Voice v2 WebSocket helpers.
Embeddings
embedding = client.embeddings.create(
model="text-embedding-3-small",
input="Embed this sentence.",
dimensions=256,
)
print(embedding.data[0].embedding)
Unlike ChatGPT transcription and Codex image generation, embeddings target the OpenAI Platform endpoint and may consume the associated platform quota.
Authentication and lifecycle
Browser OAuth
client = OpenAI().authenticate()
Use authenticate(interactive=False) to require existing usable credentials
without opening a browser, or force=True to request a fresh interactive login.
Device-code OAuth
client = OpenAI().authenticate_device_code(
on_code=lambda code: print(code.verification_url, code.user_code),
allowed_workspace_ids=["optional-workspace-id"],
)
This is suited to headless or remote harnesses that cannot receive a loopback OAuth callback.
Logout versus revocation
client.logout() # local, offline, idempotent
client.revoke() # remote OAuth revocation, then local cleanup
logout() does not invalidate the account session remotely. revoke() is an
explicit network mutation and clears local credentials only after success.
Reliability and safety
- Transient
429,5xx, timeout, and connection failures are retried by default; configuremax_retriesandretry_base_delayonOpenAI(...). - Private backend schemas may change without notice. Typed models are used only where a stable boundary is useful.
- Mutations are explicitly named and separated from discovery where possible.
- Payments, subscriptions, workspace administration, attestation, reporting, telemetry, analytics, and beacons are deliberately not exposed.
- Personal access tokens are outside this OAuth-focused SDK surface.
Documentation
- API reference: complete resource tree, methods, parameters, return values, and important validation behavior.
- Backend protocol notes: wire contracts, payload details, backend limitations, and live observations.
- Endpoint coverage: exposed, live-probed, contract-tested, and excluded surfaces.
- Desktop endpoint inventory: audited source snapshots and comparison with the official Desktop client.
- Changelog: user-visible SDK changes.
Development
uv sync --extra dev
uv run pytest -q
uv run python -m compileall -q codex_backend_sdk
uv build
Live probes are intentionally kept separate from the deterministic test suite: tests must not consume quota, mutate account state, or depend on rollout state.
License
MIT. See LICENSE.
Release files for codex-backend-sdk 0.5.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| codex_backend_sdk-0.5.2.tar.gz | 178.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| codex_backend_sdk-0.5.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 256.5 kB
Release files / codex_backend_sdk-0.5.2.tar.gz
| Download URL | codex_backend_sdk-0.5.2.tar.gz |
|---|---|
| Size | 178.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
35caf1b3e580aac60d0fa202d4e0e2bbdaa598177f5b2cc5ca6810fe426e0685
|
|
BLAKE2b-256 checksum How to use checksums |
98e399e98323312876e5865f1643a188553fcb1505a5e90316c5ad565d850a40
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Release files / codex_backend_sdk-0.5.2-py3-none-any.whl
| Download URL | codex_backend_sdk-0.5.2-py3-none-any.whl |
|---|---|
| Size | 78.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8d19c2549414a923eafae6e20f16cae8c20cbb63fa0581db0570476622cc86ed
|
|
BLAKE2b-256 checksum How to use checksums |
24b513fc0132424a7442bfcc128ea328ad4f56fa1269b4e2668f1c12ee34fcb4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|