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 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.