Documentation
Everything you need to route OpenAI, Claude, Groq, DeepSeek, or Llama API traffic through CostTrim. Every snippet below is pre-filled with your host — just swap in your key:
https://aicosttrim.comYour CostTrim host — already filled in below. Don't have an account yet? Sign up free.
YOUR_API_KEYA key from Dashboard → API Keys — this is your CostTrim key, not your OpenAI/Anthropic key (that goes in the Authorization header instead).
Quickstart
- Create a workspace (free, no card required).
- Generate a key in Dashboard → API Keys.
- Pick a path below: OpenAI, Claude, our SDK, the CLI, or the no-code widget.
- Send one request, then check Dashboard → Prompt Logs — it shows up within seconds.
OpenAI
Two options: call our proxy directly, or point the official openai package's baseURL at us and change nothing else in your code.
Option A — direct proxy call
curl -X POST https://aicosttrim.com/api/v1/monitor \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "X-API-KEY: YOUR_API_KEY" \
-d '{
"model": "gpt-4o-mini",
"messages": [{"role": "user", "content": "Hello!"}],
"metadata": { "userId": "usr_123" }
}'import os, requests
response = requests.post(
"https://aicosttrim.com/api/v1/monitor",
headers={
"Authorization": f"Bearer {os.environ['OPENAI_API_KEY']}",
"X-API-KEY": "YOUR_API_KEY",
},
json={
"model": "gpt-4o-mini",
"messages": [{"role": "user", "content": "Hello!"}],
"metadata": {"userId": "usr_123"},
},
)
print(response.json()["choices"][0]["message"]["content"])const res = await fetch("https://aicosttrim.com/api/v1/monitor", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${process.env.OPENAI_API_KEY}`,
"X-API-KEY": "YOUR_API_KEY",
},
body: JSON.stringify({
model: "gpt-4o-mini",
messages: [{ role: "user", content: "Hello!" }],
metadata: { userId: "usr_123" },
}),
});
const data = await res.json();Option B — zero code changes
Keep using the official SDK exactly as-is, just repoint it:
import OpenAI from "openai";
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
baseURL: "https://aicosttrim.com/api/openai/v1",
defaultHeaders: { "X-API-KEY": "YOUR_API_KEY" },
});
// unchanged everywhere else in your code
const completion = await openai.chat.completions.create({
model: "gpt-4o-mini",
messages: [{ role: "user", content: "Hello!" }],
});Claude (Anthropic)
Same two options as OpenAI. One header difference — read the note below the snippets.
Option A — direct proxy call
curl -X POST https://aicosttrim.com/api/v1/monitor \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ANTHROPIC_API_KEY" \
-H "X-API-KEY: YOUR_API_KEY" \
-d '{
"model": "claude-opus-5",
"max_tokens": 1024,
"messages": [{"role": "user", "content": "Hello!"}],
"metadata": { "userId": "usr_123" }
}'import os, requests
response = requests.post(
"https://aicosttrim.com/api/v1/monitor",
headers={
"Authorization": f"Bearer {os.environ['ANTHROPIC_API_KEY']}",
"X-API-KEY": "YOUR_API_KEY",
},
json={
"model": "claude-opus-5",
"max_tokens": 1024,
"messages": [{"role": "user", "content": "Hello!"}],
"metadata": {"userId": "usr_123"},
},
)
print(response.json()["content"][0]["text"])const res = await fetch("https://aicosttrim.com/api/v1/monitor", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${process.env.ANTHROPIC_API_KEY}`,
"X-API-KEY": "YOUR_API_KEY",
},
body: JSON.stringify({
model: "claude-opus-5",
max_tokens: 1024,
messages: [{ role: "user", content: "Hello!" }],
metadata: { userId: "usr_123" },
}),
});
const data = await res.json();Option B — zero code changes
import Anthropic from "@anthropic-ai/sdk";
const anthropic = new Anthropic({
apiKey: process.env.ANTHROPIC_API_KEY,
baseURL: "https://aicosttrim.com/api/anthropic",
defaultHeaders: { "X-CostTrim-Key": "YOUR_API_KEY" },
});
// unchanged everywhere else in your code
const message = await anthropic.messages.create({
model: "claude-opus-5",
max_tokens: 1024,
messages: [{ role: "user", content: "Hello!" }],
});Note: Option B for Claude uses X-CostTrim-Key, not X-API-KEY. The Anthropic SDK already sends your provider key via a header literally named x-api-key, so your CostTrim key needs a different header there to avoid colliding with it. Every other path (Option A, and OpenAI's Option B) uses X-API-KEY as normal.
Groq
Groq hosts open-weight models (Llama, Mixtral, Gemma, DeepSeek-distilled) at very low latency and cost. Point the official openai package's baseURL at our dedicated Groq route — it needs its own route (rather than the auto-detecting /api/v1/monitor) because Groq reuses other vendors' model names.
import OpenAI from "openai";
const groq = new OpenAI({
apiKey: process.env.GROQ_API_KEY,
baseURL: "https://aicosttrim.com/api/groq/v1",
defaultHeaders: { "X-API-KEY": "YOUR_API_KEY" },
});
const completion = await groq.chat.completions.create({
model: "llama-3.3-70b-versatile",
messages: [{ role: "user", content: "Hello!" }],
});curl -X POST https://aicosttrim.com/api/groq/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $GROQ_API_KEY" \
-H "X-API-KEY: YOUR_API_KEY" \
-d '{
"model": "llama-3.3-70b-versatile",
"messages": [{"role": "user", "content": "Hello!"}]
}'DeepSeek
DeepSeek's own API speaks the same format as OpenAI. Its model names (deepseek-chat, deepseek-reasoner) don't collide with anything else, so unlike Groq/Llama below, these also work on the auto-detecting /api/v1/monitor endpoint — a dedicated route is available too if you prefer repointing an existing SDK client.
import OpenAI from "openai";
const deepseek = new OpenAI({
apiKey: process.env.DEEPSEEK_API_KEY,
baseURL: "https://aicosttrim.com/api/deepseek/v1",
defaultHeaders: { "X-API-KEY": "YOUR_API_KEY" },
});
const completion = await deepseek.chat.completions.create({
model: "deepseek-chat",
messages: [{ role: "user", content: "Hello!" }],
});curl -X POST https://aicosttrim.com/api/deepseek/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $DEEPSEEK_API_KEY" \
-H "X-API-KEY: YOUR_API_KEY" \
-d '{
"model": "deepseek-chat",
"messages": [{"role": "user", "content": "Hello!"}]
}'Llama API
Meta's own hosted Llama API (api.llama.com), also OpenAI-compatible. Needs its own route — Groq serves Llama models too, under different pricing, so model names alone can't tell them apart.
import OpenAI from "openai";
const llama = new OpenAI({
apiKey: process.env.LLAMA_API_KEY,
baseURL: "https://aicosttrim.com/api/llama/v1",
defaultHeaders: { "X-API-KEY": "YOUR_API_KEY" },
});
const completion = await llama.chat.completions.create({
model: "Llama-3.3-70B-Instruct",
messages: [{ role: "user", content: "Hello!" }],
});curl -X POST https://aicosttrim.com/api/llama/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $LLAMA_API_KEY" \
-H "X-API-KEY: YOUR_API_KEY" \
-d '{
"model": "Llama-3.3-70B-Instruct",
"messages": [{"role": "user", "content": "Hello!"}]
}'Claude Code CLI
Track and hard-cap what Claude Code spends on your Anthropic account — per day, workspace-wide — without changing how you use it. Set three environment variables (or the equivalent in ~/.claude/settings.json) and every Claude Code session routes through CostTrim automatically.
export ANTHROPIC_BASE_URL="https://aicosttrim.com/api/anthropic" export ANTHROPIC_API_KEY="sk-ant-..." # your real Anthropic key — never stored, forwarded per-request export ANTHROPIC_CUSTOM_HEADERS="X-CostTrim-Key: YOUR_API_KEY"
Or in ~/.claude/settings.json:
{
"env": {
"ANTHROPIC_BASE_URL": "https://aicosttrim.com/api/anthropic",
"ANTHROPIC_API_KEY": "sk-ant-...",
"ANTHROPIC_CUSTOM_HEADERS": "X-CostTrim-Key: YOUR_API_KEY"
}
}That's it — run claude as normal. Dashboard → Prompt Logs shows every session tagged claude-code, grouped by session in Traces.
Daily budget kill-switch
Set a daily $ cap in Dashboard → Settings → Claude Code CLI budget protection. Once today's Claude Code spend hits it, further requests are rejected instantly — before Anthropic is ever called — with a clean, Claude-Code-compliant error your session will surface immediately:
{
"type": "error",
"error": {
"type": "rate_limit_error",
"message": "CostTrim: Claude Code budget threshold exceeded for today. Session halted to protect your credit card."
}
}This is separate from the per-user monthly threshold used elsewhere — Claude Code sessions are bursty and workspace-wide, not attributed to one end-user, so it gets its own daily, workspace-level cap. Resets at midnight.
Node SDK — ai-metric-sdk
A thin client mirroring both official SDKs, for either provider from one import:
import { createAIMetricClient } from "ai-metric-sdk";
const ai = createAIMetricClient({
apiKey: "YOUR_API_KEY",
openaiApiKey: process.env.OPENAI_API_KEY,
anthropicApiKey: process.env.ANTHROPIC_API_KEY,
baseUrl: "https://aicosttrim.com",
});
await ai.chat.completions.create({
model: "gpt-4o-mini",
messages: [{ role: "user", content: "Hello!" }],
userId: "usr_123",
sessionId: "task_9f2a", // optional — groups multi-step calls in Traces
});
await ai.messages.create({
model: "claude-opus-5",
max_tokens: 1024,
messages: [{ role: "user", content: "Hello!" }],
userId: "usr_123",
});See the package README for error handling, framework examples, and full API reference.
CLI — automatic migration
Already have new OpenAI(...) or new Anthropic(...) somewhere in your codebase? Have it wired up automatically:
npx ai-metric init --base-url https://aicosttrim.com
Dry-run by default — shows exactly what it would change before writing anything. Finds every client constructor and injects baseURL/defaultHeaders, skipping anything it isn't confident about rather than guessing.
No code at all
Don't want to touch code? Dashboard → Chat Widget lets you paste your provider key into a form and get back an embeddable chat box — one <iframe> tag, nothing else.
Python — FastAPI
Configure the OpenAI (or Anthropic) client once, at startup, and inject it wherever you need it — same pattern as any other FastAPI dependency.
import os
from openai import OpenAI
def get_ai_client() -> OpenAI:
return OpenAI(
api_key=os.environ["OPENAI_API_KEY"],
base_url="https://aicosttrim.com/api/openai/v1",
default_headers={"X-API-KEY": os.environ["AI_METRIC_API_KEY"]},
)from fastapi import APIRouter, Depends
from openai import OpenAI
from app.dependencies import get_ai_client
router = APIRouter()
@router.post("/chat")
def chat(message: str, user_id: str, ai: OpenAI = Depends(get_ai_client)):
completion = ai.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": message}],
user=user_id, # shows up as the attributed user in CostTrim
)
return {"reply": completion.choices[0].message.content}Python — Django
Point the client at CostTrim once in settings.py, reuse it from any view.
import os
AI_METRIC_CLIENT_CONFIG = {
"api_key": os.environ["OPENAI_API_KEY"],
"base_url": "https://aicosttrim.com/api/openai/v1",
"default_headers": {"X-API-KEY": os.environ["AI_METRIC_API_KEY"]},
}from django.conf import settings
from django.http import JsonResponse
from openai import OpenAI
client = OpenAI(**settings.AI_METRIC_CLIENT_CONFIG)
def chat_view(request):
message = request.POST["message"]
completion = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": message}],
user=str(request.user.id),
)
return JsonResponse({"reply": completion.choices[0].message.content})Telegram bot — python-telegram-bot
Every Telegram user's numeric ID becomes the attributed userId in CostTrim, so you get per-Telegram-user cost breakdown for free.
import os
from telegram import Update
from telegram.ext import Application, MessageHandler, ContextTypes, filters
from openai import OpenAI
ai = OpenAI(
api_key=os.environ["OPENAI_API_KEY"],
base_url="https://aicosttrim.com/api/openai/v1",
default_headers={"X-API-KEY": os.environ["AI_METRIC_API_KEY"]},
)
async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE):
completion = ai.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": update.message.text}],
user=f"tg_{update.effective_user.id}",
)
await update.message.reply_text(completion.choices[0].message.content)
app = Application.builder().token(os.environ["TELEGRAM_BOT_TOKEN"]).build()
app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, handle_message))
app.run_polling()Telegram bot — Telegraf
import { Telegraf } from "telegraf";
import OpenAI from "openai";
const ai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
baseURL: "https://aicosttrim.com/api/openai/v1",
defaultHeaders: { "X-API-KEY": process.env.AI_METRIC_API_KEY },
});
const bot = new Telegraf(process.env.TELEGRAM_BOT_TOKEN);
bot.on("text", async (ctx) => {
const completion = await ai.chat.completions.create({
model: "gpt-4o-mini",
messages: [{ role: "user", content: ctx.message.text }],
user: `tg_${ctx.from.id}`,
});
await ctx.reply(completion.choices[0].message.content);
});
bot.launch();