Every request to the OpenDunes API generates a usage record with exact token counts and the DA charge for that call. This recipe shows how to pull that data and turn it into meaningful usage reports.
Usage data is available from two sources:
- Inline in the API response — the
usage object on every completion response.
- The activity API — daily per-model rollups via
GET /api/v1/activity.
Every non-streaming response includes a usage object:
{
"id": "chatcmpl-01j...",
"model": "anthropic/claude-sonnet-5",
"choices": [...],
"usage": {
"prompt_tokens": 342,
"completion_tokens": 187,
"total_tokens": 529
}
}
For streaming responses, the final chunk carries the usage:
async for chunk in stream:
if chunk.usage:
print(f"Prompt: {chunk.usage.prompt_tokens} Completion: {chunk.usage.completion_tokens}")
The response does not include the DA cost directly — compute it from the model's per-token rate in the catalog, or read it from the analytics export after the fact.
def compute_cost_da(
prompt_tokens: int,
completion_tokens: int,
input_rate_da_per_million: float,
output_rate_da_per_million: float,
) -> float:
"""
input_rate_da_per_million and output_rate_da_per_million come from the model catalog.
Returns cost in DA as a float.
"""
input_cost = (prompt_tokens / 1_000_000) * input_rate_da_per_million
output_cost = (completion_tokens / 1_000_000) * output_rate_da_per_million
return input_cost + output_cost
cost = compute_cost_da(
prompt_tokens=342,
completion_tokens=187,
input_rate_da_per_million=150.0,
output_rate_da_per_million=600.0,
)
print(f"{cost:.4f} DA")
If you need per-request cost tracking for billing your own customers, log usage on your side after every call:
import json, uuid
from datetime import datetime, timezone
from openai import OpenAI
client = OpenAI(
base_url="https://opendunes.com/api/v1",
api_key=os.environ["OPENDUNES_API_KEY"],
)
LOG_FILE = "/var/log/opendunes/usage.jsonl"
def tracked_completion(user_id: str, **kwargs) -> object:
resp = client.chat.completions.create(**kwargs)
with open(LOG_FILE, "a") as f:
f.write(json.dumps({
"ts": datetime.now(timezone.utc).isoformat(),
"request_id": resp.id,
"user_id": user_id,
"model": resp.model,
"prompt_tokens": resp.usage.prompt_tokens,
"completion_tokens": resp.usage.completion_tokens,
"total_tokens": resp.usage.total_tokens,
}) + "\n")
return resp
For daily totals without maintaining your own log, GET /api/v1/activity returns the last 30 days rolled up per day and model:
import requests, os
def get_activity(day: str | None = None) -> list[dict]:
r = requests.get(
"https://opendunes.com/api/v1/activity",
params={"date": day} if day else None,
headers={"Authorization": f"Bearer {os.environ['OPENDUNES_API_KEY']}"},
)
r.raise_for_status()
return r.json()["data"]
rows = get_activity()
print(f"Total requests: {sum(r['requests'] for r in rows):,}")
print(f"Total tokens: {sum(r['prompt_tokens'] + r['completion_tokens'] for r in rows):,}")
print(f"Total cost: {sum(r['usage'] for r in rows):.2f} DA")
def usage_report(rows: list[dict]) -> None:
print("=== Usage Report ===")
print(f" Requests: {sum(r['requests'] for r in rows):,}")
print(f" Prompt tokens: {sum(r['prompt_tokens'] for r in rows):,}")
print(f" Completion tokens: {sum(r['completion_tokens'] for r in rows):,}")
print(f" Total cost: {sum(r['usage'] for r in rows):.2f} DA")
usage_report(get_activity())
OpenDunes bills in micro-DA: 1 DA = 1,000,000 micro-DA. Each request is charged the exact micro-DA cost, rounded up to the nearest micro-DA. This means very cheap requests (e.g., a 10-token call on a cheap model) may have a minimum charge of 1 micro-DA = 0.000001 DA.
When reconciling your own computed cost against exported figures, prefer the export's total_cost column (an integer in micro-DA) over any float — integer micro-DA has no rounding drift.
See User Tracking for how to attribute usage and DA spend to individual end-users with per-app API keys and per-key analytics.