Credits And Billing
The ledger
Append-only. Entries are never updated or deleted — a correction is a new adjustment row, which keeps the whole history auditable.
Every write takes a row lock on the team inside a transaction, so two concurrent
generations cannot both read the same balance and overspend. The denormalized
teams.credit_balance is updated in the same transaction, so the two can never
disagree.
CreditLedger::replayBalance() recomputes from history if you ever need to
reconcile.
Reserve, then settle
A generation reserves credits before the provider is called and settles against real token usage afterwards:
- Costs less than reserved → the surplus is refunded
- Costs more → the shortfall is charged without a balance check; the work is already done, and a negative balance simply blocks the next run
- Fails → the whole hold is released
Publishing is charged only when a build succeeds.
Gateways
Stripe for direct card billing. Paddle as merchant of record — it collects and remits international VAT, which is not a reasonable thing to build into a self-hosted script.
Both sit behind BillingProvider, so subscription handling, plan assignment and
the monthly allowance behave identically whichever you configure.
Webhooks
Unauthenticated by necessity, so treated as hostile:
- The signature is verified before the body is read as anything but bytes
- Stale timestamps are refused, so a captured payload cannot be replayed later
- Every event is recorded; a
(provider, event_id)unique index makes a redelivery a no-op - An event that was received but never processed is retried — a failed handler is not silently swallowed
Point your gateway at POST /webhooks/stripe or POST /webhooks/paddle.
The allowance
Plan credits are granted once per billing period, keyed on the period start. A redelivered invoice webhook cannot double-grant — the single most expensive bug a billing integration can have.
Turning it off
LOOM_CREDITS_ENABLED=false removes metering entirely. A Regular licence keeps
billing off regardless, since it covers one end product whose users are not
charged.