Installation
Requirements
Section titled “Requirements”- PHP ^8.3
- Laravel ^12 | ^13
- MySQL/MariaDB, PostgreSQL or SQLite — the package uses no raw SQL, and its test suite runs on SQLite and PostgreSQL
- Optional:
barryvdh/laravel-dompdffor PDF invoices and receipts (or bind your own renderer, see Invoices) - Optional:
ext-intlfor localized money formatting (Money::format()falls back to1299.00 UAHwithout it)
Install
Section titled “Install”composer require fomvasss/laravel-billingThe service provider and the Billing facade alias are auto-discovered.
Migrations
Section titled “Migrations”Migrations are published, not auto-loaded, in groups — publish only the tables you use:
| Tag | Tables | Needed for |
|---|---|---|
billing-migrations-core | billing_webhook_calls, billing_payments | Everyone |
billing-migrations-subscriptions | billing_plans, billing_prices, billing_subscriptions | Subscriptions |
billing-migrations-payment-methods | billing_payment_methods | Saved cards, including subscription renewals |
billing-migrations-invoices | billing_invoices, billing_document_sequences | Invoices and receipts |
php artisan vendor:publish --tag=billing-migrations-corephp artisan vendor:publish --tag=billing-migrations-subscriptions # Plan / Price / Subscriptionphp artisan vendor:publish --tag=billing-migrations-payment-methods # saved cardsphp artisan vendor:publish --tag=billing-migrations-invoices # invoices and receiptsphp artisan migrateFiles are copied under fixed names, so re-running vendor:publish skips a migration that is already there instead of duplicating it.
All tables use UUID (v7) primary keys. Morph columns (payable_id, billable_id) are string(64), so your models may have integer or UUID keys.
Config
Section titled “Config”Publish the config when you need to change more than the .env covers:
php artisan vendor:publish --tag=billing-configEvery key is described in Configuration. The minimum for a real gateway is its credentials and the return URLs:
BILLING_RETURN_URL_SUCCESS=https://example.com/checkout/successBILLING_RETURN_URL_FAILED=https://example.com/checkout/failed
MONOBANK_TOKEN=...Other publish tags
Section titled “Other publish tags”| Tag | What |
|---|---|
billing-config | config/billing.php |
billing-invoice-views | Invoice/receipt Blade templates → resources/views/vendor/billing/invoices |
billing-lang | Invoice translations (uk, en, pl, de) → lang/vendor/billing |
Scheduler
Section titled “Scheduler”Renewals, reconciliation of lost webhooks, trial expiry and webhook pruning are scheduled commands, off by default because they move money:
BILLING_SCHEDULE_ENABLED=trueThe usual Laravel cron entry (php artisan schedule:run every minute) must be running. See Scheduled commands.
Incoming webhooks are processed by a queued job. A worker must consume the queue — with no worker, webhooks are stored but payments never become paid:
BILLING_QUEUE_CONNECTION=redisBILLING_QUEUE=billingSee Webhooks → Queue.
Webhooks
Section titled “Webhooks”Every gateway posts to one route, POST /billing/webhooks/{gateway}. Monobank, LiqPay, WayForPay and Hutko receive the URL with every charge request — nothing to configure. Stripe and Paddle need it registered on their side once:
php artisan billing:stripe-register-webhookphp artisan billing:paddle-register-webhookAPP_URL must be your public HTTPS URL — the callback URL is built from it. See Webhooks and the gateway pages.
Try it without a bank
Section titled “Try it without a bank”In local and testing the fake gateway is registered automatically — see Fake gateway.