Stripe billing for Symfony 7.x and 8.x, inspired by Laravel Cashier.
composer require makfly/stripe-cashier-bundle
php bin/console cashier:installThe installer creates the missing bundle files and directories:
config/packages/cashier.yamlconfig/packages/cashier_doctrine.yamlconfig/routes/cashier.yaml- Stripe env vars in
.env var/datavar/data/invoices
| Dependency | Version |
|---|---|
| PHP | ^8.2 |
| Symfony | ^7.0 or ^8.0 |
| Doctrine ORM | ^3.0 |
| Stripe PHP SDK | ^16.0 |
ext-intl is recommended, but not required.
Without intl, the bundle still works:
- currency formatting falls back safely
- invoice dates fall back to ISO format
- invoice translations still work for shipped locales
With intl, invoice rendering is cleaner and more locale-aware.
cashier:
key: '%env(STRIPE_KEY)%'
secret: '%env(STRIPE_SECRET)%'
path: cashier
webhook:
secret: '%env(STRIPE_WEBHOOK_SECRET)%'
tolerance: 300
currency: usd
currency_locale: en
default_subscription_type: default
invoices:
renderer: CashierBundle\Service\InvoiceRenderer\DompdfInvoiceRenderer
default_locale: en
supported_locales: ['en', 'fr']
storage:
driver: local
path: '%kernel.project_dir%/var/data/invoices'The bundle can:
- read Stripe invoices
- render a PDF through the configured renderer
- archive paid invoice PDFs to
var/data/invoices - persist invoice archive metadata in
cashier_generated_invoices
Stripe Checkout sessions created by the bundle propagate checkout metadata to invoice creation metadata. That makes it easier for consumer applications to link:
- checkout session
- payment intent
- Stripe invoice
- archived PDF
- local order or booking
For deterministic consumer-side linking, use explicit metadata keys:
app_resource_typeapp_resource_idapp_user_idplan_codebilling_cycle
The archive service persists these values into cashier_generated_invoices so the consumer application can resolve invoices without amount/date heuristics.
You can customize invoices at four levels:
- override
templates/bundles/CashierBundle/invoice/default.html.twig - replace
cashier.invoices.renderer - replace
CashierBundle\Contract\InvoiceLocaleResolverInterface - replace
CashierBundle\Contract\InvoiceTranslationProviderInterface
For production storage, replace CashierBundle\Contract\InvoiceStorageInterface with your own implementation if invoices must be stored on S3, GCS, or any shared storage.
The bundle exposes POST /cashier/webhook and ships a local CLI helper:
php bin/console cashier:webhook:listen --forward-to --base-url http://localhost:8000This command forwards Stripe CLI events, persists the signing secret, and colorizes incoming events and HTTP responses.
Source documentation lives in docs/ and the main sections are:
- introduction
- installation
- configuration
- customers
- payments
- subscriptions
- checkout
- invoices
- webhooks
- events
- commands
- twig
- API reference
The documented configuration under cashier.*, documented commands, documented public contracts, and documented events are the supported public API surface.
Breaking changes should only be released in a new major version.