Agent-first BillingA Field Guide
[ Request early access ]

Agent-first Billing
A Field Guide

How we’re building the most ambitious metering and billing engine for AI software.

[ Request early access ]
90°135°180°225°270°r 155r 155

00Core principles

Three ideas run through everything that follows. Every number comes from events, agents are customers like any other, and billing answers next to your code without waiting on Polar.

Everything is an event

Every number Polar shows is computed from the events you send.

EVENTSSTATE · ONE VALUEstate = fn(events)

One record

Usage is recorded as events and nothing else. Each one says who did what, when, and how much.

Everything derived

Meters, credit balances and invoice lines are all computed from the events, so there is no second count to drift out of sync.

Traceable

Any number can be rebuilt from the events behind it, so a line on an invoice leads back to what happened.

Native to agentic workflows

Agents do the legwork, and people make the call.

agent Margin on pro fell to 12% this week. Opus got pricier.mcp metricsmargin · pro 12% floor 20%mcp usageoutput tokens +38% this weekmcp draftprice · pro $2.00 → $2.40 / Mmcp checkmargin · pro 27% passdraftpricing/opus-upwaiting for reviewyouapprovedapplied to prod

Agents as customers

Customers hold their agents, and every event says which one acted. Usage rolls up to whoever pays.

Agents draft changes

Agents in your editor, your chat or your own stack read usage and margins through Polar’s MCP server and draft changes. A draft is a branch, checked like any other change.

A person approves

Someone on your team reviews the draft and approves it, or asks for another. Nothing reaches customers on its own.

Zero latency & fault tolerance

Checks are answered next to your code, without waiting on the network.

YOUR APPcheck()OUTPOSTyour redisPOLARevent logZERO LATENCYSYNCS IN THE BACKGROUND

Next to your code

Checks are answered by Outpost inside your app, from state kept in your own Redis. There is no round trip to Polar.

Off the network path

Outpost answers from the state it holds, so a slow or dropped connection never holds up a check.

Always in sync

Events flow to Polar in the background, and Polar’s numbers settle the local ones as they arrive.

01Billing as code

The catalogue is a file. Products, prices, meters and entitlements are declared once, reviewed as a diff, and applied to an environment, so a pricing change goes through the same review as any other code.

The config

A product is a file you review and apply.

export default defineConfig({ events: { 'llm.completion': z.object({ model: z.string(), input_tokens: z.int(), output_tokens: z.int(), }), }, meters: ({ meter, events }) => ({ tokens: meter('Output tokens') .on(events['llm.completion']) .unit('token') .sum('output_tokens'), }), products: ({ product, meter }) => ({ pro: product('Pro') .recurring('monthly') .prices( meter('tokens') .amount(perMillion(usd(3))), ), }),})APPLYEVENTllm.completionMETERtokens · sumPRODUCTPro · $3 / Mpolar.config.ts

The file

A product’s events, meters and prices live in one typed file, beside the code that emits the events, and the types flow from the event schema to the meter to the price.

The review

The file goes through the same pull request as everything else. A price change is a diff that a reviewer reads, and the build type-checks it against the schemas before anyone can apply it.

The apply

The CLI compares the file with what is deployed and applies the difference: new products and prices are created, changed ones updated, the rest left alone. The file stays the source of truth.

Review and apply

The CLI reads the file, shows the plan, asks, and applies it.

$ polar apply --env prodReading polar.config.tsFound 1 event, 1 meter, 2 productsPlanning against prod (deployed 3 days ago) event llm.completion meter tokens - price pro.tokens perMillion(usd(3)) + price pro.tokens perMillion(usd(2.5)) + product team seats · graduated · monthlyPlan: 1 to change, 1 to add, 2 unchanged? Apply 2 changes to prod? (y/N) yUpdated price pro.tokensCreated product team✓ Applied 2 changes to prod in 0.41s

The plan

The CLI reads the file, computes the diff against what is deployed, and shows it before anything changes. The dashboard still works too, and the next plan picks up whatever was changed there.

Applied

On yes, it applies the plan. What is deployed then matches the file, and the next plan starts from there.

Margin checks

An unprofitable price fails the build.

pushPASSbuildPASStestPASSmarginFAILapplySKIPPEDFAIL margin below the floor, nothing appliedplan prometer output tokensprice $2.00 / M tokenscost $2.36 / M tokensclaude-opus-5-5margin -18%floor 20%

In CI

Polar runs in your pipeline next to your tests. Every change to the billing definition is priced against what it costs to serve before it can merge.

Price against cost

Events carry their cost, so Polar knows what a million tokens on each model costs you. Here, the plan charges $2.00 and serving it costs $2.36.

Blocked

That is 18% under water, below the 20% floor you set. The check fails and nothing is applied, the same as a failing test.

02Events

An event is a fact: at this time, this customer, through this actor, did this thing, this much. The event log only grows, and every usage number is derived from it.

What’s in an event

Who did what, when, and how much.

08162432IDevt_01ja7qTIMESTAMP2026-10-18T14:02:11ZCUSTOMERacmeACTORagent_adaNAMEllm.completionMETADATA{ input_tokens: 3120, output_tokens: 1240, … }WHENWHOWHATHOW MUCH

When

The timestamp is when it happened, so a late event still lands in the right period.

Who

The customer is who pays. The actor is who did it on their behalf: a teammate, an API key, or one of their agents.

What

The name says what happened, like llm.completion. Meters pick the events they count by name.

How much

The metadata holds the numbers, like 3,120 input and 1,240 output tokens, in any shape you like. Meters add them up.

The event log

Append only. Events are added, never changed or removed.

IMMUTABLE EVENT LOGHEAD · NOW

Append only

The event log only grows. A new event is added to it, and nothing already in it is ever edited or deleted.

Every number

Every usage number, a meter reading, a credit balance, an invoice line, is computed from the event log, so it can be traced back to the events behind it.

Late events

An event counts at the time it happened.

ARRIVED · BY INGESTION TIMEe2e1e3e5e4e6COUNTED · BY EVENT TIMEe1e2e3e4e5e6

Arrival

Events can arrive late: a retry, a queue that backed up, a batch sent at the end of a job. Each carries the time it happened, and Polar uses that time.

Same answer

A meter over the event log gives the same answer whether an event took a millisecond or a day to arrive. A late event slots into its place in time.

AI gateways

Model calls through an AI gateway are metered with no extra code.

YOUR APPgenerate()AI GATEWAYroutes the callMODELSclaude · gpt · geminiPOLARevent logllm.completion{ model, input_tokens, output_tokens, cost }

Through your gateway

If your model calls already go through an AI gateway, Polar connects to it and records every call as an event.

One event per call

Each call becomes one llm.completion event, with the model and its input and output tokens. There is nothing to add to your code.

Cost included

The gateway knows what each call cost, so the event carries it, and Polar knows your margin on every customer as the usage happens.

03Meters

A meter turns events into a number: which events count, and how to add them up. Polar keeps that number current as events arrive, and can always rebuild it from the events behind it.

How does a meter work?

A meter turns events into one number.

0 output tokensEVENT STREAMTHE FOLDREADING

What it counts

A meter picks the events it cares about, like llm.completion, and adds them up: a count, a sum of output tokens, a maximum.

Always current

Each new event updates the number straight away, so it is never waiting on a nightly job.

No drift

The number can always be rebuilt from the events behind it, so it always matches what happened.

Reducers and buckets

Events add up into five-minute buckets, and an invoice adds up the buckets.

REDUCERΣ output_tokenswhere name = "llm.completion"EVENTSBUCKETSΣ tokens2,1203 events14:002,4903 events14:059402 events14:101,4302 events14:151,8602 events14:201,3002 events14:25SEALED · BILLEDOPEN

Reducers

A meter says which events count and how to add them up: count them, or sum, average, minimum or maximum a property. That rule is a reducer. Meters with the same rule share one, so the work is done once.

Buckets

Each matching event lands in the five-minute bucket its timestamp falls in, one per customer. A bucket keeps a count, sum, minimum and maximum, enough to answer any of those for any period.

Sealed once billed

When a period is billed, its buckets are sealed and never change. An event for that period that arrives late still counts at the time it happened, and is charged on the next invoice.

Rates and tiers

One month of usage, priced two ways.

TIER 1$3.00 / MTIER 2$2.50 / MTIER 3$2.00 / MTOTALGRADUATED1M × $3= $3.001M × $2.50= $2.500.5M × $2= $1.00$6.50VOLUME2.5M × $2, all in tier 3$5.0001M2M3M2.5MTOKENS THIS MONTH

Tiers

A price splits the meter into ranges, each with its own rate. Here, the first million tokens cost $3 per million, the second $2.50, and everything after $2.

Graduated

Each tier bills the tokens that fall in it, at its own rate, like tax brackets. 2.5M tokens come to $3 + $2.50 + $1 = $6.50.

Volume

The tier the total lands in sets the rate for every token. 2.5M lands in tier 3, so all of it bills at $2: $5.00.

Declared

Tiers are declared in the config next to the meter they price, and a cap can bound the total.

04Local-first

Outpost runs inside your own process. It folds every event with the reducers Polar runs, in your own Redis, so a check is answered where your code is. Polar settles the usage behind it and sends that back.

Where Outpost sits

Between your app and Polar, with its state in your Redis.

YOUR PROCESSAPP CODEingest(event)customerMeter()OUTPOSTreducersΣ output_tokensbucketschecks0 msPOLAReventsreducersΣ output_tokensbucketsREDISyours · buckets, snapshots0msRECONCILIATIONSTATE

In your process

Outpost is part of the Polar SDK and runs in your app. Your code hands it events and asks it to check a customer’s meter, and neither call goes to Polar.

Your Redis

Its state lives in a Redis you run: the five-minute buckets, and the snapshots Polar sent. Every process of your app reads the same state, so they agree on a balance.

Between you and Polar

Events go on to Polar batched over HTTP, and Polar’s event log stays the source of truth. Back over one WebSocket come the reducers, and a snapshot whenever usage settles.

Local-first checks

Answered from the state in your own Redis. Polar catches up behind it.

CHECKSTATESTREAMv1v2v3v00 ms100 ms200 ms300 ms400 ms

No round trip

A check, "may this customer call the API?", is answered by Outpost from the state it holds: the fold of every event seen so far. It does not wait on Polar.

Same reducers

When Outpost connects, Polar sends it the organization’s reducers, so an event is folded locally exactly as Polar folds it, into the same five-minute buckets.

First sight

The only round trip is the first check for a customer Outpost has not seen yet: it fetches their usage from Polar once, and every check after that is answered locally.

Reconciliation

Outpost answers now. Polar’s snapshots correct it as buckets close.

POLAROUTPOSTSNAPSHOTSETTLED · FROM POLARLOCAL · OPEN BUCKETS

Two folds

Outpost folds what your process has seen. Polar folds everything, including events from your other processes and events that arrived late.

Snapshots

When a bucket closes, a late event lands or credits change, Polar pushes a snapshot: the customer’s settled usage up to a point in time. It replaces Outpost’s totals before that point, and the local buckets behind it are dropped.

Never backwards

Every snapshot carries a version, and an older one is never applied over a newer one. If the connection drops, Outpost keeps answering from what it has and asks for fresh snapshots when it is back.

05Identities

You might sell to agents, spawn them on a customer’s behalf, or both. Polar calls every customer an identity, human or machine, and gives every one the same meters, credits and entitlements.

Nested identities

People and agents, in whatever hierarchy you design.

acmeresearchsupport-botadalinbotrunrunrunUSAGE ROLLS UPACCESS ROLLS DOWNONE RUN, ITS OWN IDENTITY

Human or machine

A person, a team, an agent, a single agent run: each is an identity, and each holds meters, credits and entitlements the same way.

Nested

Identities nest in the shape your product needs: a company, its teams, the people and agents in them, and the runs those agents start.

Up and down

Every event names the identity that acted. Usage adds up the tree to whoever pays, and entitlements set higher up apply to everything beneath.

Usage by identity

Usage adds up the tree to whoever pays.

USAGE · LAST 30 DAYScustomer: acmecustomer acme12,750 creditsteam research8,020 creditsperson ada@acme.io1,900 creditsagent research-bot6,120 creditsagent support-bot3,480 creditsservice nightly-sync1,250 credits

Counted per identity

Each event names the identity that acted, so Polar counts usage for every person, agent and service under a customer.

Rolled up

A team’s usage is the sum of the people and agents in it, and the customer’s total is the sum of the whole tree.

One bill

The customer pays for the total, and the breakdown shows which agent or person it came from.

Unit economics

Revenue, cost and margin for every identity in the tree.

UNIT ECONOMICS · LAST 30 DAYScustomer: acmeREVENUECOSTMARGINcustomer acme$3,825$2,13344%team research$2,406$1,64032%person ada@acme.io$570$17170%agent research-bot$1,836$1,46920%agent support-bot$1,044$41860%service nightly-sync$375$7580%FLOOR 25%

Per identity

Events carry their cost, and usage is priced as it lands, so every identity has its own revenue, cost and margin.

Where the margin goes

Rolled up, acme runs at a healthy 44%. One level down, research-bot runs at 20%, under the floor, while the people and services around it make up the difference.

Act on one identity

A guardrail on an agent’s margin can move it to a cheaper model or slow it down, and leave the rest of the customer alone.

Shared and delegated

Credits and limits flow down the tree the way you set them.

IDENTITY CREDITS USEDacme pool 10,000 3,680├ research limit 4,000 2,180│ └ agent budget 500 480└ support-bot limit 3,000 1,500 └ run_7f2 cap 50 50signal run_7f2 used its cap → your app decides what happens next

Shared

A company buys one pool of credits, and every identity beneath it draws from the same pool.

Delegated

Hand a slice down: a team gets a limit, an agent a budget, a single run a cap of its own. Usage still adds up to the pool.

Same guardrails

Each level can carry its own signals, so you hear about one run burning through its cap long before the company’s pool feels it.

06Guardrails

A guardrail is a condition on a number Polar already keeps: a meter, a credit balance, a margin. When the number crosses it, a signal fires and runs your side effect, so you can move a customer to a cheaper model before the credits run out.

Signals

A side effect that runs when a number enters or leaves a threshold.

CREDITSTHRESHOLDSIGNAL · ENTERSIGNAL · EXITMODELclaude-opus-5-5claude-opus-5-5gemini-flash

A condition

Register a condition on a number Polar already keeps: a meter, a credit balance, a margin. Here, a customer’s credits falling below a fifth of their grant.

Enter and exit

The signal fires when the number crosses into the condition, and again when it leaves, so a side effect runs once per crossing.

Ahead of time

Signals run at runtime, on the zero-latency state, so you act before the limit is hit: the customer moves to a cheaper model before their credits run out, and back when a grant lands.

Margin floor

When a customer’s margin drops below a minimum, slow them down.

MARGINTHRESHOLDSIGNAL · ENTERSIGNAL · EXITACCESSopenopenrate limited

Margin

Events carry their cost, so Polar knows revenue and cost per customer as they happen, and the margin between them.

A floor

Set a minimum margin. When a customer falls below it, the signal fires: rate-limit them, or route them to a cheaper model.

Lifted again

When the margin recovers, the exit fires and the limit comes off. The rule is code, kept next to the rest of your billing.

07Simulations

Try a pricing change before your customers do. Branch your billing, replay last month’s real usage through it, pull levers like churn and growth, and see revenue, margin and who would pay more. When it looks right, deploy it like any other change.

Branch and replay

Try a new price on last month before your customers see it.

PRODBRANCHINGpricing/opus-upDEPLOYEVENTSLAST 30 DAYS · REAL USAGE

A branch of your billing

Branch the billing definition the way you branch code: a new price, a different tier, a bigger credit grant. Production keeps running on the original.

Real usage, replayed

A simulation runs your real events from the last month through the branch, so you see what each customer would actually have paid.

Then deploy

When the numbers look right, merge the branch. It goes through the same plan, review and margin check as any other change.

Levers and outcomes

Pull a lever and see what last month would have looked like.

LEVERSpricepro $2.00 → $2.40 / Mchurn6% of customers who pay moreprod opus-up changerevenue$48,200$55,100+14%cost$41,900$41,000-2%margin13%26%+13ptchurn risk312 customers pay 20% morelargest: acme, +$410 / month

Levers

Change what you want to test, a price, a tier, a grant, and the assumptions around it: how many affected customers churn, how fast new ones arrive.

Side by side

Revenue, cost and margin for production and the branch, from the same month of real events plus your assumptions.

Churn risk

Big price changes come flagged: how many customers would pay more, by how much, and the largest increases, before any of them see a new bill.

08Credits

Credits are a balance derived from two kinds of event: grants, which add, and usage, which takes away at the meter’s rate. When they run out, Polar keeps counting, and your app decides what happens at zero.

The credit balance

A grant fills it and every metered event drains it.

EVENTΔBALANCE>>01-01credit.granted+10,00010,000periodbalance.carried0 of 10,000

Two kinds of event

Credits are a balance derived from two kinds of event: grants, which add, and usage, which takes away at the meter’s rate.

Never stored

The balance is the last line of this statement, recomputed from the events above it.

Grants and expiry

A grant is an event with a start and, sometimes, an end.

OCTNOVDECJANFEB10,000 · EXPIRES JAN2,000 · EXPIRES DEC5,000 · NO EXPIRYEXPIRED · REMAINDER WRITTEN OFF

A grant

A grant adds credits from a moment, and may take them back at another.

Soonest first

Usage drains the grant that expires soonest first, so nothing is left to lapse while a longer one is spent.

Expiry

When a grant expires, its unused remainder is written off with an event of its own, and the balance is the fold over all of them.

Running out

Polar keeps counting. What happens next is up to you.

TIME EVENT CREDITS BALANCE 09:41 llm.completion -314 1,250 09:52 llm.completion -980 270 10:07 llm.completion -412 -142 10:07 signal balance < 0 → your app decides what happens next 10:31 credit.granted +5,000 4,858

Never refused

Polar records every event, even the one that takes the balance under zero. The balance goes negative, here to -142.

Your call

Polar does not cut anyone off. What happens at zero is up to your app: block the request, move the customer to a cheaper model, or let them run a tab. A guardrail at zero tells you when it happens.

Topping up

A new grant is added to the balance as it stands, so the 142 owed comes off first: 5,000 credits leave 4,858.

09Entitlements

Entitlements are what a subscription unlocks. When the subscription changes state, every entitlement on it switches with it.

How entitlements work

The subscription’s state moves every gate.

SUBSCRIPTIONactiveAPIONAGENTSONEXPORTSOFFGATE

The switch

An entitlement is a switch, and the subscription’s state is the line that drives it. When the state changes, every switch on the line moves at once.

The states

Active closes them, past due keeps them closed, and canceled opens them.

A history

Each move is an event, so access has a history.

On a product

What a product grants, held by the customer while they subscribe.

PRODUCTproapiACCESScredits10,000 / MONTHlicenseKEY · 1 SEATGRANTS, ON SUBSCRIPTION

Templates

A product lists what it grants: access to the API, a monthly grant of credits, a license key. Each is a template the customer gets a copy of.

Granted

When a subscription to the product becomes active, every entitlement on it is granted to the customer, and revoked again when the subscription ends.

Changes

Change the product’s entitlements in the file, and the next apply updates them.

10Bring your own PSP

Polar works out what to charge. Who takes the payment is up to you: the processor you already use, like Stripe or Adyen, or Polar as your merchant of record.

Bring your own PSP

Polar runs the billing. Payments go through the processor you choose.

POLAR · THE AMOUNTINVOICE · acmepro plan$20.00tokens · 2.5M$6.50total$26.50STRIPE · chargeamount$26.50card•••• 4242statussucceededYOUR PROCESSOR · THE PAYMENT$26.50OR ADYEN, OR YOUR OWN

Your processor

Keep the payment processor you already have, Stripe, Adyen and others, along with the contracts and rates that come with it. Polar charges through it.

Same billing

Meters, prices, credits and entitlements work the same whichever processor takes the payment. Switching processors does not touch your pricing.

You are the merchant

With your own processor, the sale is yours: sales tax, disputes and compliance stay with you, as they do today.

Polar Billing

Billing, payments and tax in one, with Polar as your merchant of record.

customer · Berlinpays €23.80€20.00PAYOUTto your bank€3.80VAT · 19%filed in GermanyPOLAR · MERCHANT OF RECORD

One integration

Checkout, subscriptions, usage and payments come from the same place, with nothing to wire between a billing system and a payment processor.

Merchant of record

Polar is the seller on every transaction, so sales tax and VAT are calculated, collected and filed for you, wherever your customers are.

Less to run

Disputes, refunds, fraud screening and receipts are handled for you. You get paid out to your bank account.

Early access

We're building agent-first billing with a small group of AI startups. Tell us about yours, and we'll bring you in early, with a direct line to the team building it.