The activity API gives you daily visibility into your token usage and DA spend. This recipe shows how to query the API, detect spending spikes, and build automated cost controls.
Both endpoints are key-authed inference routes (Authorization: Bearer $OPENDUNES_API_KEY):
| Endpoint | Description |
|---|
GET /api/v1/activity | Daily usage rolled up per model — tokens, requests, DA spend |
GET /api/v1/credits | Lifetime DA totals — deposited and spent |
For request-level logs and CSV/JSON export, use Dashboard → Analytics or the activity export.
curl "https://opendunes.com/api/v1/activity" \
-H "Authorization: Bearer $OPENDUNES_API_KEY"
{
"data": [
{
"date": "2026-06-30",
"model": "anthropic/claude-opus-4.8",
"model_permaslug": "anthropic/claude-opus-4.8",
"endpoint_id": "a223cc6b-19a9-48ac-a297-3210a86073e5",
"provider_name": "anthropic",
"prompt_tokens": 482000,
"completion_tokens": 123000,
"requests": 1245,
"usage": 184.23
}
]
}
usage is the DA spent that day on that model. Pass ?date=YYYY-MM-DD to narrow to a single day.
The rows arrive grouped per day × model, so a per-model breakdown is a small aggregation:
import os, requests
from collections import defaultdict
BASE = "https://opendunes.com"
HEADERS = {"Authorization": f"Bearer {os.environ['OPENDUNES_API_KEY']}"}
rows = requests.get(f"{BASE}/api/v1/activity", headers=HEADERS).json()["data"]
by_model = defaultdict(float)
for r in rows:
by_model[r["model"]] += r["usage"]
for model, da in sorted(by_model.items(), key=lambda x: -x[1]):
print(f"{model}: {da:.2f} DA")
This breakdown tells you which models are driving most of your spend — often the starting point for optimization.
def check_daily_spend(threshold_da: float) -> None:
from datetime import date
resp = requests.get(
f"{BASE}/api/v1/activity",
params={"date": date.today().isoformat()},
headers=HEADERS,
)
resp.raise_for_status()
total = sum(r["usage"] for r in resp.json()["data"])
if total > threshold_da:
send_alert(f"Spend spike: {total:.2f} DA so far today")
def send_alert(message: str) -> None:
print(f"ALERT: {message}")
check_daily_spend(threshold_da=100.0)
curl https://opendunes.com/api/v1/credits \
-H "Authorization: Bearer $OPENDUNES_API_KEY"
{
"data": {
"total_credits": 5000,
"total_usage": 4575
}
}
The remaining balance is total_credits - total_usage (DA). The X-Balance-Available header on every inference response also returns the current balance in micro-DA — useful for inline checks without a separate API call.
def balance_da() -> float:
r = requests.get(f"{BASE}/api/v1/credits", headers=HEADERS)
r.raise_for_status()
data = r.json()["data"]
return data["total_credits"] - data["total_usage"]
LOW_BALANCE_THRESHOLD_DA = 50.0
if balance_da() < LOW_BALANCE_THRESHOLD_DA:
pause_inference_queue()
send_alert(f"Balance below {LOW_BALANCE_THRESHOLD_DA} DA — topping up required.")
- Model downsizing — from the by-model breakdown, identify high-spend models and test whether a cheaper model meets your quality bar on those tasks.
- Prompt compression — long system prompts multiply cost across every request. Trim where possible.
max_tokens caps — set a realistic max_tokens per request type; runaway generations can multiply expected cost by 5–10×.
- Rate-limit tuning — if a batch job is generating thousands of requests in a short window, adding a delay reduces peak spend without affecting throughput.
- Free models for triage — use free models (filter
?free=true in the catalog) for classification and routing decisions that don't require a premium model.