EN ▾
Get API key

Codex API in Python: Calling a Coding LLM

The simplest codex api python setup is the official openai package pointed at a different base URL. The examples below cover code generation, JSON mode, tool calling and streaming against this OpenAI-compatible endpoint.

Updated

A glowing cable winding through code blocks into a server cube, illustrating Python calls to a coding LLM API
A glowing cable connecting a laptop to a server cube, illustrating pointing a client at an API base URL

Key points

  • Install the openai package, set base_url to https://api.getcodexapi.com/v1 and model to uncensored.
  • Use low temperature (0 to 0.3) for code and JSON, higher for brainstorming.
  • Tool calls, JSON mode and streaming are supported; embeddings are not.
  • Cap concurrency at 8 on a full key and retry 429 responses after a short wait.

Setup and a first call

This is an independent OpenAI-compatible service, not OpenAI's own Codex API. Its single model is open-weight, text only, and handles code well enough for generation, explanation and refactoring tasks you should still review. If you want the background first, the page on the OpenAI Codex API explains how the two relate.

Install the SDK with pip install openai, create a key on the API key page, and run:

# pip install openai
from openai import OpenAI

client = OpenAI(base_url="https://api.getcodexapi.com/v1", api_key="YOUR_KEY")

resp = client.chat.completions.create(
    model="uncensored",
    messages=[
        {"role": "system", "content": "You are a senior Python developer. Reply with code only, no commentary."},
        {"role": "user", "content": "Write a function that parses an ISO 8601 date string and returns a datetime."},
    ],
    temperature=0.2,
)
print(resp.choices[0].message.content)

The new users' trial credit of $0.50 covers thousands of small calls like this one. Temperature is 0.2 because code benefits from less randomness. If you see a markdown fence around the answer, strip it in code or ask in the system message for raw text. The base URL page, Codex API base URL, lists the exact address again.

Prompting for code that runs

A few habits improve output more than any parameter.

  • State the language and version. "Python 3.11, standard library only" removes a lot of guessing.
  • Give the signature. Paste the function header and a docstring, and ask the model to fill the body.
  • Show one example input and output. It pins down edge cases better than prose.
  • Ask for one thing. Generate the function, then ask for tests in a second call.
  • Request a diff for edits. Whole-file rewrites burn output tokens, which cost more than input.

The context window is 100,000 tokens, and max_tokens is optional. For a code task you can paste several modules and still have room for the reply. Setting max_tokens is useful only as a safety net against runaway output.

JSON mode for structured results

When code consumes the answer, use JSON mode. It makes the output valid JSON; it does not enforce your schema, so name the keys in the prompt and check them.

import json
from openai import OpenAI

client = OpenAI(base_url="https://api.getcodexapi.com/v1", api_key="YOUR_KEY")

resp = client.chat.completions.create(
    model="uncensored",
    response_format={"type": "json_object"},
    messages=[
        {"role": "system", "content": "Return JSON with keys: name, args (list of strings), returns."},
        {"role": "user", "content": "Describe the signature of: def clamp(x, lo, hi)."},
    ],
    temperature=0,
)
data = json.loads(resp.choices[0].message.content)
print(data["name"], data["args"])

Pair this with a try/except around json.loads and a single retry that sends the parse error back. In practice that handles the rare malformed response. Use temperature 0 so repeated runs match.

Tool calling

With tools you describe functions and the model decides when to call them. You run the function, then send the output back with the tool role. This is the base of every coding agent.

import json
from openai import OpenAI

client = OpenAI(base_url="https://api.getcodexapi.com/v1", api_key="YOUR_KEY")

tools = [{
    "type": "function",
    "function": {
        "name": "run_tests",
        "description": "Run the project's test suite and return the output.",
        "parameters": {
            "type": "object",
            "properties": {"path": {"type": "string"}},
            "required": ["path"],
        },
    },
}]

messages = [{"role": "user", "content": "Run the tests in tests/unit and tell me what failed."}]
first = client.chat.completions.create(model="uncensored", messages=messages, tools=tools, tool_choice="auto")
msg = first.choices[0].message

if msg.tool_calls:
    call = msg.tool_calls[0]
    args = json.loads(call.function.arguments)
    output = "2 passed, 1 failed: test_parse_empty"          # replace with a real runner
    messages.append(msg)
    messages.append({"role": "tool", "tool_call_id": call.id, "content": output})
    final = client.chat.completions.create(model="uncensored", messages=messages, tools=tools)
    print(final.choices[0].message.content)

Test generated code like any other contribution: run it, lint it, and keep a small suite of prompts with known-good outputs so you notice when a prompt change makes results worse. Pin seed and temperature while you compare versions.

Notes: keep tool descriptions short and literal, validate arguments before running anything, and never pass model output straight into a shell. For a loop, repeat the call while tool_calls is present and stop after a maximum number of steps. Each step resends the history, so a ten-step run pays for roughly ten times the context.

Streaming and retry on 429

For interactive tools, stream tokens as they arrive. Usage comes at the end of the stream, which makes cost logging easy.

import time
from openai import OpenAI, RateLimitError

client = OpenAI(base_url="https://api.getcodexapi.com/v1", api_key="YOUR_KEY", max_retries=0)

def ask(prompt, tries=4):
    for attempt in range(tries):
        try:
            stream = client.chat.completions.create(
                model="uncensored",
                messages=[{"role": "user", "content": prompt}],
                stream=True,
                stream_options={"include_usage": True},
            )
            text = []
            for chunk in stream:
                if chunk.choices and chunk.choices[0].delta.content:
                    piece = chunk.choices[0].delta.content
                    text.append(piece)
                    print(piece, end="", flush=True)
                if chunk.usage:
                    print("\ntokens:", chunk.usage.prompt_tokens, chunk.usage.completion_tokens)
            return "".join(text)
        except RateLimitError:
            time.sleep(5 * (attempt + 1))
    raise RuntimeError("still rate limited")

ask("Explain Python generators in four sentences.")

The limits behind that retry loop: a full key allows 8 concurrent requests and 300 per minute, and a trial key 2 and 60. Over a limit you get HTTP 429 with code rate_limited or concurrency. Temporary overload also gives 429 with a Retry-After: 5 header. The example sets max_retries=0 on the client so your own loop controls the waits. A streamed request holds its concurrency slot until the stream finishes, so always consume or close the stream.

Running many requests at once

Batch jobs such as generating tests for a hundred functions need a concurrency cap. Use a thread pool with at most 8 workers on a full key.

A simple pattern is ThreadPoolExecutor(max_workers=6) around a function that calls ask, leaving two slots free for other work. With the trial key use 2 workers. If you pass a bigger number, the API will answer extra requests with concurrency errors, and your retry loop will spend time waiting instead of working. For async code, use AsyncOpenAI with an asyncio.Semaphore(6) around each call; it gives the same cap without threads. The X-RateLimit-Limit-Requests and X-RateLimit-Limit-Concurrency response headers show the limits for your key.

Cost of coding workloads

The price is $0.15 per 1M input tokens and $0.50 per 1M output tokens. Say you generate unit tests for 200 functions. Each call sends 1,500 input tokens and returns 700 tokens. Input: 200 x 1,500 = 300,000 tokens, or $0.045. Output: 200 x 700 = 140,000 tokens, or $0.07. Total: $0.115.

A refactor of a large file sends 30,000 tokens in and 8,000 out: $0.0045 + $0.004 = $0.0085 per run. Failed or refused requests are not charged, and credit never expires. Top-ups start at $20 and can be paid by card or crypto, with a bonus of 5% from $50, 10% from $100 and 15% from $200. See pricing, and read the docs for the full parameter list.

Questions and answers

Can I use the standard openai Python package?

Yes. Set base_url to https://api.getcodexapi.com/v1, pass your key and use the model ID uncensored.

Does it support function calling from Python?

Yes. Pass tools and tool_choice, then return results with the tool role. Streamed tool_calls also work.

How do I get structured output?

Use response_format with type json_object, name the keys in your prompt and validate the result in code.

Is there an async client?

The openai package provides AsyncOpenAI, which works the same way with this base URL. Keep concurrency at or below 8 on a full key.

Your key is one form away

Create an account, copy the key, change the base URL. That is the whole setup.

Get API key