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

The decisionread-only · mutates nothing
Requestaccess.check
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

Allow settles. Deny costs nothing.follow the full path ↓
01The status quo

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.

The DIY stackone paid action · 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
evidencereconstructed by hand
02The money path

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 money path3 requests · one budget
Requestusage.consume

the paid action asks before it runs

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

no cost created · nothing to explain

reason → your app · limit exceeded

Paymentno charge

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.

03The receipts

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.

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 · ledger, wallet, and decision in the openRead the source
04First integration

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.

signUp → check
1import { Unprice } from "@unprice/api"
2
3const unprice = new Unprice({ token: process.env.UNPRICE_TOKEN })
4
5// Once, at your own signup.
6const { result: customer } = await unprice.customers.signUp({
7 name: "Acme Inc.",
8 email: "[email protected]",
9 planSlug: "pro",
10})
11
12// Day one: read-only. Log what Unprice would have decided
13// next to the answer your own logic gave.
14const { result } = await unprice.access.check({
15 customerId: customer.customerId,
16 featureSlug: "tokens",
17})
18
19log({ 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.

usage.consumeone request · ingests and denies atomically at the limit
runs.start / consume / endone workload · reserves a budget up front, stops itself when spent
The two calls above are the integration the walk-away guarantee is written against — read-only, blocking nothing.Explore the request-path SDK
  1. 01

    Shadow

    Run the decision beside the logic you already trust. Compare answers without changing behavior.

    runsaccess.check
    mutatesnothing · read-only
    blocksnothing
  2. 02

    Sandbox

    Prove the path before a dollar moves — model customers, plans, and budgets.

    processornone · built-in Sandbox
    customerssimulated
    evidencereal · inspectable
  3. 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 · always
    unpricenever in the middle
05The questions

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
06The offer

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

The walk-away guarantee

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]