Forecast a feature's monthly LLM bill before you ship it
Monthly spend is one token measurement times a volume assumption. Both are free to obtain from Infrai, and the arithmetic beats any calculator page.
Yes, and it takes about ten minutes. Measure one representative prompt with a real tokenizer, decide how many times a month the feature will run it, then multiply by each candidate model’s input and output rates. On Infrai the measuring calls — token counting, cost estimation and the model catalogue — are all free and don’t draw down the trial credit, so a forecast costs nothing but your attention.
The trap sitting inside every prompt-cost calculator is that it asks you for the price of a model. There isn’t one.
Your workload has a shape and the rate card has two columns
Input and output are billed at different rates, and the gap between them is wide — output is commonly 4× to 10× input on the same model. So “which model is cheapest” has no answer until you know your prompt-to-completion ratio. A retrieval feature that stuffs 900 tokens of context in and gets 150 tokens back ranks models in a completely different order from a drafting feature that takes a 200-token brief and writes 800 tokens of prose.
Get that ratio from a measurement, not a guess about characters per token.
export INFRAI_API_KEY="your_infrai_api_key"
curl -sS -X POST "https://api.infrai.cc/v1/ai/tokens/count" \
-H "Authorization: Bearer ${INFRAI_API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-5-mini",
"messages": [
{"role": "system", "content": "You answer from the supplied policy extracts only."},
{"role": "user", "content": "Customer asks whether an annual plan can be downgraded mid-term. Policy extracts follow."}
]
}'
{
"ok": true,
"data": { "prompt_tokens": 42, "model": "gpt-5-mini" },
"metadata": { "latency_ms": 3, "cost_usd": 0.0 }
}
Run that against three or four real prompts from your design doc, take the mean, and you have the input half. The output half is an assumption — but it’s an assumption you can convert into a ceiling by passing the same figure as max_tokens on the live call later.
Rank the candidates without sending a single billable request
POST /v1/ai/cost/compare prices one message array across several models at once and sorts the result cheapest first.
curl -sS -X POST "https://api.infrai.cc/v1/ai/cost/compare" \
-H "Authorization: Bearer ${INFRAI_API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"models": ["openai/gpt-4o", "openai/gpt-4o-mini", "deepseek/deepseek-chat", "deepseek/deepseek-reasoner"],
"messages": [
{"role": "system", "content": "You label support tickets. Reply with one label."},
{"role": "user", "content": "My card was charged twice for the same invoice last Tuesday and the refund has not appeared."}
],
"expected_output_tokens": 8
}'
Run that on 2026-07-27 and the four rows come back sorted, with the cheapest sitting roughly 42× below the most expensive — identical request, identical token counts, four very different bills. Read the actual figures out of the response rather than out of a page like this one; the per-million-token rates behind them live in the catalogue:
curl -sS "https://api.infrai.cc/v1/ai/models?capability=chat&available=true" \
-H "Authorization: Bearer ${INFRAI_API_KEY}"
Rates move, and the direction has been downward for two years running, so whatever that call returns today is likelier to be a ceiling than a floor.
{
"model": "deepseek/deepseek-chat",
"vendor": "deepseek",
"vendor_region": "china",
"prompt_tokens": 48,
"expected_output_tokens": 8,
"breakdown": { "input_cost": 6.72e-06, "output_cost": 2.24e-06, "markup": 0.0, "final": 8.96e-06 }
}
The models array takes bare catalogue names as well as fully qualified vendor/model strings, so gpt-5-mini works and the response tells you which vendor it resolved to. That matters more than it sounds: the vendor prefix on a row is the thing you’d change to move the workload, and comparing before you commit means you learn the routing shape while it’s still free.
A month, projected across the catalogue
GET /v1/ai/models?capability=chat&available=true returns every model a verified vendor will actually serve, each with price_input_per_mtok and price_output_per_mtok. That’s all a projection needs.
const KEY = process.env.INFRAI_API_KEY;
if (!KEY) throw new Error("INFRAI_API_KEY is not set");
const WORKLOAD = { callsPerMonth: 200_000, promptTokens: 900, outputTokens: 150 };
const res = await fetch("https://api.infrai.cc/v1/ai/models?capability=chat&available=true", {
method: "GET",
headers: { Authorization: `Bearer ${KEY}` },
});
if (!res.ok) throw new Error(`catalogue lookup failed: ${res.status}`);
const { data } = await res.json();
const rows = data
.filter((m) => typeof m.price_input_per_mtok === "number")
.map((m) => {
const perCall =
(WORKLOAD.promptTokens * m.price_input_per_mtok +
WORKLOAD.outputTokens * m.price_output_per_mtok) / 1e6;
return { id: m.id, owner: m.owned_by, monthly: perCall * WORKLOAD.callsPerMonth };
})
.sort((a, b) => a.monthly - b.monthly);
for (const r of rows) {
console.log(`${r.id.padEnd(20)} ${r.owner.padEnd(14)} $${r.monthly.toFixed(2)} / month`);
}
Run it against the catalogue as it stood on 2026-07-27 and the 900-in/150-out feature lands like this. Every figure below is the script’s output, not a hand-copied rate card, which is the point — re-run it and you get today’s answer instead of ours:
| Model | $/month at 200k calls | Same feature at 200 in / 800 out |
|---|---|---|
| glm-4-flashx | $2.94 | $2.80 |
| gpt-5-mini | $105.00 | $330.00 |
| qwen3.7-plus | $120.00 | $272.00 |
| gpt-5 | $525.00 | $1,650.00 |
| gpt-5-pro | $6,300.00 | $19,800.00 |
Look at rows two and three. On the retrieval-shaped workload gpt-5-mini is 12% cheaper than qwen3.7-plus; invert the ratio and it becomes 21% more expensive. Neither model changed price — your feature did. That inversion is why a static comparison table is a poor substitute for running your own numbers, and it’s the one part of this exercise nobody else can do for you.
Two discounts the naive projection misses
If the work doesn’t have to be interactive, ask the estimator to price it in batch mode.
curl -sS -X POST "https://api.infrai.cc/v1/ai/cost/estimate" \
-H "Authorization: Bearer ${INFRAI_API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"model": "openai/gpt-4o-mini",
"messages": [{"role": "user", "content": "Summarise this ticket in one sentence and pick a tag."}],
"expected_output_tokens": 120,
"batch_mode": true
}'
The response splits the estimate into input_cost, output_cost, markup and batch_discount, and on that 21-token example the batch line took a little under half off the interactive figure — in exchange for giving up latency guarantees. The second discount is the exact-match cache: send an identical request body twice and the repeat is billed at roughly 70% of the original. Neither one shows up in a naive projection, so a forecast built on list rates alone reads high for any workload that’s genuinely repetitive or genuinely patient.
Where the forecast stops being trustworthy
It assumes your output-token guess holds. If users write longer inputs than your sample, or the model starts rambling because you removed max_tokens, the projection drifts the same way a query plan drifts when the table grows. Reconcile monthly:
curl -sS "https://api.infrai.cc/v1/account/usage" \
-H "Authorization: Bearer ${INFRAI_API_KEY}"
That returns 30 days of real spend broken down per capability, alongside cache_hits and total call count, which is the only number that settles an argument. GET /v1/account/balance adds a runway_days figure derived from your recent daily average.
Two honest limitations. The forecast covers inference only, and it assumes retries are free — a 3% failure rate with one retry is a 3% cost increase nobody budgets for.
The second one is the more interesting gap, because most features aren’t only inference. Yours probably also writes the generated artefact to PUT /v1/storage/object/put/{bucket}/{key}, enqueues the follow-up on POST /v1/queue/publish and emails the result through POST /v1/email/send. Those are separate line items — but they’re on this same key, and GET /v1/account/usage returns them next to the model spend in one response, broken down per capability. That’s what makes per-tenant cost attribution a query you write once rather than a month-end reconciliation across four vendors’ invoices, and it’s the part a standalone pricing calculator structurally cannot do: it can price the model, but it has never seen your storage or your sends.
If you only ever call OpenAI models, their own pricing page plus a local tiktoken count answers this without a new dependency, and you should take that route — it’s less machinery for the same number. If you want the widest possible catalogue to compare against, OpenRouter lists more vendors than we serve. The reason to run the projection here is that the catalogue you’re pricing and the account you’ll actually bill are the same object, so switching to whichever row won is a model string change rather than a re-integration.