Webhooks
Point your provider at the configured billing.webhook_path (default billing/webhook). Deliveries are
verified by signature, de-duplicated on the event id, and dispatched to registered effects. The shipped
effects sync the owner's plan, credit a one-time add-on exactly once, send a dunning notice, and persist each
finalized invoice.
Where a one-time add-on's credit lives depends on the driver. Where the provider keeps a customer balance, the credit is mirrored onto it, so the provider applies it against the next invoice by itself. Where it does not, the credit stays in this package's own ledger and the cycle spends it here. Either way the customer sees the balance in the account hub; what differs is who subtracts it.
The mirror points both ways, and it has to. When the provider applies some of that balance to an invoice, a shipped effect takes the same amount off this package's ledger against the persisted invoice record, under its own reason so a support agent can tell credit the package decided to spend from credit it learned had been spent. Without the return leg the local balance only ever grows: the account hub keeps showing money the provider already consumed, and a locally collected charge spends it a second time. The debit is keyed to the invoice record, so a redelivered event does not take it twice.
A driver that keeps no customer balance is untouched by this, and the reason is the first paragraph: it never mirrors anything out, so there is nothing to hear back. On that lane the package raises the invoice and spends the credit itself, which it already records — an effect that also fired there would be the same double subtraction with its sign flipped.
The boot-time secret guard is the hosted driver's, and deliberately not every driver's. Where the
provider signs every delivery, running without the signing secret in production is a silent failure — every
event fails verification, so plan changes simply stop arriving — and the package refuses to boot rather than
let that run. Where a provider still offers unsigned deliveries, refusing to boot would lock out every
install that has not migrated yet: there the secret is optional, an unsigned ping is authenticated by
fetching the resource back from the provider, and setting the secret is what turns an unsigned ping into a
refusal. See billing.mollie.webhook_secret in the
configuration reference for that switch.
Each effect runs as its own queued job, so one that throws no longer takes the ones after it down with it,
each retries on its own, and each leaves a record of what it did or still owes. A raw-payload ledger keeps
every delivery so a failed effect can be re-driven with billing:webhooks:replay --failed, rather than
depending on the provider to redeliver (which it stops doing after its own retry window).
For the neutral domain events these effects listen on, and how to listen or fake them in your own app, see the Event reference and the Testing guide.