Skip to main content

Command reference

Scheduled commands

The service provider registers these for you:

CommandCadenceWhat it does
billing:usage:flushevery minuteReports recorded usage to the provider that bills it
billing:runhourlyAdvances the recurring cycle (a no-op under Stripe, which drives its own)
billing:dunning:advancedailyWalks the dunning ladder: escalating warnings + late fees
billing:cards:warndailyWarns owners whose card is about to expire
billing:usage:reconciledailyReads the provider's usage totals back and alarms on drift or recorded-but-unbilled usage
billing:prunedailyAges out stored webhook payloads and expired financial records

On-demand commands

php artisan billing:sync # reconcile subscriptions from the provider onto the local rows
php artisan billing:install # publish the config + generate the owner-columns migration
php artisan billing:webhooks:replay --failed # re-drive webhook effects that failed
php artisan billing:erase {owner} # erase an owner's billing data (see Data protection)
php artisan billing:export {owner} # everything the package holds about one owner, as JSON
php artisan billing:doctor # check your Stripe webhook endpoints render the pinned API version
php artisan billing:meters:check # verify every configured usage meter exists and is active at the provider
php artisan billing:usage:reconcile --redrive # (also scheduled daily) retry the rollups a flush gave up on
php artisan billing:tier:grant {owner} {tier} # comp an owner onto a tier out of band, recorded on the audit trail
php artisan billing:datev:export # a period of invoices as a DATEV EXTF booking batch (defaults to last month)
php artisan billing:marketplace:preflight # the multi-merchant go-live checklist: what still has to hold

Notes on exit behavior

billing:marketplace:preflight prints the go-live checklist that gates billing.marketplace.enabled — every point, in order, with what it found and why. It exits non-zero while a blocking point is open, so it fits a deploy check. Two things about it are worth knowing before you read a report.

Order is enforced, not suggested. A stage with an open blocking point makes every point after it UNREACHABLE rather than evaluating it, because publishing terms after the first sale is a different act from publishing them before it. An unreachable point is not a failure and emphatically not a pass: it is a point nobody ran.

A stage can be empty, and the report says so in words. Where nothing is registered you get "no checks are registered for this stage" instead of a green line — a stage that passes because it holds no checks would read exactly like a stage that passed.

The command is available whether or not the marketplace is switched on. It has to be: flipping the switch is the last step of the checklist, and with the switch on and a point open the application refuses to boot at all. That refusal names the open points itself, so the information is never out of reach.

billing:meters:check catches a metered tier whose provider_meter was never created, or was archived, at the provider — usage reported into a meter that does not exist fails silently, and the miss surfaces (if ever) as an under-charged invoice a month later. It exits non-zero when a meter is missing, so it fits a deploy check. billing:usage:reconcile answers "is there any recorded-but-unbilled usage right now?" — after fixing the cause (often a meter billing:meters:check found), --redrive returns the failed rollups to pending so the next flush retries them.

billing:sync is the bulk version of the post-checkout reconcile — use it to backfill after a webhook outage. It applies each subscription through the same plan-sync effect the webhook uses, so it can never overwrite a newer webhook state; it only moves a stale local row forward. Scope it with --owner, preview with --dry-run.

billing:tier:grant is the terminal form of a support comp (the same BillingAdmin::comp an admin panel calls): it writes the tier column directly and records the grant on the audit trail. It refuses a tier key no billing.tiers entry declares, and warns when the tier is not in billing.untouchable_tiers — because the next provider webhook is otherwise free to overwrite the grant.


← Back to the documentation index