Sell credits and usage. Keep the margin.
Authorize customer spend before paid work runs — what your customers spend, not your own provider bill. Open source, for SaaS that sells credits, API calls, or agent runs.
free during early access · no card at signup
Settles to your own Stripe — the money never touches Unprice.
AGPL-3.0 open source · two calls to integrate · nothing to deploy
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
By invoice time, the paid work already ran.
Your Redis counter is not a budget. It notices usage after the expensive action already ran, and when the customer disputes the invoice, engineering reconstructs the charge from logs by hand.
“Why were we charged $1,204? We set a $500 budget.”
The decision becomes the invoice.
An allow reserves the wallet, captures the ledger, and writes an invoice line that explains itself — settled in your own Stripe. A deny leaves nothing behind: no entry, no line, no charge, and the reason returned to your app.
the paid action asks before it runs
does the balance cover this $4.10 request?
allow · within budget
accepted: true
cost $4.10 · covered by balance
2,050 tokens × $0.002 · pro@v3
reserve → capture · balanced
the money never touches Unprice
deny · over budget
LIMIT_EXCEEDED
needs $4.10 · balance $1.80
no cost created · nothing to explain
reason → your app · limit exceeded
Every step in this path is a method in the public SDK. Run the check in shadow beside the logic you already run — TypeScript, REST, or curl.
Proof you can check yourself.
Everything above this line is drawn by us. These are not: a test that proves the concurrency guarantee, a benchmark you point at your own deployment, and the money-path source. If the ledger does not balance, you will find it here first.
A recorded walkthrough is coming. Until it does, the receipts below are the ones you can check yourself — no account, no demo call.
Two calls, and nothing in your stack changes.
customers.signUp once, at your own signup, then access.check beside the logic you already trust. The check is read-only — it decides nothing, it just tells you what it would have decided.
1import { Unprice } from "@unprice/api"23const unprice = new Unprice({ token: process.env.UNPRICE_TOKEN })45// Once, at your own signup.6const { result: customer } = await unprice.customers.signUp({7 name: "Acme Inc.",8 email: "[email protected]",9 planSlug: "pro",10})1112// Day one: read-only. Log what Unprice would have decided13// next to the answer your own logic gave.14const { result } = await unprice.access.check({15 customerId: customer.customerId,16 featureSlug: "tokens",17})1819log({ unprice: result.allowed, mine: myExistingCheck() })
When the shadow decision matches reality, enforce with a call that reserves. Never gate on access.check alone — it reserves nothing, so two concurrent requests both pass it.
- 01
Shadow
Run the decision beside the logic you already trust. Compare answers without changing behavior.
runsaccess.checkmutatesnothing · read-onlyblocksnothing - 02
Sandbox
Prove the path before a dollar moves — model customers, plans, and budgets.
processornone · built-in Sandboxcustomerssimulatedevidencereal · inspectable - 03
Enforce, in your own Stripe
Switch to a call that reserves, and go live in your own account. Unprice owns the decision; your provider still captures the payment.
enforcesusage.consume · runs.*funds flowyours · alwaysunpricenever in the middle
Asked before you integrate.
Unprice is for teams whose customers can trigger real cost — an LLM call, a data job, a paid workflow. If your product is pure seat-based SaaS, Stripe Billing is enough. If what you need to cap is your own provider bill rather than what your customers spend, you want an AI gateway, not this.
Stripe today · hosted or your own Cloudflare account · not tax, accounting, or revenue recognition
- Why not just Stripe?
- Keep Stripe for payment capture. Unprice owns the customer money path before and around the invoice: plan versions, entitlements, budgets, credits, ledger captures, and evidence. The full argument
- Do I need Cloudflare?
- Not to use it. The hosted cloud runs the runtime for you — install the SDK, call the API, nothing to deploy. Cloudflare is the self-run path: the open-source runtime deploys to your own Cloudflare account (Workers, Durable Objects, Queues) because the spend decision needs fast per-customer state where requests run. Self-run means your account, your data, your keys; hosted means no infrastructure at all. Both settle payments to your own Stripe.
- Why not an AI gateway?
- Different direction of spend. Gateways cap what you spend with your providers — your OpenAI or Anthropic bill — and route models behind virtual keys. Unprice caps what your customer is allowed to spend with you, and connects that decision to plan versions, credits, and invoice evidence. If you want per-team attribution and a ceiling on your own provider bill, use a gateway; they are not competitors and you may well want both.
- Why not a Redis counter?
- For a single limit it is genuinely fine. It stops being fine when the counter has to agree with money: under concurrency a race lets over-budget work through, and the counter can tell you usage was high but not which budget was checked, which credits were reserved, why a request was denied, or how accepted usage became an invoice line. Unprice keeps the check, the reservation, and the explanation on one path.
- Does Unprice touch the money?
- No. Your app asks Unprice before paid work runs and gets an allow or deny with evidence attached. Your payment provider captures the payment — Stripe today, your own account or Stripe Connect, plus the built-in Sandbox provider for proving the path without a processor. The provider layer is one interface: Stripe-first today, provider-extensible by design, and no other provider is claimed until it ships. Unprice owns the decision, the ledger, and the evidence; it never sits in your funds flow.
- What does my customer see when a request is denied?
- Whatever you decide — the deny is an answer, not an outage, and not an HTTP error. The call returns 200 with allowed false and a machine-readable reason (LIMIT_EXCEEDED, plan expired, no entitlement) before any cost is created, so your app can show the customer why and offer the upgrade path instead of failing silently. Every deny is recorded with its evidence, so you can see who keeps hitting limits and treat denials as upgrade conversations, not support tickets.
- What does the check add to my request latency?
- One authorization request. A warm check is a cached read plus one Durable Object read; invoicing, analytics, and the ledger ride queues off the request path — never inside it. Numbers depend on where your traffic runs, so the repo ships a k6 harness instead of a marketing claim: point it at your own deployment and read the percentiles. Run the benchmark
- What happens if Unprice is down?
- The check fails loud, never silent: you get an explicit error and your code owns the fallback — fail open and log, or fail closed for the expensive actions. Caches serve stale answers while they revalidate, and shadow mode blocks nothing by construction, so an outage during adoption costs you nothing.
- Is it safe enough for money logic?
- Do not adopt it all at once. Read the source, run one request path in shadow, prove it on Sandbox, then enforce only when the evidence matches. Read the source
Start with one paid action in one afternoon.
Bring the one action in your product that burns margin when a customer runs it. That is the whole prerequisite — the argument behind it is in the manifesto.
one plan version · one customer signup · one shadow check
If the decisions don't match your reality, delete the access.check line and walk away. Nothing in your stack changed, and there is no contract to exit.
I am taking ten design partners and I onboard each one myself. Email me your action and I'll reply with the first step — whether or not a slot is left.
— Seb, founder of Unprice · [email protected]