Spend and limits

See what your account spends per user, key and agent, cap each of them, and charge your users for theirs.

Platform usage is charged to your NoClick account at what each service costs NoClick, nothing added, and reported in US dollars. It's paid from your account's balance, where funds you add carry your plan's fee (15% on Free, 5% on Member). Everything is attributed to the key, the user and the agent it was for, so you can see exactly where the money goes and put a ceiling on each.

What costs money

TypeWhat it covers
Model tokensevery agent turn and its model calls
Tool runsintegration operations, including the ones on NoClick's key, and the search and fetch capabilities
Sandboxeseach second a sandbox runs, including the ones behind the code capability and the one an agent on a coding harness runs in
Emailsrequest emails to people and inbox replies
Phone callseach call's minutes
AItokens, images and minutes of audio through AI models (an agent model's turns are the agent's)
Storagewhat buckets store, by the GB-month; requests and downloads are free
Volumeswhat volumes store, by the GB-month
Appsrequests, compute time and builds of deployed apps; what an app spends on AI, agents and its data shows under those types, attributed to the app
Databasescompute time (Postgres), rows read and written (SQLite), and storage, for databases
Browser minuteseach minute a browser runs, plus its model's tokens
App emaileach message an app sends
Domainsdomains you buy and renew

Phone numbers are billed monthly on top.

An agent on a coding harness (claude_code, codex, opencode, hermes, openclaw) thinks with its model connection's key or plan, so its model tokens are the provider's to bill, not NoClick's. What NoClick bills is its sandbox's running time, from the turn that starts it through about a minute after each reply, even when the key is yours: 1 core and 4,096 MB at a sandbox's price, about $0.24 an hour without a region. That time counts toward the agent's budget and its user's and key's caps like any other spend. A turn needs a little balance to start its sandbox, and fails with noclick.PaymentRequired without it.

TypeWhat it covers
Dictswhat dicts store, and their reads and writes
Queuesmessages put on queues
Card numbers$0.10 per card number issued; what a card pays comes from your company's card balance, limited by each card's own limit

See what you've spent

import noclick

month = noclick.usage(group_by="user")
print(month.total_usd)
for group in month.groups:
    print(group.id, group.usd, group.events)

month["user_42"].usd     # one user, by id: 0.0 if they spent nothing
month.get("user_42")      # the group, or None if they spent nothing

support = noclick.Agent.from_name("support")
noclick.usage(group_by="user", agent=support)   # what one agent cost, per user

group_by is "user", "key", "agent" or "project" (each app's spend), and agent narrows it to one agent. Inside as_user, noclick.usage() covers only that user.

For a chart, get daily lines:

series = noclick.Usage.series(group_by="type")   # this month, one line per type above
for line in series.series:
    print(line.label, line.total_usd, [point.usd for point in line.points])

group_by can also be "user", "agent" or "key", and from_ and to pick another window of up to 92 days.

Cap it

A cap for each kind of spender, each per calendar month:

CapSet it with
A key's spendthe key's settings in the console
A user's spendspend_cap_usd_per_month on the user
An agent's budgetbudget_usd_per_month on the agent; a sub-agent's comes out of its parent's
An app's budgetbudget_usd_per_month on the app

Once any cap that applies to a call is used up, the call fails with noclick.SpendCapExceeded before doing any work:

try:
    agent.message("Summarize my week", user="user_42")
except noclick.SpendCapExceeded as err:
    print(err.scope, err.spent, err.cap)   # "user", 20.13, 20.0

Caps are checked before work starts, so the call that crosses a cap still finishes; the next one is refused. Caps reset at the start of each month.

The first refusal sends your webhooks a spend.cap_reached event naming the cap's scope and id, once a month for each cap (again if you raise it and it's reached again), and NoClick emails your account's owner, at most once a day while it refuses work. Your users never hear from NoClick about money: the event is how your code decides whether and how to tell them, say by pausing their spending with your own message.

noclick.Usage.limits() lists every capped key, user and agent with what it has spent this month, and every app with a budget in projects.

Your account's monthly cap

Above all of these, your account can have a cap of its own: what it may spend in each billing period, counted as the Usage page totals it. Once the period's spend reaches it, every call that costs money fails with noclick.SpendCapExceeded (its scope is "account") until the period resets. What the account already has keeps renewing (numbers, domains, storage), and apps keep serving pages until the period reaches twice the cap. noclick.Usage.limits() shows it under account: cap_usd, and where one is set spent_usd and resets_at.

Only the account's owner sets, raises or removes it, in Settings → Plan and billing in the NoClick app. Besides the owner, only the account's own assistant can change it, and only to lower one that's set: POST /v1/usage/limits/account/lower with {"cap_usd": 50}. Your keys, your apps' code and your other agents are refused, whatever they hold.

When an app reaches a cap

A deployed app spends on its own, from its hosting to its AI calls and the agents it messages or made, what it buys (a number, a domain, each renewal too) and what bills after its request (its numbers' calls and texts, its automations, MCP servers, channels, machines and cards), all billed to your account and attributed to the app and its user. It counts toward the user's cap and the app's own budget_usd_per_month, which every app made through the API has ($10 unless its maker sets another), and toward the budget of the app whose code made it, if any. When either is used up, or your balance is, the app keeps serving pages and reading its data, while its paid calls (writes, email, app.ai, agent turns) fail with noclick.SpendCapExceeded or noclick.PaymentRequired naming the app; only at twice its budget do its pages pause:

app = noclick.Project.current()
try:
    reply = app.ai.chat("Summarize today's bookings.")
except noclick.SpendCapExceeded as err:
    print(err.scope, err.project, err.spent, err.cap)   # project booking 25.04 25.0

Deploys are refused the same way, NoClick emails your account's owner once a day until it lifts, and a spend.cap_reached event names the app and its user, so your own code decides whether and how to tell your customer. When it runs out lists which calls keep working and which fail.

When the account runs out

Usage is charged to your account's balance, in dollars: what your plan includes each month, plus any funds you add. When it's used up, calls that spend fail with noclick.PaymentRequired. Its balance_usd is what's left and required_usd what the call needed, and its offers are one-tap links to add funds or change plan, each a payment operation that finishes when it's paid (see Errors). The console's Usage page shows the balance and when your plan's amount renews.

Charging your users

NoClick bills your account, never your users: everything done for a user, from an agent's turns to a domain registered in their name, is charged to you, in dollars. What you charge them, and how, is yours to decide: a subscription, monthly credits with top-ups, paying for exactly what they're short, a team's shared pool, an invoice at the end of the month. That logic stays in your own billing system, where it already lives, and NoClick gives it three things:

  • The usage, as it happens: a usage.recorded event for each step of spend for a user, within seconds.
  • A switch: user.pause_spending() stops a user's spending and tells them what to do; user.resume_spending() lets them go on.
  • A ceiling: a user's spend cap, which holds whatever your billing does.

Usage, as it happens

Subscribe a webhook to usage.recorded, and each step of spend for one of your users reaches your server a few seconds after it settles: an agent's turn when it ends, an AI request, a tool run, a call when it ends, each stretch of a running sandbox or machine as it's billed, an email, a text, a purchase or a renewal, and, early the next day, what their storage held that day.

event = noclick.Webhook.verify(request.get_data(), request.headers, os.environ["NOCLICK_WEBHOOK_SECRET"])
if event.type == "usage.recorded":
    usage = event.data
    billing.record(customer=usage["user_id"], usd=usage["usd"], at=usage["occurred_at"], key=event.id)

Each event's data is one usage record:

FieldWhat it is
user_idYour id for the user it was for.
usdWhat NoClick charges you for it, in dollars, to 6 decimal places.
kindWhat it was: agent.turn, ai.request, tool.run, sandbox.time, phone.call, email.send, text.message, purchase, renewal or storage.day.
linesWhat it's made of, each with its type (as in What costs money), usd, quantity and unit: token, run, second, email, text (a text's segments), gb_hour or item (a purchase or a renewal).
agent_id, agent, conversation, operation_idThe agent, conversation and turn it was for, when it was one.
resourceWhat a span, a purchase or a renewal was about, like {"object": "phone_number", "id": "..."}.
started_at, occurred_atWhen it began and when it ended; the same for anything instantaneous.
correctsThe record a correction amends, else None.

That's what any meter API asks for: whose usage, how much, when, and a key that makes a second delivery harmless. Use event.id as the key (the record's own id is the same), since the same event can arrive twice. A turn's record comes a few seconds after the turn ends, so that what it charged after its reply is in it; an agent's step outside any turn (a call's) is a record of its own. Charge by usd with your margin on top, or by a line's quantity (a call's seconds, say) if that's how you price. Spend that costs your account nothing, like model tokens on a user's own key, sends no record.

Records are never edited. If NoClick has to amend one (a turn charged for something after its record went), the correction arrives as a record of its own, with corrects set to the record's id and a usd that may be negative: net it in your ledger, or send it as an adjustment if your meter takes them. The records add up to what noclick.usage(group_by="user") reports for the same period once they've all settled (a day's storage arrives early the next day), so you can reconcile your totals against it, and replay any your server missed from the event log, which keeps 30 days.

Pause a user's spending

When your billing says a user can't go on (their balance is low, a payment failed, a trial ended), pause them with what they can do about it, and resume them once they've paid:

user = noclick.User.from_id("user_42")
user.pause_spending(message="You've used your credits.", action=("Top up", top_up_url("user_42")))

# later, from your payment webhook:
user.resume_spending()

While a user is paused, nothing that costs money starts for them. Your code's calls raise noclick.SpendingPaused; a message they send an agent gets your message and link back, without the agent running, and waits to run until you resume; a call hears your message. What they already have keeps running. Pause a user's spending has the details for each case.

The action you pause with is your own page, so the money goes to your account and you decide what to offer. Three common ways, simplest first:

  • A payment link from your payment processor, with the user's id on it, like https://pay.example.com/l/abc?client_reference_id=user_42. Its "paid" webhook names the user, so you credit them and resume.
  • Your billing page, where the user signs in. Simple for people on your web app, slower for someone answering from their email or phone.
  • A stable link on your own domain that makes a checkout when it's opened, like https://acme.com/top-up/user_42?sig=.... Use this when the amount varies (topping up exactly what's missing) or the message may be read days later: a checkout session made ahead of time can expire before anyone opens it. Sign the link, so nobody can make one for another user.

How far past their balance a user can go

Your billing hears of each step seconds after it settles, and pausing stops new work at once, so what a user can spend past the point you'd have stopped them is the work in flight when you pause, which finishes: a model call in progress, the reply a call is speaking. Pause at a margin (when a dollar's worth is left rather than none), and keep a spend cap as the ceiling no delay can cross.

Plan features

What a user may do at all (web search only on your Pro plan, say) belongs in your policy, not their balance: a deny rule with a condition on the user, and a message that tells them how to get it.

noclick.Policy.add(
    noclick.Rule("search", when='user.metadata.plan == "free"',
                 message="Web search comes with Pro: https://acme.com/upgrade?user={{user.id}}"),
    to="deny",
)

Keep metadata.plan in step from your billing with user.update(metadata=...). A refused call comes back to the agent with your message, and the agent tells the user. A purchase you'd rather judge case by case goes in require_approval: it waits until a person, or your own code with request.approve(), answers.

Without any of this

  • noclick.usage(group_by="user") gives what each user cost you this month, to bill them on at the end of it, and group_by="project" what each of their apps did.
  • An app takes its own users' payments with app.payments, into a payments account its owner claims.