Codex CLI, OpenAI SDK & LiteLLM with Claude: OpenAI-Compatible Setup
TL;DR
As of today, every endpoint at https://llmapi.pro/v1 speaks both protocols:
| Protocol | Endpoint | Who uses it |
|---|---|---|
| Anthropic Messages | POST /v1/messages |
Claude Code, Hermes, IDE plugins, anthropic-sdk |
| OpenAI Chat Completions | POST /v1/chat/completions |
OpenAI SDK, LiteLLM, older Codex versions, most community CLIs |
| OpenAI Responses | POST /v1/responses |
Codex CLI 0.130+ (it dropped chat/completions support) |
Same API key. Same models. Same pricing. You don't have to pick a protocol up front — point your client at our base URL and use whatever it speaks natively.
Why we did this
A user asked twice in two days how to wire Codex CLI through LLM API. The honest answer at the time was "Codex CLI speaks OpenAI's protocol, we don't expose that yet, please use Claude Code instead."
That answer wasn't good enough. The whole point of a relay is that you bring your tools and we adapt — not the other way around. So we shipped the adapter the same evening.
Codex CLI setup (5 minutes)
Codex CLI 0.130 only supports OpenAI's Responses API (the older chat/completions wire format was removed in this release). The config we use:
~/.codex/config.toml:
model = "claude-sonnet-4-7"
model_provider = "llmapi"
[model_providers.llmapi]
name = "llmapi"
base_url = "https://llmapi.pro/v1"
wire_api = "responses"
env_key = "OPENAI_API_KEY"
Then:
export OPENAI_API_KEY=sk-relay-your-key-here
codex exec "list the files in this folder and tell me what each does"
Tool calling works end-to-end — Codex will spawn shell commands, get their output back through us, and finish the turn normally. We tested the full chain (multi-step ls/cat/grep sequences with sandbox=read-only) on the production binary before announcing.
OpenAI SDK (Python)
from openai import OpenAI
client = OpenAI(
base_url="https://llmapi.pro/v1",
api_key="sk-relay-your-key-here",
)
resp = client.chat.completions.create(
model="claude-sonnet-4-7",
messages=[
{"role": "system", "content": "You are a concise assistant."},
{"role": "user", "content": "Hello"},
],
stream=False,
)
print(resp.choices[0].message.content)
Streaming works the same way — pass stream=True and iterate the chat.completion.chunk events. We translate Anthropic's eight SSE event types into OpenAI's single chunk format internally, including delta.tool_calls.arguments for tool-use deltas. Your code looks like every other OpenAI SDK example on the internet; you don't have to know there's a translation layer in the middle.
OpenAI SDK (Node.js)
import OpenAI from 'openai';
const client = new OpenAI({
baseURL: 'https://llmapi.pro/v1',
apiKey: 'sk-relay-your-key-here',
});
const resp = await client.chat.completions.create({
model: 'claude-sonnet-4-7',
messages: [{ role: 'user', content: 'hello' }],
});
console.log(resp.choices[0].message.content);
LiteLLM
LiteLLM is the most common adapter for OpenAI-shaped multi-provider setups. Point it at our base URL with the openai/ prefix:
import litellm
resp = litellm.completion(
model="openai/claude-sonnet-4-7",
api_base="https://llmapi.pro/v1",
api_key="sk-relay-your-key-here",
messages=[{"role": "user", "content": "hello"}],
)
print(resp.choices[0].message.content)
Does the protocol choice cost anything?
No. Both protocols route through the same backend pool, charge the same tokens, and return responses from the same models. The translation layer is a few thousand lines of TypeScript that adds sub-millisecond overhead — well below the noise floor of a typical streaming generation.
What the protocol does affect is what feature surfaces you get. The two big ones today:
- Tool calling: OpenAI uses
tools[].function.parameters; Anthropic usestools[].input_schema. We translate both directions, including streamingtool_calls.argumentsdeltas. Codex CLI's full agentic loop (think → call shell → observe → think → respond) works end-to-end. - Streaming: OpenAI's SSE format is one chunk type (
chat.completion.chunk) with cumulative deltas. Anthropic's is eight event types (message_start,content_block_delta, etc.) with explicit lifecycle. Both work; pick whichever your client supports.
What about thinking / extended-reasoning?
OpenAI's Responses API has a reasoning.effort field (low / medium / high). We map that to Anthropic's thinking.budget_tokens internally:
OpenAI effort |
Anthropic budget |
|---|---|
low (or unset) |
thinking off |
medium |
8,000 tokens |
high |
16,000 tokens |
Thinking content is never leaked in the OpenAI response shape — there's no equivalent field in the OpenAI protocol, so the thinking blocks are dropped during translation. The model's final visible answer is what comes back in message.content.
Pricing
Same as the Anthropic endpoint. Subscription plans cover both protocols; per-token plans charge the same per-1M-token rates regardless of which endpoint you hit. See /pricing.
What's next
A few things on the roadmap that this announcement unblocks:
- Aider / Continue.dev / open-interpreter integration guides — these tools all speak OpenAI-shaped APIs natively and now work without any adapter on the user side.
- Cursor / Windsurf custom-endpoint setup — some IDE plugins expose an OpenAI-compatible "custom endpoint" field; same config as the SDK examples above.
- Sample Codex agent recipes — coding agents, code review, repo-wide refactors.
If you have a client we should test against, email us at support@llmapi.pro and we'll verify the setup.
llmapi.pro is an independent, Claude-compatible API relay; we are not affiliated with Anthropic or OpenAI. We use the ANTHROPIC_BASE_URL env var and OpenAI-shaped base_url config keys that both vendors document for pointing at compatible endpoints.