A plan is a stored object that compiles to a route on every run. It sets the price, the allowance, what happens past it, which compute it may use, and what a user earns for connecting their own.
Pricing and routing are the same decision, so they are the same object. A plan says
what a user pays and what their runs are allowed to run on, and it compiles to a
route on every request.
The shape#
Build plans in the dashboard's plan builder, which previews the pricing card as your
users will see it, or through the API. Either way these are the fields:
| Field |
What it sets |
priceModel |
free, flat, per_message, per_token, prepaid |
priceMicros |
The price, in integer micros |
interval |
month or year |
unit |
What an allowance is counted in: message, run, token, seat |
includedUnits |
What the price already covers. Null means unlimited |
overage |
stop or meter |
overageMicrosPerUnit |
What a unit costs past the allowance, when metering |
trialDays |
|
routePrefer / routeAllow |
The compute dimension: which cost classes a run on this plan may use |
maxCostMicros |
The ceiling on one run, not on a month |
connectedReward |
What the user gets for bringing their own compute |
maxCostMicros is per run
Only the metered classes can spend it, so it means nothing on a plan that allows none
of them. Null is no ceiling, which is the honest default: a zero would read as "spend
nothing" and stop every metered run.
Priced at your rate, not at cost#
Metering is cost accounting: what a run actually consumed, in micros, stamped with
its cost class. Billing is a different number, and it is yours.
Every user carries a ledger priced at your rate. A per_message plan at your price
bills the same whether the run cost you nothing or your app served it, because what
the run cost to serve is your margin, not your customer's concern.
The connected reward#
The one lever that moves the rate the whole product rests on: what a user gets for
connecting their own compute.
connectedReward |
|
none |
Nothing |
unlimited |
The cap comes off while they are connected |
included |
A larger allowance, set by connectedIncludedUnits |
credit |
Money back per interval, set by connectedCreditMicros, issued as a credit on the user's Stripe balance |
Three rules are built into the model rather than left to the customer:
One reward, not a set. A plan picks one, so there is one promise on the pricing
card rather than two.
Earned, not switched on. Pairing a machine that never wakes earns nothing. For
unlimited that is enforced on every run: the cap is lifted for a run the user's own
compute is actually serving, and for nothing else, so the reward cannot be collected
by a laptop that stays shut. included holds while a machine is connected, because a
larger allowance is a promise about the month rather than about one run. credit is
assessed at renewal, against how much of the period's work their own compute served.
A credit, never a surcharge. Given as money back rather than taken away, so a user
who disconnects stops earning instead of watching their price go up.
Note that unlimited and included spend your cost saving as allowance, which
costs you nothing when the runs are free to serve. credit spends it as money,
which is easier to advertise and dearer to give.
Where the user meets it
unlimited and included are enforced at dispatch, so a plan carrying one really
does refuse a run past its allowance and really does let a machine-served run
through. That is what <SobaPlans /> advertises on the pricing
card and what <RunLimit /> offers at the moment a run is
refused. credit is stored and shown, and is not charged yet: it needs the payments
rail below.
Codes#
A code grants a plan for a period. It carries its own ceiling, the number of times it
can be redeemed, so a code that leaks stops at a number you chose rather than at
whatever the internet does with it.
Payments#
Payments run in your own Stripe account, not Soba's. Soba connects to it as a Stripe
App, compiles each plan into the products and prices it needs there, runs checkout and
reports usage. Payouts, tax, refunds and disputes stay with you.
Soba takes no percentage and no application fee, so what your user pays arrives in your
account in full and Soba never holds or moves your money. Soba invoices you separately,
for Soba. See Stripe and Pricing.
Render the whole thing with <SobaPlans /> and <SobaCheckout />,
or drive it yourself through the API.
The number to watch#
Your dashboard leads with inference you didn't pay for this month, auditable
against your own provider bill. It is the figure a plan exists to move, and no gateway
can compute it.