Skip to Content
Polyant is open source under AGPL-3.0 — star us on GitHub.
Admin PanelSpend Cap

Spend cap

On this page

Managed services. Spend caps are available with Polyant managed services.

Spend cap is a section of the agent’s Governance group, at ?tab=budget, between GDPR opt-out and Retention. It holds the amounts, in USD, at which the agent stops calling the model, and the message it sends when it stops.

It sits under Governance rather than beside Analytics because Analytics reports what was spent, while a cap is a rule that stops the agent. Like Retention, it is a limit with its own form and its own Save.

Anyone who can read the agent (agent:read) can open the section and see the caps and what the open windows have cost so far: knowing the cap is part of knowing why an agent went quiet. Changing a cap or the stop message requires agent.governance:write, held by Admin and above. Without it the fields are shown read-only. Raising a cap spends the customer’s money and lowering one can silence the agent, which is why the write sits on the governance permission rather than on agent:write.

The caps

Every field is optional. An empty field means no cap for that window, and an agent with every field empty has no limit at all, which is how every agent starts. A value must be an amount greater than zero: 0, a negative number or text is refused with the field marked, rather than read as “no cap”, because the save replaces the whole budget and a dropped figure would remove a limit the operator believed they had set.

Caps per window

One field per calendar window: Per hour, Per day, Per week, Per month, Per quarter, Per four months and Per semester. These caps are agent-wide: every model call made for the agent counts toward them. Beside each field the panel shows what has been spent in the window open right now.

The windows are fixed calendar buckets, not sliding ones, because “the agent resumes when the next window opens” only means something if the window has an opening. They are anchored to the calendar year and read in the agent’s time zone, the one set under Advanced → Behaviour overrides (the deployment’s TZ when the agent sets none), so a daily cap follows the customer’s day:

WindowOpens
Hourat the start of each local hour
Dayat local midnight
WeekMonday at local midnight (ISO weeks)
Monthon the 1st of each month
QuarterJanuary, April, July, October
Four monthsJanuary, May, September (January to April, May to August, September to December)
SemesterJanuary and July

Daylight-saving changes are handled in the agent’s zone, including the hour that repeats when clocks go back.

Caps per contact

The same seven windows, applied separately to every contact. Use it when one customer must not be able to spend what is meant for everyone.

The engine has no identity for a person across channels, so a contact here is one chat on one channel: the conversation key <agent>:<channel>:<chat>. A person who keeps writing from the same Telegram or WhatsApp chat keeps one counter, and that counter survives across days and windows. The same person reaching the agent from another channel, or a Web or API client that sends a new chat_id, starts a separate counter, and the members of a group chat share one. The cap therefore limits what one chat can spend; it cannot stop a caller who is free to open new chats, which on the HTTP and OpenAI-compatible endpoints is any caller holding the agent’s key. Pair it with a window cap on the whole agent when that matters.

Cap per conversation

One amount for the whole conversation, with no window. It is the defence against a single conversation that spins, such as a tool loop that keeps restarting. A conversation that reaches it stays stopped until the cap is raised or removed, since there is no next window to wait for.

Stop message

What the agent says when a cap stops it, up to 2,000 characters. Write it in the language the agent speaks. Left empty, the agent uses the default, shown as the placeholder: “I have reached the usage limit set for me. I will resume when it resets.”

When a cap is reached

Before each model call the engine compares the agent’s committed spend with every cap that applies to that call. When one of them is reached, the call is refused:

  • Before the turn’s first call, the stop message is the whole reply. The message is still examined by the agent’s input governance first, at no cost, because the cap refuses the semantic classifier calls too while the deterministic gates run as usual. A message the gates allow is saved in the conversation with the stop message, like any other answer, so both are still there after a reload; a message the gates block, or one a classifier could not examine, is not stored.
  • In the middle of a turn, inside the tool loop, the loop stops and the stop message is appended after whatever the agent had already said. On a streaming channel the reader sees the partial answer and then the stop message.

Each stop appears on the live activity feed as a governance event from the spend-limit gate, with the window that was reached and the amounts.

A window cap applies to the agent’s background work too (memory extraction, titles, summaries, event matching, embeddings), so an agent at its daily cap stops all model calls until the day turns. Output and tool classifier calls inside a turn that was already admitted are charged but never refused, so reaching a cap cannot switch those governance gates off.

Speech-to-text is admitted the same way, before it runs: once a cap is reached the voice note is not transcribed and the sender gets the stop message.

When the agent resumes

  • At the next window. A window cap lifts on its own when the next window opens.
  • At once, if you raise the cap. Saving a higher figure (or clearing the field) takes effect on the next call. On a deployment with several engine replicas, the replica that handled the save applies it immediately and the others within about 15 seconds; a lowered cap takes the same few seconds to bite.

A cap set partway through a window starts from what the agent has already spent in that window, so setting a monthly cap on the 20th does not hand the agent the full amount a second time.

Soft caps

Spend caps are soft caps, and there is no guaranteed bound on the overshoot:

  • They are checked against committed spend, the cost of calls that have already finished and been counted. A call is admitted when committed spend is below the cap, and is not stopped for what other calls are spending at the same moment.
  • Calls already in flight finish. Several calls admitted together can each read the same headroom and all complete, and the next call is the one refused.
  • Counting can lag. Completed calls are reconciled in batches on later admissions, so while a backlog catches up a few more calls can be admitted than the cap would allow.

The panel’s own help text describes the overshoot as bounded by the cost of the calls in progress. Treat that as the usual case, not a guarantee: set the cap below the amount that must never be exceeded.

A failed or aborted model call is charged for the steps it completed. A multi-step call that dies at the provider on step five has already been billed for four, and a turn cancelled and restarted because the user sent a follow-up has been billed for what it did before the restart. Both count toward the caps.

If the engine cannot read the counters at all (a database error), it lets the call through uncounted rather than silencing the agent, and reports the fact as a spend-limit warning on the activity feed and an error in the engine log. While that lasts, the agent has no spend protection.

Which calls count

CallWindow capsContact capsConversation cap
A turn in a real conversation, including its tools and sub-agentsyesyesyes
A background (service) call for a real conversation: memory extraction, title, summaryyesnoyes
A Room cycle, a scheduled task, an agent-to-agent call, a webhook turnyesnono
A voice-note transcription (speech-to-text)yesnoyes
An embedding call (knowledge ingestion, memory, retrieval)yesnono

Service calls count agent-wide and never per contact. Room, scheduler, agent-to-agent and webhook conversations are never treated as a contact, and the conversation cap applies only inside a real conversation. A transcription is billed on the audio’s duration, and every one the provider processed counts, including one that comes back empty.

The figures can differ from Analytics: both sum what failed and pre-empted calls had already cost, but a cap’s day or month follows the agent’s time zone while Analytics renders in your browser’s.

Phone calls

A phone call is only partly under the caps. The agent’s turns and the call’s text model count like any other conversation. The speech and transcription by ElevenLabs, the turn detection by Deepgram and the Typesafe judges are billed by those providers outside the caps and are not logged. A call stays connected after a cap is reached, and the engine limits neither the number of concurrent calls nor their length. Set usage limits at those providers, and a concurrency limit on the Twilio number, before publishing it.

Status checks

The agent’s Status section raises these checks, each pointing back to this section:

CheckSeverityFires when
Spend cap reached ({period})Brokencommitted spend in an agent-wide window has reached its cap. New calls are blocked until the next window opens or the cap is raised
Near the spend cap ({period})Warningcommitted spend in an agent-wide window is at 80% of its cap or more
No spend capNotethe agent has no cap at all and made model calls in the last seven days

Only the window caps raise checks. A contact or a conversation that reaches its own cap is an ordinary event rather than a state of the agent, and one check per conversation would bury the page.

REST API

MethodPathPermission
GET/api/instances/{slug}/budgetagent:read
PUT/api/instances/{slug}/budgetagent.governance:write

GET returns the caps, the stop message the agent will actually use, and the open agent-wide windows with what each has cost:

{ "limits": { "conversationUsd": 2, "periods": { "day": 50, "month": 800 }, "contactPeriods": { "day": 5 } }, "stopMessage": "I have reached the usage limit set for me. I will resume when it resets.", "stopMessageIsDefault": true, "windows": [ { "period": "day", "limitUsd": 50, "spentUsd": 12.4 }, { "period": "month", "limitUsd": 800, "spentUsd": 310.75 } ] }

PUT takes { "limits": {...}, "stopMessage": "..." } and replaces the whole budget: a window left out has no cap afterwards. The period keys are hour, day, week, month, quarter, four_month and semester. Amounts must be positive numbers, an unknown key inside limits is refused with 400, and an empty or missing stopMessage restores the default. Each write is recorded in the management audit log with the new figures.

See also

  • Analytics - what the agent spent, by period.
  • AI Gateway - how each call is priced and logged.
  • Retention - the other limit in the Governance group.
Last updated on