Build with Codex.
An OpenAI-compatible API backed by the Codex account connected to each API key. Existing OpenAI SDKs work by changing the base URL and key.
Authentication
Every API request requires a authapi.dev key in the HTTP bearer authorization header. Create a key from your dashboard after connecting Codex.
Keys are scoped to the account that created them. Requests use that account’s connected Codex session.
Authorization: Bearer $KEY
Quick start
Send your first request with curl, or point the official OpenAI SDK at this API.
OpenAI Python SDK
Set base_url to the AuthAPI and pass your dashboard key. The rest of the client interface remains unchanged.
curl https://authapi.dev/v1/chat/completions \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-5.6-sol",
"messages": [
{"role": "user", "content": "Hello"}
]
}'
Streaming
Set stream: true to receive output as server-sent events while it is generated.
Chat Completions emits chat.completion.chunk objects and ends with data: [DONE]. Tool calls use indexed delta.tool_calls argument fragments and finish with finish_reason: tool_calls. Responses preserves typed events including response.output_item.added/done and response.function_call_arguments.delta/done.
from openai import OpenAI
client = OpenAI(
base_url="https://authapi.dev/v1",
api_key=KEY,
)
stream = client.chat.completions.create(
model="gpt-5.6-sol",
messages=[{"role": "user", "content": "Hello"}],
stream=True,
)
for chunk in stream:
text = chunk.choices[0].delta.content
print(text or "", end="")
/v1/health
Checks both your API key and its owner’s connected Codex authorization. Send the API key in the bearer authorization header, never in the URL.
| Status | Meaning |
|---|---|
| 200 | The API key is valid and Codex is connected. |
| 401 | The API key is missing, invalid, or revoked. |
| 503 | The API key is valid, but Codex must be reconnected. |
curl https://authapi.dev/v1/health \
-H "Authorization: Bearer $CODEX...e>
/v1/models
Lists the models currently exposed by Codex in OpenAI-compatible model-list format.
| Returns | Description |
|---|---|
| object | Always list. |
| data[] | Available model objects. Use each object’s id in generation requests. |
curl https://authapi.dev/v1/models \ -H "Authorization: Bearer $KEY"
/v1/chat/completions
Creates an OpenAI-compatible chat completion with native function tools. The gateway relays calls and results but never executes client tools.
| Parameter | Description |
|---|---|
| model | Model ID. Defaults to gpt-5.6-sol. |
| messages | Required system, developer, user, assistant, and tool messages. Assistant calls use tool_calls; results use role: tool and tool_call_id. |
| tools | Up to 128 nested OpenAI function definitions. |
| tool_choice | none, auto, required, or a forced function. |
| parallel_tool_calls | Allow one response to contain multiple calls. |
| reasoning_effort | Reasoning level supported by the selected model. |
| stream | When true, returns OpenAI-compatible SSE chunks. |
{
"model": "gpt-5.6-sol",
"messages": [{"role": "user", "content": "Weather in Paris?"}],
"tools": [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get current weather",
"parameters": {"type": "object", "properties": {
"city": {"type": "string"}
}}
}
}],
"tool_choice": "auto",
"parallel_tool_calls": true
}
content: null, stable call IDs, and finish_reason: tool_calls. Send results back as tool messages./v1/responses
Creates an OpenAI Responses response with flat function tools and canonical function_call/function_call_output items.
| Parameter | Description |
|---|---|
| model | Model ID. Defaults to gpt-5.6-sol. |
| input | Required string or structured message/function item array. |
| instructions | Optional developer-level instructions. |
| tools | Up to 128 flat function definitions. |
| tool_choice | none, auto, required, or a forced function. |
| parallel_tool_calls | Allow multiple function calls. |
| reasoning.effort | Reasoning level for the selected model. |
| stream | When true, preserves typed Responses API events. |
{
"model": "gpt-5.6-sol",
"input": [{
"role": "user",
"content": [{"type": "input_text", "text": "Weather in Oslo?"}]
}],
"tools": [{
"type": "function",
"name": "get_weather",
"description": "Get current weather",
"parameters": {"type": "object", "properties": {
"city": {"type": "string"}
}}
}],
"tool_choice": "auto",
"parallel_tool_calls": true,
"stream": true
}
call_id. Execute them client-side, then submit a function_call_output item using that ID. Final event: response.completed./v1/images/generations
Generates an image and returns OpenAI-compatible base64 image data. Every response includes X-Request-Id. A supplied canonical UUID is accepted; invalid or unsafe values are replaced. Disconnects and the bounded image timeout cancel upstream work.
| Parameter | Description |
|---|---|
| prompt | Required description of the image. |
| size | 1024x1024, 1536x1024, or 1024x1536. |
| quality | low, medium, or high. |
| output_format | Output format, defaulting to png. |
{
"model": "gpt-image-1",
"prompt": "A technical blueprint of a lunar rover",
"size": "1536x1024",
"quality": "medium"
}
/v1/images/edits
Edits one or more supplied images. Send multipart form data for files, or JSON with image data URLs.
| Parameter | Description |
|---|---|
| image | Required source image file or data URL. Multiple images are supported. |
| prompt | Required edit instruction. |
| size | Requested output dimensions. |
| quality | Requested image quality. |
curl https://authapi.dev/v1/images/edits \ -H "Authorization: Bearer $KEY" \ -F "image=@source.png" \ -F "prompt=Make the background transparent" \ -F "size=1024x1024"
/v1/limits (alias: /limits)
Requires a bearer API key and returns normalized provider-reported Codex quota windows for that key’s owner. Browser session identity is not used. Account IDs, email, OAuth tokens, and key data are omitted. Successes and errors use Cache-Control: private, no-store.
curl https://authapi.dev/v1/limits \ -H "Authorization: Bearer $AUTHAPI_KEY"
/v1/audio/transcriptions
Transcribes one uploaded audio file using the API key owner’s connected Codex account and the same private batch route used by the Codex prompt box. Audio and transcripts are not logged or stored by AuthAPI.
| Parameter | Description |
|---|---|
| file | Required audio file up to 25 MB: FLAC, M4A, MP3/MP4/MPEG/MPGA, OGA/OGG, WAV, or WebM. |
| model | Required. codex-transcribe or gpt-4o-mini-transcribe. |
| language | Optional ISO language code such as en or en-US. |
| response_format | json (default) or text. |
This compatibility subset does not support prompts, temperature, timestamps, or verbose JSON. Successful responses use Cache-Control: no-store.
curl https://authapi.dev/v1/audio/transcriptions \ -H "Authorization: Bearer $KEY" \ -F "file=@recording.webm" \ -F "model=codex-transcribe" \ -F "language=en"
{"text":"Transcribed speech."}
/v1/audio/speech
Generates spoken audio using the API key owner’s connected Codex account. The server uses Codex’s realtime output-audio stream and returns audio only after the spoken transcript is verified against the requested text. Input text, transcripts, and audio are not logged or stored.
| Parameter | Description |
|---|---|
| input | Required text, from 1 to 1,000 characters. |
| model | codex-tts (default), gpt-4o-mini-tts, or gpt-realtime-1.5. |
| voice | marin (default), alloy, ash, ballad, cedar, coral, echo, sage, shimmer, or verse. |
| response_format | wav (default) or raw pcm. Both are mono signed 16-bit little-endian PCM at 24 kHz. |
| instructions | Optional voice-style guidance up to 500 characters. |
| speed | Optional and currently must be 1. |
This is a restricted OpenAI speech compatibility subset. MP3 and other encoded formats are not supported. A transcript mismatch fails with 502 incomplete_speech rather than returning known-wrong audio.
curl https://authapi.dev/v1/audio/speech \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "codex-tts",
"input": "Hello from Codex.",
"voice": "marin",
"response_format": "wav"
}' \
--output speech.wav
/api/provider-usage
Returns current provider-reported Codex quota windows for the logged-in account. This browser-account endpoint requires the cxa_session cookie, removes upstream account identity and OAuth fields, and responds with Cache-Control: private, no-store.
| Field | Description |
|---|---|
| kind | five_hour, weekly, or other, classified from the provider’s reported window duration. |
| usedPercent | Percentage consumed, clamped to 0–100. |
| remainingPercent | Percentage available, calculated as 100 minus used. |
| resetsAt | Account-specific absolute reset time supplied by Codex. |
Primary and secondary positions are not assumed to mean 5-hour and weekly. Missing windows are not fabricated, and additional model-specific limits are returned as independent entries. Results are cached per owner/account for 30 seconds.
{
"available": true,
"fetchedAt": "2026-08-08T12:00:00.000Z",
"planType": "pro",
"limits": [{
"id": "codex",
"name": "Codex",
"allowed": true,
"limitReached": false,
"windows": [
{ "kind": "five_hour", "label": "5-hour",
"usedPercent": 25, "remainingPercent": 75,
"windowSeconds": 18000,
"resetsAt": "2026-08-08T17:00:00.000Z" },
{ "kind": "weekly", "label": "Weekly",
"usedPercent": 60, "remainingPercent": 40,
"windowSeconds": 604800,
"resetsAt": "2026-08-12T12:00:00.000Z" }
]
}]
}
/api/voice/session
Exchanges a complete WebRTC audio SDP offer for an answer using the authenticated owner’s connected Codex/ChatGPT OAuth account. Browser requests require the logged-in session cookie and same-origin Origin; origin-less clients may use a cxa bearer key whose owner has connected Codex.
tools. Frameless Bidi emits delegation.created over oai-events; your backend selects the function through Responses SSE, executes it, and the browser returns result context. AuthAPI never executes your tools.| Parameter | Description |
|---|---|
| sdp | Required bounded, ICE-complete WebRTC SDP offer with audio. |
| voice | Optional Codex V3 voice. Defaults to cove. |
| instructions | Optional assistant instructions, up to 16,384 characters. Requires tools. |
| tools | One to 128 flat OpenAI function definitions with type, name, and optional description, parameters, and strict. The client-delegation Responses adapter selects a function; your executor must allowlist names and validate arguments. |
| tool_choice | auto, none, required, or {"type":"function","name":"…"}. Defaults to auto. |
| response_model | Optional model used by the Responses adapter. Defaults to gpt-5.5. |
Audio uses browser WebRTC media tracks. Create oai-events before the offer and parse each message as one UTF-8 JSON object. The response never includes OAuth credentials, account ID, or the validated upstream call ID.
{
"sdp": "v=0\\r\\n…",
"voice": "cove",
"instructions": "Use functions when needed.",
"tools": [{
"type": "function",
"name": "get_weather",
"description": "Get current weather for a city.",
"parameters": {
"type": "object",
"properties": { "city": { "type": "string" } },
"required": ["city"],
"additionalProperties": false
},
"strict": true
}],
"tool_choice": "auto"
}
{
"sdp": "v=0\\r\\n…",
"protocol": { "transport": "webrtc", "architecture": "frameless-bidi", "version": 3,
"experimental": true, "dataChannel": "oai-events",
"model": "gpt-live-1-codex", "voice": "cove",
"delegation": "client", "functionTransport": "responses-adapter",
"responseModel": "gpt-5.5", "toolChoice": "auto", "toolCount": 1 }
}
Realtime transcript events
Select text by exact event type. Do not look for transcript fragments in top-level delta, text, or transcript properties.
| Event | Read and render |
|---|---|
input_transcript.added | Append event.item.text to the current user draft. |
output_transcript.added | Append event.item.text to the current assistant draft. |
turn.done | Use event.turn.role; replace its draft with the complete event.turn.transcript, then finalize it. |
*.added payload is a fragment and should be appended once. A turn.done transcript is the authoritative complete value and must replace, not append to, the draft.Ignore unknown event types and sanitize error events rather than displaying raw upstream details. A valid delegation.created may be handled only by an explicitly registered client function. See the complete transcript mapper and function adapter contract.
{"type":"input_transcript.added","item":{"text":"Can you "}}
{"type":"input_transcript.added","item":{"text":"hear me?"}}
{"type":"output_transcript.added","item":{"text":"Yes, I "}}
{
"type": "turn.done",
"turn": {
"role": "assistant",
"transcript": "Yes, I can."
}
}
if (event.type === 'input_transcript.added')
appendDraft('user', event.item?.text || '');
else if (event.type === 'output_transcript.added')
appendDraft('assistant', event.item?.text || '');
else if (event.type === 'turn.done')
finalizeDraft(event.turn?.role, event.turn?.transcript || '');
Custom voice function calls
Custom voice functions use two connected transports. Frameless Bidi sends delegation.created over the WebRTC oai-events channel. Your backend submits the delegated text and fixed tool registry to bearer-authenticated POST /v1/responses, executes exactly one validated function, then the browser returns sanitized result context over the existing data channel.
/api/voice/session directly. Send the browser's SDP to your authenticated, CSRF-protected backend, make the origin-less bearer request server-to-server, and bind later delegation work to a short-lived application voice-session ID. The same backend should call /v1/responses, rate-limit requests, and execute only fixed privileged functions.Deployment topology
- The browser creates
RTCPeerConnection, adds microphone tracks, createsoai-eventsbeforecreateOffer(), and waits for ICE gathering. - Your backend injects its allowlisted tools and API key into
POST /api/voice/session; the browser applies the returned SDP answer. - On
delegation.created, key work byevent.item.idand send the joinedinput_textto your backend. - Your backend calls
https://authapi.dev/v1/responseswithstream: trueandparallel_tool_calls: false. - Require
response.completed, exactly one allowlisted call, complete JSON arguments, and local schema validation before execution. - Return the stringified result to the browser, which sends
delegation.context.appendand waits fordelegation.context.appended.
The session's response_model value becomes the Responses request's model field, and the normalized session tool_choice must also be retained for the Responses request. Voice instructions control when the live model delegates; separate Responses instructions control tool selection and arguments. Do not copy untrusted voice instructions into a privileged selector.
Correlation and fail-closed rules
| VALUE | USE |
|---|---|
event.item.id | The voice delegation_item_id. Cache work by this ID so duplicate events cannot execute a side effect twice. |
Responses call_id | Identifies the selected function call and its string output. |
handoff_id | Optional voice transport metadata. Do not use it as either ID above. |
Zero calls, multiple calls, unknown names, invalid arguments, failed or truncated SSE, timeouts, and execution exceptions must execute nothing. Send short failure context so the spoken turn is not left waiting. Never blindly re-execute because an acknowledgement is delayed.
Browser Your backend AuthAPI
RTCPeerConnection
POST /voice/session ----------> add tools + bearer key ----> /api/voice/session
<----------------------------- SDP answer <---------------- 201 SDP answer
oai-events: delegation.created
POST /voice/delegation -------> select + execute ----------> /v1/responses SSE
<----------------------------- sanitized result <---------- function_call
oai-events: delegation.context.append
delegation.context.appended
{"type":"delegation.created","item":{
"id":"delegation_123",
"type":"delegation",
"target":"client",
"content":[{"type":"input_text","text":"Weather in Chicago?"}]
}}
{"type":"response.output_item.added","item":{
"id":"fc_123","type":"function_call",
"call_id":"call_123","name":"get_weather","arguments":""
}}
{"type":"response.function_call_arguments.done",
"item_id":"fc_123","arguments":"{\"city\":\"Chicago\"}"}
{"type":"response.completed","response":{"status":"completed"}}
Errors
Errors use an OpenAI-compatible envelope. Authentication failures return HTTP 401 or 403; invalid input returns HTTP 400; upstream generation failures return HTTP 502.
{
"error": {
"message": "Incorrect API key provided.",
"type": "invalid_request_error",
"param": null,
"code": "invalid_api_key"
}
}