
Stripe Billing for B2B SaaS — Per-Seat, Usage, Enterprise Invoicing
Per-seat plus usage on one subscription, NET-term invoices with PO numbers, EU reverse-charge VAT, and an enterprise tier that does not fork your codebase.
The problem
B2B SaaS billing breaks at the seam between self-serve and enterprise. The self-serve side runs on Stripe Subscriptions with a credit card on file, per-seat pricing, maybe some metered usage on top — clean, automatic, the kind of integration a single engineer ships in a sprint. Then the first six-figure deal lands and the procurement requirements show up.
Procurement-side invoicing requirements
Finance needs NET 30 or NET 60 invoicing with a PO number printed in the header. Legal needs a custom contract with negotiated discount tiers and an enterprise-only SLA. The buyer is in Germany and needs reverse-charge VAT on the invoice or their AP team will not pay it. Each requirement is one line in a contract and one architectural decision on your side.
Enterprise tier as a parallel code path
The product team wants a different feature flag tree for the enterprise tier, and the natural reflex is to fork the billing code into an "enterprise mode" that runs alongside self-serve. The result is two systems of record that drift over the next year, two quarters of engineering that does not ship anything customers actually wanted, and a finance cost that compounds every quarter the spreadsheet reconciliation gets harder.
Fragmented revenue view
The CFO wants one revenue report that shows per-seat MRR, usage overages, and NET-term invoiced revenue in the same view rather than three spreadsheets reconciled by hand at month end. Stripe holds the transactions; your contract context lives somewhere else; the reconciliation lives in an analyst's head until they leave.
The right shape is the opposite of the fork: one billing system that handles both surfaces, with enterprise behavior expressed as configuration on Stripe primitives rather than as a separate code path.

What changes for your business
A B2B-aware Stripe architecture leans on Stripe's existing primitives harder than most teams realize.
Licensed-plus-metered on one subscription
Per-seat pricing rides on a licensed subscription item where quantity maps to seats; usage rides on metered prices on the same subscription with Meter Events posted from your backend. Both bill on the same invoice against the same customer. Self-serve cards and enterprise invoices ride the same model — the prices, coupons, and collection methods change; the model does not.
Enterprise invoicing on Stripe primitives
Enterprise invoicing is the same subscription with collection_method set to send_invoice instead of charge_automatically and days_until_due set to whatever the contract specifies — 30 days, 60 days, sometimes 90. The PO number lives in a customer-level custom field that inherits onto every draft invoice, so the field gets configured once at contract signing and finance does not retype it monthly. Negotiated discounts attach as Stripe coupons. Reverse-charge VAT applies automatically when a valid tax ID sits on the customer object and the jurisdictions support it.
Enterprise tier as feature flag, not fork
The enterprise tier itself is not a separate codebase — it is a feature flag and a different price ID. Self-serve customers and enterprise customers run on the same subscription model, the same metered prices, the same webhook handlers; what differs is which Stripe prices the subscription holds, which coupon attaches, which collection method governs payment, and which capability flags resolve from the subscription's metadata at runtime. The contract surface lives in Stripe and in a small contract table on your side, not in branching application code.
Append-only revenue ledger with contract context
Behind that surface sits an append-only revenue ledger in your own database, populated by idempotent webhook handlers keyed on Stripe event.id. The ledger captures every revenue-affecting event — subscription changes, invoice finalization, payment success and failure, refunds, credit notes — and joins them to the contract context Stripe does not hold: PO references, renewal terms, custom discount agreements, the sales rep who closed the deal. Finance queries that ledger instead of Stripe directly, which means month-end reporting is a query rather than a reconciliation, and the spreadsheet exports stop. Audit trails are clean because the ledger is append-only and every row points back to the Stripe event that produced it.
The outcome is a billing system that absorbs procurement complexity instead of forking under it. Closing an enterprise deal stops being a multi-quarter engineering project and becomes a contract configuration. The finance team sees one revenue picture across self-serve cards, per-seat invoices, and usage overages. The product team ships features against feature flags without thinking about billing. And the next enterprise deal, the one with a different discount structure or a different invoicing cadence, lands on the same primitives as the last one.

What gets shipped for B2B-specific billing
The work for a B2B SaaS at this intersection lands in a predictable shape. The combined pricing model goes in first — one subscription per customer carrying a licensed per-seat price for the platform component plus one or more metered prices for usage components, with proration_behavior set deliberately for mid-cycle seat changes so adding ten seats on day 12 does not surprise the buyer. Meter Events get posted from a single chokepoint in your backend, downstream of the business logic that determines what counts as billable usage.
The enterprise invoicing surface ships next. The collection_method gets switched to send_invoice for enterprise accounts, days_until_due is set per contract, and customer-level custom fields hold the PO number and any other procurement-required references — contractor number, cost center, tax compliance ID. Negotiated discounts attach as Stripe coupons rather than as custom price objects, which keeps the price catalog clean and makes the discount auditable in Stripe directly. Stripe Tax is enabled with tax ID collection at signup and contract time, so reverse-charge VAT applies automatically when an EU or UK B2B customer presents a valid VAT ID.
The enterprise feature tier ships as flags, not as a fork. A small capability resolver reads subscription metadata at request time and answers questions like "does this account get SSO," "what is their API rate limit," "do they have the advanced audit log." Self-serve and enterprise run the same handlers; the resolver decides what they see. New enterprise capabilities ship by adding a flag to the resolver and a metadata field to the relevant subscriptions, not by branching a code path.
The local revenue ledger ships last and is the piece finance actually cares about. Idempotent webhook handlers keyed on event.id write every revenue-affecting event into an append-only table, joined to the contract context — PO number, renewal date, discount terms, sales rep, contract document URL — that lives in a small contract table on your side. Reporting runs off this ledger. The result is a billing surface that handles per-seat plus usage, self-serve plus enterprise, automatic plus invoiced, single-currency plus multi-jurisdiction, without requiring the engineering team to think about billing again after launch.
Proof this pattern lands
BoostFrame Enterprise AI runs seven production applications on a Stripe billing stack we built ourselves — including a dual-pool credit system with metered consumption, subscription tiers, and webhook reconciliation that has run without a duplicate-charge incident across the live customer base. The same primitives that hold BFEAI's billing together — combined licensed-plus-metered subscriptions, idempotent webhook handlers, an event.id-keyed dedup store, and a local revenue ledger — are the ones a B2B SaaS needs to absorb procurement complexity without forking. The B2B-specific work — enterprise invoicing terms, custom field inheritance for POs, reverse-charge VAT, feature-flag enterprise tiers — is the part we architect against your existing contract flow rather than something we bring in pre-built. The author is Bill Fackelman, co-founder and CTO of BoostFrame Enterprise AI.
Outcomes you should expect
What this delivers
- Enterprise deals close without a multi-quarter billing fork — custom pricing rides on the same Stripe primitives as self-serve.
- Finance stops asking for spreadsheet exports because per-seat MRR, usage overages, and NET-term invoices land in one revenue view.
- EU and UK B2B invoices apply reverse-charge VAT automatically when a valid tax ID is on the customer, so cross-border deals stop blocking on tax questions.
Industry data
By the numbers
Stripe defines per-seat pricing as a linear model where the number of seats maps to the number of units, and quantity can only be specified on recurring prices with usage_type=licensed — which is the same subscription item that supports proration on mid-cycle quantity changes.
Stripe only creates prorations for changes that affect billable amounts in the current cycle on licensed (per-seat) subscriptions because they are billed at the start of each billing period, so seat adds and removals mid-cycle have to be modeled explicitly.
Stripe invoices allow up to four custom field key-value pairs that display in the invoice header and can be set at the customer level so they inherit onto every draft invoice — the supported pattern for PO numbers, contractor numbers, and tax compliance references.
The send_invoice collection method generates an invoice for manual payment instead of charging automatically, and the days_until_due parameter sets the payment window — the mechanism behind NET 30 and NET 60 terms on Stripe.
Stripe Tax automatically applies the reverse charge based on the presence of a tax ID and the jurisdictions involved in the transaction, and the seller's invoice specifies that the transaction is subject to reverse charge and does not include tax in the total amount.
Live in production today
The same engineering, shipped in production at BFEAI.
I'm co-founder & CTO of Be Found Everywhere (BFEAI), a 7-app AI SaaS platform running today. The work I deliver for clients is the work I do every week on my own platform.
7
Production apps
200K+
Keywords generated
1,500+
AI scans run
7,000+
Sites automated
Common questions
What buyers ask before reaching out
Can Stripe handle per-seat plus usage on the same subscription, or do we need two products?
One subscription, multiple prices. The clean model is a single Stripe subscription on the customer with a per-seat (licensed) price for the platform component and one or more metered prices for the usage components — API calls, jobs run, storage, AI tokens, whatever you sell on consumption. The per-seat side bills in advance with proration on quantity changes; the metered side bills in arrears off Meter Events your backend posts as usage clears. Both land on the same invoice, against the same customer, with the same metadata schema. The mistake teams make is creating a second Stripe customer for the usage product, which then breaks the revenue view and the enterprise contract flow.
How do mid-cycle seat changes get billed without surprising buyers?
Stripe only creates prorations on licensed (per-seat) subscriptions because those bill at the start of each period, so adding ten seats on day 12 of a 30-day cycle generates a prorated charge for the remaining days. The default behavior charges immediately, which is correct for most B2B contracts but can blindside buyers who expected a clean monthly invoice. The architecture choice is whether to default to immediate charge, defer to next invoice, or expose proration_behavior as a per-customer setting for enterprise accounts that negotiated specific terms. Whichever you pick, the rule has to live in one place and be visible to support.
Buyers want NET 30 or NET 60 invoicing with a PO number. Does Stripe support that out of the box?
Yes, with two primitives. Setting the subscription's collection_method to send_invoice swaps automatic card charging for an emailed invoice the buyer's AP team can pay on their schedule, and days_until_due controls the payment window — 30, 45, 60, whatever the contract says. PO numbers ride in invoice custom fields, which support up to four key-value pairs in the invoice header. Setting the PO field at the customer level means it inherits onto every draft invoice the contract generates, so finance does not have to retype it monthly. The pattern is one Stripe customer per enterprise account with NET terms and PO custom fields configured once at signing.
How do you handle custom enterprise plans without forking the codebase?
The enterprise tier should be a feature flag and a different Stripe price, not a different code path. Self-serve customers and enterprise customers run on the same subscription model with the same metered prices; what differs is the price IDs, the discount coupon, the collection method, and a small set of capability flags resolved at runtime from the subscription's metadata. Negotiated discounts go in as percentage-off or amount-off coupons attached to the subscription, custom contract terms ride in metadata your authorization layer reads, and enterprise-only features unlock from those flags. The codebase stays one codebase; the contract surface lives in Stripe.
How does EU and UK reverse-charge VAT work for B2B?
Stripe Tax applies the reverse charge automatically based on the presence of a valid tax ID on the customer and the jurisdictions in the transaction — when a UK seller invoices a German B2B customer with a valid VAT ID, the invoice specifies reverse charge and tax does not get added to the total. The buyer self-accounts for the VAT on their side. The integration work is collecting the tax ID at signup or contract time and storing it on the Stripe customer, plus surfacing the validation status in your admin UI so a sales op knows whether a deal is invoice-blocked on a pending VAT check. Stripe validates EU VAT and GB VAT asynchronously against government databases; you decide whether to gate invoice send on a passing check.
Finance keeps asking for spreadsheet exports. What does an audit-friendly setup look like?
Every revenue-affecting event lands in one append-only ledger inside your own database, populated by idempotent webhook handlers keyed on Stripe event.id. The ledger holds subscription changes, invoice finalization, payment success and failure, refunds, credit notes, and the customer and contract IDs joining them. Finance queries that ledger, not Stripe directly, and reconciles it against Stripe's reporting on a schedule. The reason for the local ledger is that Stripe is a source of truth for transactions but not for your contract semantics — discounts, PO references, contract dates, and renewal terms live on your side. Once that ledger exists, the spreadsheet asks stop because the answer is a query.
Multi-product subscriptions — can one customer hold a Pro plan plus an Add-on plus usage on the same Stripe account?
Yes. A Stripe subscription holds multiple subscription items, each with its own price, and you can mix licensed and metered usage_types on the same subscription. The constraint is that all items share one billing cycle, one collection method, and one currency on that subscription, so when you need a different cycle or currency for one of the add-ons you split it into a second subscription on the same customer. Multiple subscriptions per customer is supported and the right shape for cases like an annual platform plan plus a monthly add-on.
How long does this take to stand up for a B2B SaaS already on Stripe?
For a team already running Stripe Subscriptions for self-serve, layering enterprise invoicing — NET terms, PO custom fields, reverse-charge tax, the local revenue ledger, the feature-flag enterprise tier — is typically a focused multi-week engagement. Most of the time goes into the ledger design and the webhook idempotency work rather than into Stripe API calls. The variable is how clean the contract data model is on your side; if discount and renewal terms currently live in a sales spreadsheet, the project includes moving them into a model your authorization layer can read.
Ready to see if this is a fit?
A 15-minute call. No deck, no slides. We talk about what you're shipping and where engineering is the bottleneck. Either way, you walk away with a senior engineer's read on your situation.