AI cost attribution
One invoice, decomposed into causes
A blended AI bill is a number nobody owns. Label each request with the app, the customer and the run that caused it, and the same spend comes back split along all three - so you can price a feature, charge a customer, or find the one workload that doubled last week.
- Four labels - app, end customer, session and tags - carried on the request and kept on the record
- Cost lands on the response itself in cents, so your own logs can reproduce every figure in our analytics
- Breakdowns are computed in the database over the whole window, never sampled - and the filtered view exports to CSV
POST /v1/chat/completions
X-Title: checkout-assistant // which app
X-Session-Id: run_8f21c // which run, with its own caps
{
"model": "auto",
"user": "acct_10023", // which of YOUR customers
"tags": ["tier:pro", "feature:summarise"],
"messages": [ ... ]
}"final_router": {
"cost_cents": 0.84,
"reason": "Chose claude-haiku-4-5 - lowest latency among healthy models."
}
// Four labels on the way in, one cost on the way out.
// Analytics then splits that cost by app, customer,
// session and model — computed over everything, not
// sampled from the first thousand rows.What is AI cost attribution?
Cost attribution is the difference between knowing what you spent and knowing why. Provider invoices answer the first: one number per provider per month. The questions that actually come up - is this feature profitable, which customer is unprofitable, what changed on Tuesday - need the second, and no provider can answer them because the provider never knew which of your customers made the call.
The gateway does know, because you told it. Four optional labels ride along with each request, cost is computed per request at list price, and the two are stored together - so the month's spend decomposes along whichever axis you need to defend a number.
The four labels, and what each answers
All optional, all cheap to send, and each one turns a blended figure into an answerable question.
App - which product spent it
Send X-Title and every request is attributed to a named app. Analytics then shows cost, tokens and failures per app, which is the split most teams want before they want any other.
X-Title: checkout-assistant
Customer - who to charge
The user field names your own end customer. Cost per customer is the number behind usage-based pricing, and behind noticing that your heaviest account is your least profitable one.
body: { "user": "acct_10023" }
Session - which run
X-Session-Id groups an agent run into one story: every step, the total it cost, and where it went wrong. Sessions also carry their own spend and request ceilings, so a loop stops itself.
grouping and enforcement from one header
Tags - your own axis
Up to ten short tags per request for whatever your business actually splits on - a plan tier, a feature flag, an experiment arm. They are stored on the record and travel into the export.
10 tags, 40 characters each
AI cost attribution
Best practices - the order that works
- 01
Send X-Title from day one
It costs one header and it is the label you will miss most when a bill doubles. Unlabelled traffic cannot be attributed retroactively - the request is already gone.
- 02
Use the customer field even before you bill for usage
You do not need usage pricing to benefit from knowing which account costs what. You need it the first time someone asks whether the enterprise tier pays for itself.
- 03
Tag anything agentic with a session id
It is the only label that is also a control: a session carries spend and request ceilings, so labelling a run also bounds it.
- 04
Keep tags low-cardinality
A tag per plan tier is useful; a tag per request id is noise you will pay to store and never group by. If it is unique per call, it belongs in the customer field or nowhere.
- 05
Reconcile once, then trust the number
Export a month to CSV and check our cost figure against the provider invoice. Once they agree, stop doing it - the arithmetic is the same code that bills you.
Attributed at the gateway vs reconstructed later
| Final Router | Provider invoices | |
|---|---|---|
| Cost per request | On the response, in cents, at request time | Derived from token counts afterwards |
| Per customer | A field on the request | The provider never knew your customers |
| Per app or feature | A header on the request | One number per provider |
| Per agent run | Sessions, which also carry spend ceilings | Not represented at all |
| Getting it into a spreadsheet | CSV of exactly the filtered view | PDF invoices, one per provider |
| Totals vs samples | Aggregated in the database over the whole window | Whatever the dashboard sampled |
FAQ
Do I have to label everything?
No - every label is optional and unlabelled traffic still bills, logs and appears in totals. But attribution is only ever forward-looking: a request that arrived without a label cannot be attributed later, so the cheap move is to send X-Title from the first day and add the others when a question makes you want them.
Are the breakdowns totals or samples?
Totals. Every breakdown is aggregated in the database over the whole window you selected - by app, by end customer, by session, by model and by error reason. Nothing is computed from the first page of rows, which is the usual way a dashboard quietly lies about a long tail.
Can I get the raw rows out?
Yes. The log exports to CSV, and it exports exactly what the screen is showing - the same filters, read from the same query string - so an export can never contain more or fewer rows than the view you were looking at. It exists for reconciling against a provider invoice and for charging a customer their share.
Does labelling cost anything or slow requests down?
No. The labels are headers and two body fields; they are stored alongside the usage record that gets written anyway. There is no extra call and no extra charge.
Does this store my prompts?
No. Attribution is metadata - which app, which customer, what it cost, how it behaved. Prompt and completion text is only stored if you separately switch that on, and even then it is kept for a window you choose, up to thirty days.
Turn one number into an answer
Add X-Title to your next request and the following month's spend arrives already split by the thing that caused it.
Related: LLM observability, AI spend management, smart LLM routing, pricing.