What an answer costs, and how the ceilings behave

How AI Support spend is measured across both turn tables, what the daily and monthly ceilings do when they are reached, what happens when a call cannot be priced at all, and which settings drive the bill.

15 min readUpdated 7 August 2026cost, budget, spend, prompt-cache, overview

Every figure on this page comes from one screen and two tables: the Overview dashboard at /admin/ai/support, and the ai_support_turn and ai_support_admin_turn rows behind it. The first records what the assistant spent answering your customers. The second records what your own administrators spent asking it questions. Both count against the same ceilings.

Everything the dashboard shows — spend, budget, cache health, outcomes and readiness.

The page itself opens on access.ai.support, but every number on it comes from that route. A role with the page key and not the analytics key gets an empty dashboard and no explanation — see Permissions.

What Overview reports

Block What it says
Status line One sentence: off, no provider, paused, drafting, or answering
Spent today Today's cost, both surfaces, above a count of customer turns
Spent this month The month's cost, both surfaces, above the average per customer answer
Handled without a person Conversations the assistant closed with no human, of those it touched
Prompt cache Share of input tokens served from cache — read this one, see below
Budget Today and this month against their ceilings, or "no cap"
Cached tokens / Fresh tokens Today's split. Cached cost a tenth of fresh
What it did (30 days) Answered, handed to a person, stayed silent, and failed when there are any
Ready to answer unsupervised? Drafts reviewed, sent as written, average rewrite, against the promotion gate. Only while you are in COPILOT

The masthead rail above them carries the live state — which provider is answering, whether the budget still allows a call, and whether the cache has gone bad.

Every dollar figure on this screen — the two spend tiles and the two budget bars — includes what your own administrators spent: the console, the handbook, "ask about this customer", "teach from this ticket" and the provider connection test. They are all built from the same sum, so the tile and the bar can no longer disagree.

The counts underneath them are customer conversations only. That split is deliberate: folding an operator's own questions into "turns today" would inflate the one number the whole feature is judged on. It does mean spend ÷ turns is not a per-answer cost on a desk that uses the operator assistant — which is why the average per answer on the month tile divides customer cost by customer turns rather than doing that division for you.

How the two windows are measured

Both periods are UTC, with explicit UTC boundaries: the day runs from 00:00 UTC, and the month from the 1st at 00:00 UTC. That is deliberate — a window derived from the server's local timezone resets at a different instant on every install, and the admin screen then disagrees with the ledger for a few hours every month.

Spend for a window is one SQL sum over both surfaces:

SELECT COALESCE(SUM(costUsd), 0)
  FROM (
        SELECT costUsd FROM ai_support_turn
         WHERE createdAt >= :windowStart AND costUsd > 0
        UNION ALL
        SELECT costUsd FROM ai_support_admin_turn
         WHERE createdAt >= :windowStart AND costUsd > 0
       ) AS spend

There is no status filter. A row carrying a cost is a row somebody was charged for, whatever happened to it afterwards — and that is the whole rule, so a status added later needs no maintenance here.

The model was called and the tokens were billed before anything downstream got to decide the answer was not worth sending. That covers three cases people expect to be free and are not:

  • Refused. The groundedness gate withheld a generated answer.
  • Failed. The provider errored after it had already produced tokens.
  • Cancelled. One of your agents replied while the assistant was generating. Whatever had been produced by the time it stopped was billed — and if the generation had already finished with drafting on barge-in switched off, the finished answer is not even offered to the desk.

An install whose confidence floors are set very high can therefore burn a daily budget without a single customer receiving an answer. If spend is rising and Answered is not, that is what is happening — check the escalation reasons on Overview, then Sources.

Skipped turns contribute nothing, but not because of their status: nothing was generated, so costUsd is zero and the costUsd > 0 clause never sees them.

The two ceilings

Spend ceiling for one UTC day, in USD. 0 means unlimited.
Spend ceiling for the UTC calendar month, in USD. 0 means unlimited.

Both are Super-Admin only and both live on the Guardrails tab of /admin/ai/support/settings. 0 is unlimited on either — a real escape hatch for an operator running a local model whose per-token cost is genuinely zero, not a way of saying "unset". Setting both to 0 is also the only way to switch off the refusal in the next section; one ceiling left standing keeps it armed.

The shipped $5 a day and $100 a month are deliberately low enough to be safe on an install nobody is watching. They are not production numbers, and leaving them is the single most common cause of the next two sections.

There is no fallback model, no queue, and no partial service. From the moment a ceiling is reached, every conversation escalates to a person until the window rolls over — the daily one at 00:00 UTC, the monthly one on the 1st.

Your team experiences this as the addon spontaneously stopping in the middle of a shift, usually with no idea a limit exists. Set the ceilings where you actually want them, and put the Overview remaining-budget figure in front of whoever runs the desk.

Three things happen the first time a customer's message hits a closed gate, and only the first of them is on a screen:

  1. The Overview status line reads "Paused: the spend cap has been reached." It says that for every pause, including the unpriced case below, which is the one sentence on the dashboard that can send you looking for the wrong problem.
  2. A notification goes to the whole desk — everyone holding view.support.ticket — linking to /admin/ai/support. It is the only signal that names the reason, and it says one of three things: the daily cap was reached, the monthly cap was reached, or spend cannot be measured. Only the first two end with "Raise the cap in Settings to resume"; the third counts the calls that could not be priced and points at the two per-million-token variables in the install guide rather than spelling them out on screen. It is sent once per cap period — the first conversation the cap stops that day, or that month — so the hour after a ceiling trips is not sixty identical alerts to every administrator while the desk is answering everything by hand.
  3. That conversation's session moves to AI_SUSPENDED, which is per-conversation and does not lift on its own. It is lifted on the next message the customer sends once the budget allows again — and only for the two cap reasons, so a conversation suspended because spend could not be measured stays suspended even after you have fixed the pricing.

Admin-side model calls hit the same gate and return a 429 rather than escalating. Four of the seven admin-side spenders listed at the end of this page say The AI budget for this period has been reached; the provider connection test and gap drafting word it themselves, and gap drafting is the only one that tells you when the reason was the unpriced case rather than a ceiling. The seventh — the retrieval preview — consults no budget at all and so cannot report one.

When spend cannot be measured, the gate refuses

A cap is only a cap if the spend under it is a real number. Two providers can record a turn that moved thousands of tokens and cost, as far as the database is concerned, nothing:

  • The compatible endpoint adapter reports no cost by design. It cannot know: the thing behind it may be a local model, a metered API or a flat subscription.
  • Any model id not in the price table — typically one typed in by hand — prices to nothing rather than being guessed at.

So the budget gate counts those turns. A turn is unpriceable when it moved tokens (inputTokens or outputTokens above zero) and recorded no cost; genuinely free work — a skipped turn, a refusal before the call, a direct answer from one of your own articles — moves no tokens and is not caught.

If either cap is above 0 and the current month contains even one unpriceable turn, the gate refuses everything, with the reason unpriced_model. The assistant escalates every conversation and the admin routes return 429, exactly as if a ceiling had been reached. That is deliberate: the alternative is reporting $0.00 every day while the real bill grows at the provider, under a ceiling that was never going to fire.

There are two ways out, and both are decisions only you can make.

Price the endpoint. Set both of these in .env to what your endpoint actually charges, in USD per million tokens, and restart the backend:

AI_SUPPORT_OPENAI_INPUT_USD_PER_MTOK=0.60
AI_SUPPORT_OPENAI_OUTPUT_USD_PER_MTOK=2.40

Both are required and both must be above zero — half a rate card is worse than none, and a rate of 0 would be indistinguishable from "unknown" all over again. Cached input is billed at the full input rate here, because these endpoints do not agree on whether a cached prefix is discounted and over-counting is the safe direction for a ceiling.

Or set both caps to 0. That has always meant "no ceiling", and it is the honest setting for an install running a local model that really is free.

The count is over the current UTC month and old rows are not re-priced. Turns already written without a cost keep counting, so an install that has been running unpriced for a fortnight stays refused until the 1st, even after the rate card is in place.

If you need the assistant back today, set both caps to 0, let the month roll over, and put your real ceilings back then — with the rate card already configured, they will be enforced against a real number from the first turn.

What drives the bill, in order

1. The answering model. aiSupportModel, on the Model tab. It ships as MashDiv AI Core, and on an install running MashDiv AI those three tiers are the whole vocabulary — the tier is a promise about the job, not a pinned model, so what serves it can improve without you editing a setting.

Tier Input Output
MashDiv AI Lite $1.80 $9
MashDiv AI Core $3.60 $18
MashDiv AI Max $9 $45

Those are the gateway's sell side, so the local budget gate and the figure on your wallet statement agree. Core is currently on an introductory rate and returns to $5.40 / $27 on 1 September 2026; the schedule is in the price table, so the gate switches over on the day with nothing for you to change.

An install running its own provider key picks from a different list, priced at the vendor's own rates:

Model Input Output
claude-haiku-4-5 $1 $5
claude-sonnet-5 $2 $10
claude-opus-5 $5 $25

claude-sonnet-5 carries a dated change of its own — $3 / $15 from 1 September 2026 — read from the same schedule, on the same UTC day boundary as the caps. Which model serves a MashDiv tier is a routing decision made at the gateway, and nothing on your install asserts one.

A model outside both lists prices to nothing. The agent editor refuses one with a 400, but aiSupportModel written through the settings endpoint is not checked against the list, so a typo there is accepted, answers normally, and records $0.00 a turn — which is what the refusal in the previous section exists to catch. If the assistant stops the day after somebody edited the model, look there first.

2. The two internal models. aiSupportRerankModel and aiSupportClassifierModel both ship as MashDiv AI Lite, the cheapest tier. Reranking runs on every question that retrieves anything and classification runs on every message: they are high-volume and structurally simple, and pointing either at a larger model is the easiest way to multiply your bill for no measurable gain. Both controls appear on the Model tab only on a self-managed install — on MashDiv AI the gateway routes those calls down to the cheap tier itself, so there is nothing to choose.

3. Reasoning effort and answer length. aiSupportEffort defaults to low and aiSupportMaxTokens to 4000. Thinking tokens are billed and count against the ceiling on length, so effort is a real cost lever rather than a quality dial — a two-sentence answer measured on a live install at high effort took 42 seconds, 1,026 output tokens and $0.25. On MashDiv AI each tier has its own effort ceiling and a setting above it is served at the highest the tier allows; on a self-managed install the adapter strips the parameter for models that reject it — claude-haiku-4-5 among them — so raising it there changes nothing but your expectations.

4. Prompt cache reads. A cache read costs a tenth of a fresh input token; a cache write costs 1.25× for the five-minute lifetime, or 2× for the one-hour one. When the cache is working, most of your input is being billed at a tenth.

Prompt-cache health

The Prompt cache tile is not a setting — it is a measurement. The ratio is cacheRead ÷ (cacheRead + input) over the last 24 hours of successful customer turns; unlike the money, it does not read the admin table. Below 0.5 it is called unhealthy. Fewer than ten turns in the window is not enough evidence either way, so a quiet install does not alarm.

When something changes the top of the prompt on every request — one unsorted map, one interpolated timestamp above a cache breakpoint — the prefix stops being reused and every answer silently pays full price. The bill multiplies several times over and nothing else on the platform will tell you. Watching this ratio fall is the only detection mechanism that exists.

Two things watch it for you:

  • The Prompt cache tile and its alert banner on Overview.
  • An hourly job, aiSupportCacheHealthCheck, described in Scheduled jobs. When the ratio is unhealthy over at least ten turns it writes a warning to the backend log and raises an admin notification — "AI support is costing more than it should" — to everyone holding view.support.ticket, linking to /admin/ai/support.

It runs hourly rather than daily precisely because a day of an invalidated cache is a day of multiplied bills.

The two levers that cost nothing

Offer the article that answers the question while the customer types their subject line.
Serve a published article verbatim when it already answers the question. No model call at all.

Neither calls a model, so neither can spend a cent. Deflection is a search over articles you wrote and published, offered while the customer is still typing their subject line, with the file-anyway button never hidden. A direct answer arrives in about half a second, and only on the opening question of a conversation written in English — a verbatim English article is a worse answer, not a faster one, for a customer who wrote in Spanish. In COPILOT it is filed as a draft like everything else, because an install where a person reads every reply does not stop being one just because this reply is your own prose.

Direct answers ship off because they change the voice — the customer reads your prose rather than the assistant's persona — not because they are expensive. On an install with a real knowledge base they are the largest reduction in cost per ticket available, and they are the reason chasing coverage on Gaps pays for itself.

aiSupportDeflectEnabled is on the Retrieval tab of /admin/ai/support/settings, where you would expect it. aiSupportDirectAnswerEnabled is live in the backend and accepted by the settings endpoint, but no screen in the product renders it — there is nothing to click.

Until there is, the only way to switch it on is to write the key directly. The settings endpoint takes only the keys you are changing, so a body carrying aiSupportDirectAnswerEnabled set to true is a complete request:

Writes AI Support settings. Send only the keys you are changing.

The admin-side spenders

Seven things in the admin area call a model. Five of them now record what they spent, so the ceiling is computed from the whole bill rather than from your customers' half of it.

Where Route Permission Checks the cap Recorded
The operator assistant, in the console and on Handbook POST /api/admin/ai/support/console access.ai.support Yes Yes
Handbook questions, when the assistant is off POST /api/admin/ai/support/handbook view.ai.support.handbook Yes Yes
Ask about this user, on /admin/crm/user/{id} POST /api/admin/ai/support/ask view.user Yes Yes
Teach from this ticket, in the Live Inbox POST /api/admin/ai/support/article/from-ticket create.ai.support.knowledge Yes Yes
Test connection, on the Provider screen POST /api/admin/ai/support/provider/test access.ai.support.provider Yes Yes
Draft articles from open gaps POST /api/admin/ai/support/gap/draft create.ai.support.knowledge Yes No
Test what it would find, the retrieval preview on Sources GET /api/admin/ai/support/knowledge/search view.ai.support.knowledge No No

The Handbook screen is two routes wearing one face: it fires the console route when the operator assistant is switched on, and the documentation-only handbook route when it is not. Both are billed and both are recorded, but only the first keeps a conversation you can reopen.

All but the last check the budget before spending and refuse with a 429 when it is reached. The operator assistant books its cost onto the conversation you were having, so you can read it turn by turn. The other four have no conversation to book against, so each files its turn under a per-administrator, per-surface ledger row — "Handbook questions — 41 turns, $3.12" — which is what makes their spend readable rather than merely counted. Those ledger rows are listed apart from real conversations in the console's history, and deleting a conversation clears its text without giving its cost back. See Your own assistant.

Generating a draft from the Live Inbox spends too, but it runs the same engine a customer's message runs and writes an ordinary customer turn — so it is already in both the spend tiles and the turn counts, and it is not in the table above.

gap/draft calls a model twice for every gap — the re-ranker inside retrieval, then the drafting call itself — and writes no turn row, so its spend is invisible to both ceilings and cannot be accounted for retroactively. It carries its own control instead: it reads the remaining daily allowance once, keeps a running total of both calls as it works, and stops the batch when that total is exhausted — because re-reading a budget its own calls do not move would return the same number twenty-five times.

Its response is therefore the only place its cost is ever stated. Read the Cost $… in the message it returns; nothing on Overview will show it to you.

Test what it would find on the Sources screen says under its own box that it "costs nothing". That is true only of the answering model. It still calls the re-ranker, which is a model — retrieval reranks whenever the first pass finds more candidates than aiSupportTopK, which on any real corpus is every query. So the default path bills a small generation per search.

Two things sharpen that. Its rerank parameter overrides aiSupportRerankEnabled rather than being narrowed by it, so it reranks even on an install that has switched reranking off everywhere else. And it is the one model-calling admin route with no ceiling in front of it: no budget check, no turn row, no line on Overview.

Add ?rerank=false to get the BM25 ordering instead. The response is the same shape, reranked comes back false, and it genuinely costs nothing. See the API reference.

Two more worth knowing before you hand out the permissions:

  • Teach from this ticket is the most expensive single call an admin can make in this addon: the answering model over a whole transcript at 1,500 output tokens, reachable by anyone with create.ai.support.knowledge, on as many tickets as they care to click.
  • Test connection is not a reachability ping. It runs the whole path a customer's question takes, ending in a real generation, and bills a fraction of a cent for it — on the one screen an operator opens repeatedly because the assistant has gone quiet.

Where to look when the bill moves

  1. Prompt cache on Overview. If it has fallen, nothing else matters until it is fixed.
  2. The average per answer under the month tile. A jump here with flat volume means a model, an effort level or a max-tokens change.
  3. Spent this month against that average × the turn count. The gap is what your own administrators spent. If it is large, the console is your bill.
  4. What it did (30 days). Spend rising while Answered is flat means you are paying for refusals.
  5. The Model tab, for the two internal models. They are the change nobody remembers making.

More failure shapes are in Troubleshooting.