AI SaaS Unit Economics: Calculate Cost per Usable Output
Calculate quality-adjusted unit cost with Decimal, controlled ledger fixtures and real usage counts. Rates are explicitly illustrative, with no actual billing claim.

Measure AI unit economics per usable result, including failed-quality attempts that consumed tokens. Dividing only by successful HTTP requests can make a workflow look cheaper than it is. Keep arithmetic, output quality and actual billing reconciliation as separate checks.
Crazyrouter is the API used in this ledger example: one completed request supplied real token counts, while a controlled three-attempt fixture showed that two usable results cost more per result than the per-attempt estimate. The rates used below are illustrative currency units, not Crazyrouter or provider prices.
By Sophie M · Tested November 3, 2026
How do I calculate cost per usable AI output?#
Add the modeled cost of all attempts in the evaluation window, then divide by the number of results accepted by the task's quality rule. If no result is usable, report that no finite unit cost was observed rather than dividing by zero or returning a reassuring zero.
For a simplified text-only fixture, modeled cost is input tokens times an input rate plus output tokens times an output rate. Real billing can contain cache categories, reasoning, media, tiers, tool charges and adjustments. This article deliberately tests the simple arithmetic without pretending it is a complete invoice calculator.
A controlled ledger and one real usage receipt#
On November 3, 2026, Python 3.10.2 used Decimal arithmetic with illustrative rates of 1 currency unit per million input tokens and 2 per million output tokens. Those numbers are test parameters, not a tariff.
The local ledger contained three attempts, each with 1,000 input and 100 output tokens. Two outputs were marked usable; one was not. The live request used gpt-4.1-mini through /v1/chat/completions at https://api.crazyrouter.com, with COST-1406 as the required exact answer.
| Observation | Result |
|---|---|
| Controlled attempts / usable results | 3 / 2 |
| Illustrative modeled total | 0.0036 units |
| Illustrative cost per usable result | 0.0018 units |
| Live prompt / completion tokens | 13 / 5 |
| Local arithmetic fixtures | 4 passed |
| Actual bill queried | No |
Observed response IDs (successful responses only):
chatcmpl-Eg6ApocuzMnUh6RWtRejnEjftN1TK

The synthetic ledger's total was 0.0036 illustrative units. Dividing by three attempts gives 0.0012 per attempt, but dividing by two usable results gives 0.0018 per usable result—a 50% increase in this constructed example. This is arithmetic, not an observed production failure rate.
Run the calculation and usage probe#
Install requests, set CRAZYROUTER_API_KEY in the process environment, save this as unit_cost_probe.py, and run it. The Python Decimal documentation explains decimal arithmetic. The example constructs rates from strings instead of introducing binary floating-point rounding into the rate values.
"""Measure quality-adjusted unit cost with explicitly illustrative input rates."""
from decimal import Decimal
import json
import os
import requests
def unit_cost(attempts,input_rate,output_rate):
# Rates are illustrative currency units per million tokens, not a live tariff.
total=Decimal('0');usable=0
for r in attempts:
if type(r['input_tokens']) is not int or type(r['output_tokens']) is not int or min(r['input_tokens'],r['output_tokens'])<0:raise ValueError('invalid token counts')
total+=(Decimal(r['input_tokens'])*input_rate+Decimal(r['output_tokens'])*output_rate)/Decimal(1000000)
usable+=bool(r['usable'])
return {'attempts':len(attempts),'usable':usable,'estimated_total':str(total),'per_usable':str(total/usable) if usable else None}
def main():
ir=Decimal('1');orr=Decimal('2')
fixture=[{'input_tokens':1000,'output_tokens':100,'usable':True},{'input_tokens':1000,'output_tokens':100,'usable':False},{'input_tokens':1000,'output_tokens':100,'usable':True}]
calculated=unit_cost(fixture,ir,orr)
assert Decimal(calculated['estimated_total'])==Decimal('0.0036') and Decimal(calculated['per_usable'])==Decimal('0.0018')
tests=[{'case':'three attempts / two usable','passed':True}]
assert unit_cost([],ir,orr)['per_usable'] is None;tests.append({'case':'empty input has no unit cost','passed':True})
assert unit_cost([dict(fixture[0],usable=False)],ir,orr)['per_usable'] is None;tests.append({'case':'zero usable has no unit cost','passed':True})
try:unit_cost([dict(fixture[0],input_tokens=-1)],ir,orr)
except ValueError:tests.append({'case':'negative usage rejected','passed':True})
else:raise AssertionError('negative usage accepted')
endpoint='https://api.crazyrouter.com/v1/chat/completions';model='gpt-4.1-mini'
s=requests.Session();s.trust_env=False
response=s.post(endpoint,headers={'Authorization':'Bearer '+os.environ['CRAZYROUTER_API_KEY']},json={'model':model,'max_tokens':32,'messages':[{'role':'user','content':'Reply only COST-1406'}]},timeout=60)
response.raise_for_status();data=response.json();c=data['choices'][0];usage=data['usage']
usable=c['finish_reason']=='stop' and c['message']['content'].strip()=='COST-1406'
assert usable
live_estimate=unit_cost([{'input_tokens':usage['prompt_tokens'],'output_tokens':usage['completion_tokens'],'usable':usable}],ir,orr)
print(json.dumps({'endpoint':endpoint,'model':model,'response_id':data['id'],'output':c['message']['content'],'usage':usage,'local_tests':tests,'illustrative_rates':{'input_per_million':str(ir),'output_per_million':str(orr)},'fixture':calculated,'live_tokens_at_illustrative_rates':live_estimate,'billing_claim':False}))
if __name__=='__main__':main()
The live response reported 13 prompt tokens and 5 completion tokens. At the deliberately illustrative rates, the function calculates 0.000023 units. This is not the amount charged for that request. No billing transaction was queried or reconciled.
Keep denominators and unknown costs visible#
| Record | Include in token-based modeled cost? | Count as usable? |
|---|---|---|
| Validated successful answer | Yes | Yes |
| Completed answer that fails quality | Yes, when usage is available | No |
| Retry that consumed tokens | Include each attempt separately | Only accepted final work counts |
| Timeout without known usage | Mark cost unknown pending reconciliation | No completed result established |
| Crazyrouter live fixture | Real usage with illustrative rates | Yes, exact marker validated |

Do not enter zero token cost for a timeout merely because no usage response arrived. The server may have processed work before the response was lost. Use your billing records and per-attempt telemetry to reconcile uncertain attempts.
The small function tests a provided list; it is not a durable, multi-tenant billing ledger. It does not deduplicate records or choose which business result counts once. A real implementation needs stable attempt and task IDs, rate versioning, currency policy and explicit rounding rules. Decimal helps arithmetic precision but does not solve accounting completeness.
Reduce work without hiding quality failures#
Start with a representative task set and define acceptance before comparing routes. Use structured-output validation when shape is part of the contract, but remember that valid JSON can still contain wrong facts.
Use admission control to limit simultaneous work and a bounded retry policy to keep attempts visible. If you use fallback models, measure their accepted outputs independently. An application cache may remove a generation, while prompt caching changes input processing; those require different counters.
FAQ#
Are the rates in this article real model prices?#
No. They are explicitly illustrative test inputs of 1 and 2 currency units per million tokens.
Why does a failed-quality answer still count toward cost?#
It may have consumed billed resources even though it did not solve the task. Keep its attempt and known usage in the ledger.
What happens when there are no usable results?#
The function returns null for per-usable cost. It does not divide by zero or claim a zero cost per result.
Can I count an unknown timeout as zero usage?#
No. Record usage or cost as unknown until you can reconcile it.
Does Decimal make this production billing software?#
No. It addresses arithmetic representation, not missing records, rate categories, deduplication or settlement.
Did this prove one model is cheaper than another?#
No. The test validates the calculation and one usage receipt; it does not compare real tariffs or representative quality.
Implementation Guides
Podcast
AI Dev Tools: The Crazyrouter Podcast
Short episodes for developers on AI APIs, gateways, cost control and coding tools.
Latest episodes
EP196 · Oct 29, 2026 · 6:53
AI API Security Posture — Turn Controls Into Continuous Evidence
A practical guide to AI API security posture: inventory exposure, verify controls continuously, protect keys and data, constrain tools, and turn security assumptions into evidence that operators can act on.
EP195 · Oct 28, 2026 · 7:21
AI API Policy Drift — Detect When Production Rules Stop Matching Intent
A practical guide to policy drift in AI APIs: version routing and safety rules, detect stale enforcement, compare intended and observed behavior, and restore control before small gaps become incidents.
Available in other languages:





