API Reference
November 24, 2025 ยท View on GitHub
Overview
Codex WebUI exposes a RESTful HTTP API and Server-Sent Events (SSE) for real-time communication. This document provides complete API specifications for all endpoints.
Base Configuration
Server Configuration
Default Values:
HOST=127.0.0.1
PORT=5055
WEBUI_TOKEN= # Optional bearer token
ALLOW_ORIGIN=http://localhost:5055
Base URL: http://127.0.0.1:5055
Authentication
Read Endpoints: No authentication required
Write Endpoints: Require authentication when WEBUI_TOKEN is set
Authentication Header:
Authorization: Bearer <WEBUI_TOKEN>
Responses:
401 Unauthorized- Invalid or missing token (when token is configured)200 OK- Authentication successful
CORS
All endpoints include CORS headers:
Access-Control-Allow-Origin: <ALLOW_ORIGIN>
Access-Control-Allow-Methods: GET,POST,PUT,DELETE,OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization
OPTIONS Requests: All endpoints support preflight OPTIONS requests.
Endpoints
Static Files
GET /
Serves the main UI (index.html).
Response:
Content-Type: text/html- Status:
200 OK - Body: HTML content
Example:
curl http://127.0.0.1:5055/
Health Check
GET /health
Health check endpoint for monitoring.
Response:
{
"ok": true
}
Status Codes:
200 OK- Server is running
Example:
curl http://127.0.0.1:5055/health
Server-Sent Events
GET /events
Establishes an SSE connection for real-time server updates.
Headers:
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
Event Format:
event: <event_type>
data: <json_data>
Initial Event: Upon connection, immediately sends current status:
event: status
data: {"resumed":true,"resume_path":"...","memory":[...],"config":{...}}
Keepalive:
- Sent every 15 seconds:
: ping\n\n - Prevents proxy timeouts
- No action required from client
Event Types: See SSE Events section below.
Example (JavaScript):
const eventSource = new EventSource('http://127.0.0.1:5055/events');
eventSource.addEventListener('status', (e) => {
const data = JSON.parse(e.data);
console.log('Status:', data);
});
eventSource.addEventListener('delta', (e) => {
const data = JSON.parse(e.data);
process.stdout.write(data.text);
});
Example (curl):
curl -N http://127.0.0.1:5055/events
Messaging
POST /message
Send a user message to Codex.
Authentication: Required if WEBUI_TOKEN is set.
Request Body:
{
"text": "User message text"
}
Constraints:
textmust be a stringtextmust not be empty after trimming- Maximum length: 16,384 characters (16 KB)
Response:
{
"ok": true
}
Status Codes:
200 OK- Message accepted and queued400 Bad Request- Invalid JSON or text constraints violated401 Unauthorized- Missing or invalid token
Behavior:
- Starts Codex process if not running
- Injects memory facts into message
- Sends to Codex via stdin
- Response streams via SSE (delta events)
Example:
curl -X POST http://127.0.0.1:5055/message \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-token" \
-d '{"text": "Create a hello world Python script"}'
Session Management
GET /sessions
List all session files in ~/.codex/sessions/.
Response:
{
"sessions": [
{
"path": "/home/user/.codex/sessions/rollout-abc123.jsonl",
"name": "rollout-abc123.jsonl",
"mtimeMs": 1700000000000,
"size": 12345
}
],
"current": "/home/user/.codex/sessions/rollout-abc123.jsonl"
}
Fields:
sessions- Array of session objects sorted by modification time (newest first)path- Absolute file pathname- FilenamemtimeMs- Last modified timestamp (milliseconds since epoch)size- File size in bytes
current- Path of currently resumed session (null if none)
Status Codes:
200 OK- Sessions listed successfully
Example:
curl http://127.0.0.1:5055/sessions
GET /session-messages
Get parsed messages from the current session.
Response:
{
"messages": [
{
"role": "user",
"text": "Create a Python script"
},
{
"role": "assistant",
"text": "I'll create a Python script for you..."
}
]
}
Fields:
messages- Array of message objects (last 100 messages)role- Either "user" or "assistant"text- Message content
Status Codes:
200 OK- Messages retrieved (empty array if no current session)
Example:
curl http://127.0.0.1:5055/session-messages
POST /resume
Resume from a specific session file.
Authentication: Required if WEBUI_TOKEN is set.
Request Body:
{
"path": "/home/user/.codex/sessions/rollout-abc123.jsonl"
}
Alternative:
{
"resume_path": "/home/user/.codex/sessions/rollout-abc123.jsonl"
}
Constraints:
- Path must be within
~/.codex/sessions/ - Filename must match pattern
rollout-*.jsonl - File must exist
Response:
{
"ok": true,
"resume_path": "/home/user/.codex/sessions/rollout-abc123.jsonl"
}
Error Response:
{
"ok": false,
"error": "Invalid resume path"
}
Status Codes:
200 OK- Resume successful400 Bad Request- Invalid path or file not found401 Unauthorized- Missing or invalid token
Behavior:
- Stops current Codex process
- Starts new process with resume flag
- Broadcasts status update via SSE
Example:
curl -X POST http://127.0.0.1:5055/resume \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-token" \
-d '{"path": "/home/user/.codex/sessions/rollout-abc123.jsonl"}'
DELETE /session
Delete a session file.
Authentication: Required if WEBUI_TOKEN is set.
Request Body:
{
"path": "/home/user/.codex/sessions/rollout-abc123.jsonl"
}
Response:
{
"ok": true
}
Status Codes:
200 OK- Session deleted successfully400 Bad Request- Invalid JSON or path403 Forbidden- Path outside sessions directory or invalid pattern401 Unauthorized- Missing or invalid token
Behavior:
- Validates path is within
~/.codex/sessions/ - Validates filename matches
rollout-*.jsonl - Deletes file
- Removes from history.json
- Clears current resume if deleted
Example:
curl -X DELETE http://127.0.0.1:5055/session \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-token" \
-d '{"path": "/home/user/.codex/sessions/rollout-abc123.jsonl"}'
Project History
GET /projects
Get session history grouped by working directory.
Response:
{
"groups": {
"/home/user/project1": [
{
"resume_path": "/home/user/.codex/sessions/rollout-abc.jsonl",
"workdir": "/home/user/project1",
"last_used": 1700000000000
}
],
"/home/user/project2": [
{
"resume_path": "/home/user/.codex/sessions/rollout-def.jsonl",
"workdir": "/home/user/project2",
"last_used": 1699900000000
}
]
}
}
Fields:
groups- Object keyed by workdir path- Each group contains array of history entries
- Entries sorted by
last_used(newest first) - Fields:
resume_path- Session file pathworkdir- Working directorylast_used- Timestamp in milliseconds
Status Codes:
200 OK- Projects retrieved
Example:
curl http://127.0.0.1:5055/projects
DELETE /project-history
Remove an entry from project history (doesn't delete session file).
Authentication: Required if WEBUI_TOKEN is set.
Request Body:
{
"resume_path": "/home/user/.codex/sessions/rollout-abc123.jsonl"
}
Response:
{
"ok": true
}
Status Codes:
200 OK- Entry removed400 Bad Request- Invalid JSON401 Unauthorized- Missing or invalid token
Note: This only removes the history entry, not the session file itself.
Example:
curl -X DELETE http://127.0.0.1:5055/project-history \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-token" \
-d '{"resume_path": "/home/user/.codex/sessions/rollout-abc123.jsonl"}'
Memory Management
GET /memory
Retrieve all memory facts.
Response:
{
"facts": [
"Uses JWT for authentication",
"Follow PEP 257 docstring conventions",
"Tests located in tests/ directory"
]
}
Fields:
facts- Array of fact strings- Extracted from
.codex/memory.md - Each fact is a markdown bullet point
Status Codes:
200 OK- Facts retrieved (empty array if no memory file)
Example:
curl http://127.0.0.1:5055/memory
DELETE /memory
Remove a specific memory fact.
Authentication: Required if WEBUI_TOKEN is set.
Request Body:
{
"fact": "Uses JWT for authentication"
}
Response:
{
"ok": true
}
Status Codes:
200 OK- Fact removed (or wasn't present)400 Bad Request- Invalid JSON or missing fact field401 Unauthorized- Missing or invalid token
Behavior:
- Reads memory.md
- Removes line matching
- <fact> - Writes updated memory.md
- Broadcasts status update
Example:
curl -X DELETE http://127.0.0.1:5055/memory \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-token" \
-d '{"fact": "Uses JWT for authentication"}'
Configuration
GET /config
Get current configuration.
Response:
{
"model": "gpt-5",
"tools.web_search_request": false,
"use_streamable_shell": true,
"sandbox_mode": "danger-full-access",
"approval_policy": "never",
"instructions_extra": ""
}
Fields:
model- AI model to usetools.web_search_request- Enable web search tooluse_streamable_shell- Enable streaming shell outputsandbox_mode- Execution sandbox levelapproval_policy- Auto-approval settinginstructions_extra- Additional instructions for agent
Status Codes:
200 OK- Configuration retrieved
Example:
curl http://127.0.0.1:5055/config
PUT /config
Update configuration.
Authentication: Required if WEBUI_TOKEN is set.
Request Body:
{
"model": "gpt-5",
"approval_policy": "never",
"sandbox_mode": "danger-full-access"
}
Allowed Keys:
modelapproval_policytools.web_search_requestuse_streamable_shellsandbox_modeinstructions_extra
Response:
{
"ok": true
}
Status Codes:
200 OK- Configuration updated400 Bad Request- Invalid JSON401 Unauthorized- Missing or invalid token
Behavior:
- Filters request to whitelisted keys only
- Merges with defaults
- Writes to config.toml
- Broadcasts status update
- Note: Changes apply to next Codex restart
Example:
curl -X PUT http://127.0.0.1:5055/config \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-token" \
-d '{"model": "gpt-5", "approval_policy": "auto"}'
Process Control
POST /restart
Restart Codex process with current resume path.
Authentication: Required if WEBUI_TOKEN is set.
Response:
{
"ok": true,
"resume_path": "/home/user/.codex/sessions/rollout-abc123.jsonl"
}
Status Codes:
200 OK- Restart initiated401 Unauthorized- Missing or invalid token
Behavior:
- Stops current Codex process
- Starts new process with same resume path
- Applies current configuration
Use Cases:
- Apply configuration changes
- Recover from hung process
- Reset session state
Example:
curl -X POST http://127.0.0.1:5055/restart \
-H "Authorization: Bearer your-token"
POST /shutdown
Gracefully shutdown Codex process.
Authentication: Required if WEBUI_TOKEN is set.
Response:
OK
Status Codes:
200 OK- Shutdown command sent
Behavior:
- Sends shutdown control message to Codex stdin
- Closes stdin stream
- Process exits naturally
- Server continues running (only Codex stops)
Example:
curl -X POST http://127.0.0.1:5055/shutdown \
-H "Authorization: Bearer your-token"
SSE Events
Event: status
System state update.
Data:
{
"resumed": true,
"resume_path": "/home/user/.codex/sessions/rollout-abc123.jsonl",
"resume_meta": {
"name": "rollout-abc123.jsonl",
"mtimeMs": 1700000000000,
"size": 12345
},
"memory": [
"Memory fact 1",
"Memory fact 2"
],
"config": {
"model": "gpt-5",
"approval_policy": "never"
}
}
Sent:
- On initial connection
- After configuration changes
- After memory updates
- After resume operations
Event: delta
Incremental message text from agent.
Data:
{
"text": "text chunk"
}
Sent:
- During agent response streaming
- Multiple deltas form complete message
Usage:
let buffer = '';
eventSource.addEventListener('delta', (e) => {
const data = JSON.parse(e.data);
buffer += data.text;
// Update UI incrementally
});
Event: message
Complete agent message.
Data:
{
"text": "Complete agent response text"
}
Sent:
- After all deltas for a message
- Signals message completion
Event: tool
Tool execution notification.
Data:
{
"name": "Bash",
"detail": "ls -la"
}
or
{
"name": "Edit",
"detail": "apply_patch"
}
Sent:
- When Codex begins tool execution
- Before tool output appears
Tool Names:
Bash- Shell command executionEdit- File patch application
Event: system
System-level notifications.
Data:
{
"text": "Codex session configured"
}
Examples:
- "Codex session configured"
- "Resuming from rollout:
" - "Codex exited with code 0"
- "Task complete"
Sent:
- On process lifecycle events
- Session state changes
- Task completion
Event: stderr
Raw stderr from Codex process.
Data:
{
"text": "stderr output text"
}
Sent:
- When Codex writes to stderr
- Useful for debugging
Event: error
Error messages from Codex.
Data:
{
"text": "Error message"
}
Sent:
- When Codex reports errors
- On tool execution failures
Error Responses
HTTP Status Codes
| Code | Meaning | Common Causes |
|---|---|---|
| 200 | OK | Request successful |
| 204 | No Content | OPTIONS preflight, favicon |
| 400 | Bad Request | Invalid JSON, missing fields, constraint violations |
| 401 | Unauthorized | Missing/invalid token when required |
| 403 | Forbidden | Path validation failure |
| 404 | Not Found | Static file not found |
Error Response Format
4xx Errors:
{
"ok": false,
"error": "Error description"
}
or plain text:
Bad JSON
Examples:
// Invalid resume path
{
"ok": false,
"error": "Invalid resume path"
}
// Missing field
"Missing text"
// Bad JSON
"Bad JSON"
Rate Limiting
None implemented.
Server is designed for single-user local usage. If exposed publicly, implement rate limiting at reverse proxy level.
Pagination
Not implemented.
All list endpoints return complete results:
/sessions- All session files/session-messages- Last 100 messages only/projects- All history entries/memory- All facts
For large datasets, consider implementing pagination in future versions.
Versioning
Current Version: 1.0.0
API Stability: Stable
Breaking Changes: Will be announced via:
- GitHub releases
- README updates
- CHANGELOG entries
Backward Compatibility: Minor versions maintain compatibility.
WebSocket Alternative
Not supported. Server uses Server-Sent Events (SSE) for streaming.
Rationale:
- Simpler protocol for one-way streaming
- Native browser support via EventSource
- Better proxy compatibility
- Sufficient for use case
For bidirectional communication needs, clients use HTTP POST for requests and SSE for responses.
CORS Configuration
Default:
Access-Control-Allow-Origin: http://localhost:5055
Configuration:
Set ALLOW_ORIGIN environment variable:
ALLOW_ORIGIN=https://example.com node server.js
Security Note: Be cautious when setting ALLOW_ORIGIN for production deployments.
Example Client Implementations
JavaScript (Browser)
// Connect to SSE
const eventSource = new EventSource('http://127.0.0.1:5055/events');
eventSource.addEventListener('status', (e) => {
console.log('Status:', JSON.parse(e.data));
});
eventSource.addEventListener('delta', (e) => {
const { text } = JSON.parse(e.data);
document.getElementById('output').textContent += text;
});
// Send message
async function sendMessage(text) {
const response = await fetch('http://127.0.0.1:5055/message', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer your-token'
},
body: JSON.stringify({ text })
});
return response.json();
}
Python
import requests
import json
from sseclient import SSEClient # pip install sseclient-py
# Connect to SSE stream
def listen_events():
url = 'http://127.0.0.1:5055/events'
messages = SSEClient(url)
for msg in messages:
if msg.event == 'delta':
data = json.loads(msg.data)
print(data['text'], end='', flush=True)
elif msg.event == 'status':
data = json.loads(msg.data)
print(f"\nStatus: {data['resumed']}")
# Send message
def send_message(text, token=None):
url = 'http://127.0.0.1:5055/message'
headers = {'Content-Type': 'application/json'}
if token:
headers['Authorization'] = f'Bearer {token}'
response = requests.post(url,
headers=headers,
json={'text': text}
)
return response.json()
Curl
# Send message
curl -X POST http://127.0.0.1:5055/message \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-token" \
-d '{"text": "Hello Codex"}'
# Get sessions
curl http://127.0.0.1:5055/sessions | jq
# Listen to events
curl -N http://127.0.0.1:5055/events
# Get config
curl http://127.0.0.1:5055/config | jq
# Update config
curl -X PUT http://127.0.0.1:5055/config \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-token" \
-d '{"model": "gpt-5"}'
Troubleshooting
Connection Issues
Problem: Cannot connect to server
Solutions:
- Verify server is running:
curl http://127.0.0.1:5055/health - Check port:
netstat -an | grep 5055 - Verify HOST/PORT environment variables
- Check firewall settings
SSE Disconnects
Problem: EventSource keeps disconnecting
Solutions:
- Check proxy timeout settings (increase to 60s+)
- Verify keepalive pings are received
- Check browser console for errors
- Try different browser
Authentication Errors
Problem: 401 Unauthorized
Solutions:
- Verify WEBUI_TOKEN is set correctly
- Check Authorization header format
- Ensure token matches on client and server
- Test without token (unset WEBUI_TOKEN)
Large Responses
Problem: Timeout or truncation
Solutions:
- SSE streams indefinitely (no timeout)
- HTTP requests have default timeouts
- Increase client timeout settings
- For very large sessions, consider pagination
Best Practices
- Always handle SSE reconnection - EventSource does this automatically
- Buffer delta events - Don't render each character individually
- Implement backoff - For failed HTTP requests
- Validate input - Before sending to API
- Handle errors gracefully - Display user-friendly messages
- Use HTTPS in production - With reverse proxy
- Set strong tokens - When exposing beyond localhost
- Monitor connection status - Provide UI feedback
- Test error paths - Don't just test happy path
- Keep tokens secret - Never commit to version control
Future API Additions
Potential future endpoints (not yet implemented):
GET /sessions?search=<query>- Search sessionsGET /export?path=<rollout>- Export transcriptGET /logs?lines=200- Recent logsPOST /import- Import session fileGET /profiles- Configuration profilesPUT /profiles/:name- Update profile
See DESIGN.md for rationale on future directions.