Skip to content

Installation

  • 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-dompdf for PDF invoices and receipts (or bind your own renderer, see Invoices)
  • Optional: ext-intl for localized money formatting (Money::format() falls back to 1299.00 UAH without it)
Terminal window
composer require fomvasss/laravel-billing

The service provider and the Billing facade alias are auto-discovered.

Migrations are published, not auto-loaded, in groups — publish only the tables you use:

TagTablesNeeded for
billing-migrations-corebilling_webhook_calls, billing_paymentsEveryone
billing-migrations-subscriptionsbilling_plans, billing_prices, billing_subscriptionsSubscriptions
billing-migrations-payment-methodsbilling_payment_methodsSaved cards, including subscription renewals
billing-migrations-invoicesbilling_invoices, billing_document_sequencesInvoices and receipts
Terminal window
php artisan vendor:publish --tag=billing-migrations-core
php artisan vendor:publish --tag=billing-migrations-subscriptions # Plan / Price / Subscription
php artisan vendor:publish --tag=billing-migrations-payment-methods # saved cards
php artisan vendor:publish --tag=billing-migrations-invoices # invoices and receipts
php artisan migrate

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

Publish the config when you need to change more than the .env covers:

Terminal window
php artisan vendor:publish --tag=billing-config

Every 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/success
BILLING_RETURN_URL_FAILED=https://example.com/checkout/failed
MONOBANK_TOKEN=...
TagWhat
billing-configconfig/billing.php
billing-invoice-viewsInvoice/receipt Blade templates → resources/views/vendor/billing/invoices
billing-langInvoice translations (uk, en, pl, de) → lang/vendor/billing

Renewals, reconciliation of lost webhooks, trial expiry and webhook pruning are scheduled commands, off by default because they move money:

BILLING_SCHEDULE_ENABLED=true

The 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=redis
BILLING_QUEUE=billing

See Webhooks → Queue.

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:

Terminal window
php artisan billing:stripe-register-webhook
php artisan billing:paddle-register-webhook

APP_URL must be your public HTTPS URL — the callback URL is built from it. See Webhooks and the gateway pages.

In local and testing the fake gateway is registered automatically — see Fake gateway.