Skip to Content
GuidesCost Attribution

Cost Attribution

Tag gateway requests with custom labels to track LLM spend by project, team, environment, agent, or any dimension your organization needs. Attribution data flows into the dashboard for visualization and the API for programmatic access.

Adding Tags to Requests

Include the X-CM-Tags header on any gateway request. Tags are comma-separated key=value pairs:

curl https://api.curate-me.ai/v1/openai/chat/completions \ -H "X-CM-API-Key: cm_sk_xxx" \ -H "X-Provider-Key: sk-your-key" \ -H "X-CM-Tags: project=chatbot,team=platform,env=production" \ -H "Content-Type: application/json" \ -d '{"model": "gpt-4o", "messages": [{"role": "user", "content": "Hello"}]}'

Python

from openai import OpenAI client = OpenAI( base_url="https://api.curate-me.ai/v1/openai", api_key="sk-your-key", default_headers={ "X-CM-API-Key": "cm_sk_xxx", "X-CM-Tags": "project=chatbot,team=platform,env=production", }, )

TypeScript

import OpenAI from "openai"; const client = new OpenAI({ baseURL: "https://api.curate-me.ai/v1/openai", apiKey: "sk-your-key", defaultHeaders: { "X-CM-API-Key": "cm_sk_xxx", "X-CM-Tags": "project=chatbot,team=platform,env=production", }, });

Per-Request Tags

Override default tags on individual requests when you need per-call attribution:

response = client.chat.completions.create( model="gpt-4o", messages=[{"role": "user", "content": "..."}], extra_headers={ "X-CM-Tags": "project=chatbot,feature=onboarding,user_tier=premium", }, )

Built-In Attribution Dimensions

The gateway automatically records these dimensions for every request (no tags needed):

DimensionSourceExample
ModelRequest bodygpt-4o, claude-sonnet-4-5
ProviderRoutingopenai, anthropic, google
API KeyX-CM-API-Key headercm_sk_abc123
OrganizationKey -> org mappingorg_xyz

Custom tags via X-CM-Tags add additional dimensions on top of these.

Hierarchical Budgets

The gateway enforces a three-level budget hierarchy. Each level can have its own daily and monthly limits:

Organization ($500/day) └── Team: Platform ($200/day) │ └── Key: cm_sk_platform_prod ($100/day) │ └── Key: cm_sk_platform_staging ($50/day) └── Team: ML ($300/day) └── Key: cm_sk_ml_prod ($200/day)

When a request arrives, the gateway checks budgets at all three levels. If any level is over budget, the request is blocked with 403.

Configure hierarchical budgets via the dashboard or the budget-node API. Each budget node has a level (org, team, or key), an optional parent_id linking it to the node above it, and a budget_limit that resets on the chosen reset_period (daily, weekly, or monthly).

# Create a team budget node (parent_id links it to the org node) curl -X POST https://api.curate-me.ai/gateway/admin/budgets/nodes \ -H "X-CM-API-Key: cm_sk_xxx" \ -H "Content-Type: application/json" \ -d '{ "name": "Platform", "level": "team", "parent_id": "bgt_org_node_id", "team_id": "platform", "budget_limit": 200.0, "reset_period": "daily" }' # Create a key budget node under the team node curl -X POST https://api.curate-me.ai/gateway/admin/budgets/nodes \ -H "X-CM-API-Key: cm_sk_xxx" \ -H "Content-Type: application/json" \ -d '{ "name": "Platform Prod", "level": "key", "parent_id": "bgt_team_node_id", "key_id": "cm_sk_platform_prod", "budget_limit": 100.0, "reset_period": "daily" }' # Update an existing node (e.g. raise its limit) curl -X PATCH https://api.curate-me.ai/gateway/admin/budgets/nodes/bgt_team_node_id \ -H "X-CM-API-Key: cm_sk_xxx" \ -H "Content-Type: application/json" \ -d '{"budget_limit": 250.0}'

List nodes with GET /gateway/admin/budgets/nodes and view live spend across the whole hierarchy with GET /gateway/admin/budgets/status.

Querying Cost Attribution

By Model

curl "https://api.curate-me.ai/gateway/admin/costs/by-model?days=7" \ -H "X-CM-API-Key: cm_sk_xxx"
[ {"dimension": "gpt-4o", "cost": 45.23, "request_count": 1200, "avg_cost": 0.038}, {"dimension": "gpt-4o-mini", "cost": 3.10, "request_count": 8500, "avg_cost": 0.0004}, {"dimension": "claude-sonnet-4-5", "cost": 28.50, "request_count": 600, "avg_cost": 0.048} ]

By Provider

curl "https://api.curate-me.ai/gateway/admin/costs/by-provider?days=7" \ -H "X-CM-API-Key: cm_sk_xxx"

By Custom Tags

curl "https://api.curate-me.ai/gateway/admin/costs/by-tag?tag_key=project&days=7" \ -H "X-CM-API-Key: cm_sk_xxx"
[ {"dimension": "chatbot", "cost": 52.30, "request_count": 5000}, {"dimension": "search", "cost": 18.40, "request_count": 3200}, {"dimension": "agents-demo", "cost": 2.10, "request_count": 150} ]

Python SDK

from curate_me import CurateGateway gw = CurateGateway(api_key="cm_sk_xxx") admin = gw.admin() # Daily cost breakdown (async) costs = await admin.get_daily_costs(days=7)

TypeScript SDK

import { CurateMe } from "@curate-me/sdk"; const client = new CurateMe({ apiKey: "cm_sk_xxx" }); const costs = await client.costs.getTimeSeries({ startDate: "2026-03-19", endDate: "2026-03-26", granularity: "day", });

Dashboard Views

The cost attribution dashboard shows:

  • By Model — which models are driving spend
  • By Provider — cost breakdown across OpenAI, Anthropic, Google, etc.
  • By Tag — custom attribution dimensions (project, team, env)
  • By API Key — which keys are consuming the most budget
  • Time Series — cost trends over time with drill-down

Tag Best Practices

TagPurposeExample
projectWhich product or featureproject=chatbot
teamWhich team owns the costteam=platform
envDevelopment stageenv=production
agentWhich agent in a multi-agent systemagent=triage
featureSpecific feature within a projectfeature=onboarding
user_tierCustomer tier for unit economicsuser_tier=premium

Keep tag cardinality manageable — avoid per-user or per-request unique values as tag values.

Next Steps