Funding & allowances
fs.included / fs.prepaid / fs.promo / fs.referral — the buckets that pay rated charges before anything is owed, and how they display, expire, and refund.
fs.included / fs.prepaid / fs.promo / fs.referral — the buckets that pay rated charges before anything is owed, and how they display, expire, and refund.
A funding bucket is rated value the subscriber can spend before amount due begins. Buckets are denominated in money internally (nanodollars), so an allowance is worth the same across models, dimensions, and rate changes. The bucket kind is the constructor — there is no label heuristic and no plan-level credit policy.
funding: {
buckets: [
fs.included(fs.money.usd(10)),
fs.prepaid(fs.money.usd(25), { topUp: true }),
fs.promo(fs.money.usd(5)),
fs.referral(fs.money.usd(5)),
],
}
Constructors take money first and never take a string label.
| Kind | Constructor | Source | Cash-backed | Refundable to the rail | Ledger contra account |
|---|---|---|---|---|---|
included | fs.included(amount, { display? }) | plan issuance | no | no | IncludedAllowanceContra |
prepaid | fs.prepaid(amount, { topUp? }) | subscriber pays | yes | yes | none — PrepaidLiability |
promo | fs.promo(amount) | platform issues | no | no | PromoContra |
referral | fs.referral(amount) | platform issues | no | no | ReferralContra |
display.topUp: true lets the platform offer
replenishment; a top-up moves pending → available when the rail confirms
payment, and admission reserves only against available value. Required (and
the only kind allowed) on prepaid plans. Initial purchase uses the
managed plan checkout. Refills use the signed-in subscriber session and
the public Frontend SDK fs.core() handoff; see the
prepaid wallet cookbook
and top-up HTTP contract.When a rated charge lands, eligible buckets pay it in one total order:
(priority, expiresAt ASC nulls-last, promo < referral < included < prepaid, bucketId)
Cheapest-to-the-builder value goes first, soonest-expiring first within a priority, and the bucket id is the final tie-break — never database order or arrival time. Allocation runs against an epoch-versioned snapshot of the subject's buckets so concurrent charges cannot double-spend.
The gateway's monetary reservation is an admission bound; the durable funding claim is a bucket hold:
availableNanos = balanceNanos − heldNanos
Reserving moves value from available to held; capturing decreases both; releasing returns value to available unless the bucket expired while held, in which case the expiry posting runs atomically. An expiry sweep can never take a hold.
UsageRevenue, role
BREAKAGE).RECONCILIATION_REQUIRED, which blocks
monetary admission until reconciliation clears it.An included bucket may carry a multiplier display:
fs.included(fs.money.usd(25), {
display: fs.display.multiplier({ factor: 5 }),
});
The display accepts only factor; the base is derived as amount / factor
($5 here). Combined with spendPolicy.disclosure: fs.disclosure.opaque, every
subscriber surface — the portal and the
bill preview API — shows the allowance as
factor display units with remaining and consumed units, and never a
nanodollar amount. Without a display, an opaque plan shows the consumed and
remaining fraction in basis points. transparent (the default) exposes
per-window rated totals and bucket balances.
spendPolicy.onExhaustion decides what happens when no eligible bucket can
pay:
fs.exhaustion.block — the gateway denies credit_exhausted (402) until a
top-up lands or the next issuance. Required on prepaid plans.fs.exhaustion.overage(pricing.current()) — usage continues and is rated at
the named catalog as amount due. Required on hybrid plans; the binding must
name the same pricing family as usagePricing.Overage after exhaustion happens mid-period with no plan transition and no release event.
A top-up on a topUp: true prepaid bucket is a Stripe payment; the bucket
becomes spendable only when the rail confirms it (pending → available).
There is no builder or subscriber API that mutates a bucket balance directly —
every balance change is a ledger posting, and bucket balances are reconciled
against the ledger on a schedule.