Authorize agent spend before the provider call.

Unprice checks your customer's budget before each agent run. If the budget can't cover it, the run never starts.

free during early access · no card at signup

Payments go to your own Stripe account. Unprice never holds the money.

AGPL-3.0 open source · EU-hosted · two calls to integrate · nothing to deploy

The reservationbudget authorized · before provider
Requestreservations.reserve
Price2,050 tokens × $0.002 = $4.10
Budget check$5.90

does the balance cover this $4.10 request?

allow · within budget

allowed: true

cost $4.10 · covered by balance

deny · over budget

LIMIT_EXCEEDED

needs $4.10 · balance $1.80

Authorize first. Settle what the run actually cost.follow the full path ↓
01The status quo

Your provider gets paid before anything checks the budget.

Your Redis counter is not a budget. It counts spend only after it happens.

The DIY stackone agent run · traced
cron reset-usagelast success · 3d ago
POST /v1/run200 · work executed
INCR usage:acme-corp4,101 → 4,102
provider cost$0.48 · already spent
38 more log lines · unindexed
30 days later · invoice line$1,204.00
support · ticket #4812reply due · 24h

"Why were we charged $1,204? We set a $500 budget."

assignedengineering
plan versionunknown
budget checknever ran
ledgerno entry
evidencerebuilt by hand
02The money path

One check, from request to invoice.

If the check allows a request, Unprice holds the cost, the agent runs, and the actual usage goes on the invoice. If it denies the request, nothing runs and nothing is charged.

The money path3 requests · one budget
Requestusage.consume

the agent run asks before it spends

Metertokens used · 2,050
Accessincluded in plan · yes
Pricing rule$0.002 / token · pro@v3
Budget check$10.00

does the balance cover this $4.10 request?

allow · within budget

accepted: true

cost $4.10 · covered by balance

Walletreserve −$4.10
Ledgercapture · balanced
Invoiceline explained
invoice line · explain$4.10

2,050 tokens × $0.002 · pro@v3

reserve → capture · balanced

Paymentyour own Stripe

the money never touches Unprice

deny · over budget

LIMIT_EXCEEDED

needs $4.10 · balance $1.80

Walletuntouched
Ledgerno entry
Invoiceno line
invoice line—

zero provider calls · no cost to explain

reason → your app · limit exceeded

Paymentno charge

Reserve when the cost varies, like an agent run. Use one call when you know the cost up front.

03The proof

Read the proof.

Don't take our diagram on trust. Read the tests, run the benchmark, and read the source.

There's no walkthrough video yet. You can check everything below without an account.

AI chatbotreserve before generation · settle actual token usage on finishRead the integration
concurrency5 concurrent over-limit writes → 2 accepted, 3 rejectedRead the test
latencyk6 harness · run it against your own deploymentRun the benchmark
the money pathAGPL-3.0 · the decision, ledger, and wallet codeRead the source
04First integration

Reserve the customer's budget before the model spends yours.

Reserve before generateText runs, then settle the actual usage. If Unprice denies the reservation, your code never calls the provider.

reserve → generate → settle
1import { generateText } from "ai"
2import { Unprice } from "@unprice/api"
3
4const unprice = new Unprice({ token: process.env.UNPRICE_TOKEN })
5
6// 1. Reserve the most this model call may cost.
7const { result: reservation, error } = await unprice.reservations.reserve({
8 customerId,
9 maximumAmountMinor: 10, // $0.10 ceiling, held against the customer's budget
10 idempotencyKey: messageId,
11})
12
13// Hard deny. Return here and the provider is never called.
14if (error) {
15 return new Response("Customer budget unavailable", { status: 402 })
16}
17if (!reservation.allowed) {
18 return new Response("Customer budget unavailable", { status: 402 })
19}
20
21// 2. Spend only after the reservation succeeds.
22const generation = await generateText({
23 model,
24 prompt,
25 maxOutputTokens: 2_000,
26})
27
28// 3. Capture actual usage and release the unused amount.
29const settlement = await reservation.settle({
30 featureSlug: "ai-output-tokens",
31 eventSlug: "completions",
32 id: messageId,
33 properties: {
34 inputTokens: generation.usage.inputTokens,
35 outputTokens: generation.usage.outputTokens,
36 },
37})
38
39if (settlement.error) throw settlement.error
40
41return Response.json({ text: generation.text })

Two calls cover simpler cases.

usage.consumeknown cost · authorize and consume in one atomic call
access.checkread-only · checks access, reserves nothing
An open-source AI chatbot uses this pattern.Read the chatbot integration
  1. 01

    Reserve

    Hold the maximum cost before the provider call.

    customerfunds the work
    held$0.10 maximum
    deniedno provider call
  2. 02

    Run

    Start the agent once the hold succeeds.

    provideryour model account
    limit2,000 output tokens
    executoryour application
  3. 03

    Settle

    Report the actual usage. Unprice releases the rest.

    capturedactual usage
    releasedunused hold
    evidenceusage → invoice
05The questions

Questions before you integrate.

Unprice is for products where one customer request can trigger paid AI work. If you only charge per seat, use Stripe Billing. If you want one cap on your whole provider bill, use an AI gateway.

payments through Stripe today · no tax, accounting, or revenue recognition

Why not just Stripe?
Keep Stripe. It charges after the work runs, so it can't stop the work. Unprice checks the spend before the work runs. The full argument
Why not an AI gateway?
A gateway caps your total provider bill. Unprice caps each customer's budget before the call reaches the gateway. Some products use both.
Why not Redis?
You can build the hold in Redis in about fifty lines. The hard part is the record behind each charge: the plan version, the rate, the ledger entry, and the invoice line. Unprice keeps that record for every charge. Read the source
Where does this run?
On the hosted cloud there is nothing to deploy, and billing state stays in Cloudflare's EU jurisdiction. Budget state is the exception and can live outside the EU. You can also run Unprice in your own Cloudflare account.
Does Unprice hold the money?
No. Payments go through your own Stripe account. Unprice records the decision, the ledger entry, and the invoice line.
What does a deny look like to my user?
Whatever you choose. A deny returns 200 with allowed set to false and a reason such as LIMIT_EXCEEDED, so your app can offer an upgrade.
How much latency does the check add?
One request, before a provider call that costs far more. Ledger and invoice work run afterward. Run the k6 benchmark against your deployment to see real numbers. Run the benchmark
What if Unprice is down?
Your code decides. Fail open and log it, or fail closed for expensive actions.
06The offer

Put one agent action on a budget in one afternoon.

Bring one agent run that costs you money. The reasoning is in the manifesto.

one plan version · one customer signup · one reserved agent run

Sandbox first

Try it in Unprice's built-in Sandbox first. If it doesn't fit, remove it. Nothing else changes.

I'm onboarding ten design partners myself. Email me the action you want to budget, and I'll reply with the first step.

Seb, founder of Unprice · [email protected]