All posts

OpenAI Python SDK: Carpe Diem base_url, cdm_ key, real cost

·By Carpe Diem Team — Lumen Labs·6 min read
tutorielguidetechnicalai
A single gold filament splitting into dozens of threads toward geometric solids, black background.

This tutorial is for calling Carpe Diem from a Python script, with the OpenAI SDK you already use: chat, model list, model switch, streaming, cost readout. You install one package, openai==3.36.0, in a venv. Then two fields are enough: base_url set to https://carpe-diem.xyz/api/operator/v1 and a cdm_ key. Our 22 October 2026 run got pong from llama-3.3-70b for 524 micro-USDC; the same client listed 392 models.

A gold filament splitting toward a constellation of geometric solids, black background.

Illustration generated with seedream-v5-lite on Carpe Diem.

What you need

Nothing besides Python, a venv, the pinned OpenAI SDK, and a Carpe Diem key. No Carpe Diem CLI, no house SDK.

  • A Carpe Diem account with credits or a prepaid account, and a cdm_ key (API Keys tab of the buyer dashboard).
  • Python 3.10 or newer (openai==3.36.0 requires it).
  • pip inside a venv, to pin openai==3.36.0.

When you are done, you can: send a chat.completions.create (step 3), list ids via models.list() (step 3), read x-carpe-cost-usdc-micro (step 4), switch from llama-3.3-70b to claude-haiku-5-5 by changing one string (step 5), and stream a haiku (step 6).

Step 1: create a cdm_ key

Open Credits & keys, API Keys tab. Keys start with cdm_ and are shown only once. Choose how the key pays (Credits or Prepaid), optionally a name, then Create a key.

Credits: usage balance, 1 credit = 0,01 $, no withdrawal. Prepaid: an account you own; the protocol deducts only the cost of each call, withdrawal possible. Both settle in USDC on Base (guide, §4.1). A third rail, x402, pays from a wallet without a cdm_ key; this tutorial does not cover that rail.

Buyer dashboard API Keys tab: name field, Credits or Prepaid, Create a key button.

Copy it immediately into a secrets manager: it will not be shown again. In the tutorial shell:

export OPENAI_API_KEY=cdm_your_key_here

To try a model without code, use Create Hub.

Step 2: install openai 3.36.0

python3 -m venv .venv
.venv/bin/pip install openai==3.36.0

We did not test any other version of the package. The OpenAI client sends POST /chat/completions under base_url. For Carpe Diem, base_url must therefore already include /v1:

https://carpe-diem.xyz/api/operator/v1

Not https://carpe-diem.xyz/api/operator: that is the Anthropic adapter URL, a different protocol. The SDK guide states it at the top of the page, just above the OpenAI Python example.

Carpe Diem SDK page: Base URL https://carpe-diem.xyz/api/operator/v1 and the start of the Python example.

Step 3: send the first message

File hello.py (the client is recreated there, as in every snippet):

import os
from openai import OpenAI

client = OpenAI(
    base_url="https://carpe-diem.xyz/api/operator/v1",
    api_key=os.environ["OPENAI_API_KEY"],
)

response = client.chat.completions.create(
    model="llama-3.3-70b",
    messages=[{"role": "user", "content": "Reply with the exact word: pong"}],
    max_tokens=16,
)

print(response.choices[0].message.content)
print("model:", response.model)
print("usage:", response.usage)
.venv/bin/python hello.py

Output we got:

pong
model: llama-3.3-70b
usage: CompletionUsage(completion_tokens=2, prompt_tokens=1675, total_tokens=1677, …)

Two output tokens, but 1675 on input for a six-word sentence. On our two calls to llama-3.3-70b with this prompt, 1675 then 1695 input tokens were billed (2714 on Haiku). The origin of that preamble is not documented. max_tokens=16 caps output only.

To check that an id exists before writing the rest:

import os
from openai import OpenAI

client = OpenAI(
    base_url="https://carpe-diem.xyz/api/operator/v1",
    api_key=os.environ["OPENAI_API_KEY"],
)

models = client.models.list()
ids = sorted(m.id for m in models.data)
print("count:", len(ids))
print("has llama-3.3-70b:", "llama-3.3-70b" in ids)
print("has claude-haiku-5-5:", "claude-haiku-5-5" in ids)

Output: 392 ids, both True. models.list() calls GET /v1/models with the same key: no second client.

Step 4: read the call cost

The SDK JSON body does not carry the price. Carpe Diem puts it in HTTP headers, in micro-USDC (1 USDC = 1 000 000 micro-USDC), non-streaming only. That is documented in the SDK guide, X-Carpe-* header table. with_raw_response exposes them; raw.parse() returns the usual object.

File cost.py:

import os
from openai import OpenAI

client = OpenAI(
    base_url="https://carpe-diem.xyz/api/operator/v1",
    api_key=os.environ["OPENAI_API_KEY"],
)

raw = client.chat.completions.with_raw_response.create(
    model="llama-3.3-70b",
    messages=[{"role": "user", "content": "Reply with the exact word: pong"}],
    max_tokens=16,
)

headers = raw.headers
print("x-carpe-cost-usdc-micro:", headers.get("x-carpe-cost-usdc-micro"))
print("x-carpe-input-tokens:", headers.get("x-carpe-input-tokens"))
print("x-carpe-output-tokens:", headers.get("x-carpe-output-tokens"))
print("x-carpe-available-credits:", headers.get("x-carpe-available-credits"))
print("x-carpe-cached-tokens:", headers.get("x-carpe-cached-tokens"))

response = raw.parse()
print("text:", response.choices[0].message.content)
print("usage:", response.usage)

Headers read on this call:

  • x-carpe-cost-usdc-micro: 524
  • x-carpe-input-tokens: 1675
  • x-carpe-output-tokens: 2
  • x-carpe-available-credits: your remaining balance, in credits
  • x-carpe-cached-tokens: absent (None in the SDK)

524 micro-USDC. At 0,311 $ / 1,24 $ per million tokens (31,1 / 124 cr/M on /models, 1 credit = 0,01 $), 1675 × 0,311 $ / M + 2 × 1,24 $ / M = 523 micro-USDC. 523 calculated, 524 billed: the amount appears rounded up to the next micro-USDC.

Step 5: switch model with a string

Same client, different id. The public catalog shows prices in credits per million (1 credit = 0,01 $): llama-3.3-70b at 31,1 / 124 cr/M, claude-haiku-5-5 at 4,5 / 22,2 cr/M.

Models catalog: llama-3.3-70b at 31,1 / 124 cr/M and claude-haiku-5-5 at 4,5 / 22,2 cr/M.

File switch_model.py:

import os
from openai import OpenAI

client = OpenAI(
    base_url="https://carpe-diem.xyz/api/operator/v1",
    api_key=os.environ["OPENAI_API_KEY"],
)

for model in ("llama-3.3-70b", "claude-haiku-5-5"):
    raw = client.chat.completions.with_raw_response.create(
        model=model,
        messages=[{"role": "user", "content": "Reply with the exact word: pong"}],
        max_tokens=16,
    )
    text = raw.parse().choices[0].message.content
    print(model)
    print("  text:", text)
    print("  cost-usdc-micro:", raw.headers.get("x-carpe-cost-usdc-micro"))
    print("  in:", raw.headers.get("x-carpe-input-tokens"), "out:", raw.headers.get("x-carpe-output-tokens"))

Both returned pong. On this second pass, llama-3.3-70b cost 530 micro-USDC for 1695 + 2 tokens, in the same range as the 524 / 1675 of step 4. claude-haiku-5-5 was billed 14 micro-USDC, with 2714 + 4 tokens in the headers. At the catalog rate 4,5 / 22,2 cr/M, those tokens would come to about 123 micro-USDC: the gap is unexplained (we did not read x-carpe-cached-tokens on that call). Trust the header, not the hand calculation.

Ids are copied from /models. llama-3.3-70b-typo was not rewritten to llama-3.3-70b: paste the id from the card.

Step 6: turn on streaming

Keep the chunk.choices check: the SDK guide uses it, and a chunk with no choices would crash on chunk.choices[0].

import os
from openai import OpenAI

client = OpenAI(
    base_url="https://carpe-diem.xyz/api/operator/v1",
    api_key=os.environ["OPENAI_API_KEY"],
)

stream = client.chat.completions.create(
    model="llama-3.3-70b",
    messages=[{"role": "user", "content": "Write a haiku about the sea."}],
    max_tokens=64,
    stream=True,
)

for chunk in stream:
    if chunk.choices and chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="", flush=True)
print()

Text received, token by token:

Crashing waves ascend
Foam kisses the sandy shore
Ocean's gentle song

When streaming, X-Carpe-Cost-Usdc-Micro is not sent (SDK docs). To record cost, stay on the non-streaming call.

If it fails

401 AUTH_REQUIRED. With OPENAI_API_KEY=cdm_invalid, the SDK raised openai.AuthenticationError: Error code: 401 - {'error': 'Unauthorized', 'code': 'AUTH_REQUIRED'}. Incomplete key, bad copy, or the env var not exported in this shell. An export in a terminal does not reach an IDE launched from the dock.

400 MODEL_ERROR. model="llama-3.3-70b-typo" returned: This model is no longer available upstream. Try a newer version of the same model. The message talks about an upstream retirement; here it was a typo. Check the id on /models or via client.models.list().

URL without /v1. See step 2.

Going further

The same base_url with /v1 replaced by /router sends the call to the best-price router: same key, same body. We did not replay hello.py on /router in this run.

For an agent in the terminal rather than a script, we already wired OpenCode: Kimi K3 and Claude Fable in OpenCode.

To try a model without writing hello.py, open Create Hub, then come back and paste the id into model=.

Test run on 22 October 2026 with openai==3.36.0 and a funded test key. The snippets are the ones that ran here.