Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Filament Billing Console Laravel Package

amjadiqbal/filament-billing-console

A Filament billing console for Laravel that adds an admin interface for managing plans, subscriptions, invoices, and payments. It integrates billing dashboards and actions directly into Filament panels, making it easier to oversee customer billing from one place.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Verdict: Low-cost, low-blast-radius addition worth a time-boxed pilot. The integration surface is a single Filament plugin registration, but it should be treated as a convenience UI over Cashier data and the Stripe API — not as a finance system of record. The two items that need engineering and finance sign-off before rollout are (a) how MRR/churn are computed and (b) what "Sync from Stripe" actually writes.

Architecture fit

  • Correctly scoped: a panel plugin, not a service. No migrations, no new tables, no queue workers, no scheduled jobs are announced — it reads existing Cashier customers/subscriptions tables and calls Stripe for invoices/charges. That is the right shape for a read-only ops console.
  • Fits the existing data model: identity is the Stripe customer ID already stored by Cashier; the customer page composes subscriptions (local) with invoices/payments (remote, cached). This is a pragmatic split, since Cashier does not persist invoices/charges locally.
  • Authorization is delegated to host-app primitives (authorizeUsing(), a viewBillingConsole gate, or model policies) rather than a bespoke role system. That is the correct choice — it inherits your existing RBAC and avoids a parallel permission model.
  • The one architectural wrinkle: "read-only" is accurate with respect to Stripe (no mutations to the Stripe account), but not with respect to your database — "Sync from Stripe" writes into Cashier tables. That dual nature needs to be understood and documented internally, because it is the only code path that can change local state.

Integration feasibility

  • Install is composer require plus one ->plugin(...) line on a panel provider. This is among the cheapest possible integrations and is reversible in one commit.
  • Test posture is stronger than typical for a v1.0.0 package: 40 Pest tests, PHPStan and Pint in CI, a PHP 8.2–8.5 × Laravel 12/13 × Filament 4/5 matrix, contract tests against Stripe's official stripe-mock, plus a 39-check browser pass per stack combination in light and dark mode. Contract testing against stripe-mock is the right technique for an API-dependent UI, though it validates against a mock's view of Stripe's schema, not your account's pinned API version.
  • Main feasibility question is not "can we install it" but "does its view of Cashier's schema match ours" — custom billable models, team/multi-tenant billing, or a customized Cashier schema are the likely friction points.

Technical risk

  • Vendor maturity (medium-high): v1.0.0, single-maintainer package, no commercial support, no stated deprecation/support policy. Bus factor is 1.
  • Version-matrix churn (medium): advertising Filament 4 and 5 plus Laravel 13 and PHP 8.5 implies a fast-moving target and a wide compatibility claim. Wide matrices are good for adoption but raise the odds that a Filament major release lands before the plugin catches up.
  • Runtime Stripe dependency (medium): the invoices/payments surfaces require live Stripe API calls. Latency, 429s, and API incidents become your panel's latency and incidents unless the cache and degradation behavior are acceptable. Caching is mentioned but TTL, invalidation, and cold-start behavior are unspecified.
  • Metric credibility (high business risk, low technical risk): "list-price MRR" is a deliberately simple definition. It does not, per the notes, account for discounts/coupons, proration, quantities, multi-currency, tax, or annual-plan normalization. If finance or the board ever screenshots that dashboard, a defensible methodology note is mandatory.
  • Stale-data risk (medium): local Cashier rows drift from Stripe whenever webhooks fail or are misconfigured. The plugin surfaces the drift as "past-due/unpaid" counters, so a broken webhook endpoint now silently corrupts a visible dashboard metric.
  • Data exposure (medium): the console renders customer PII and billing state. Delegated authz is good, but correctness depends on the host app wiring the gate/policy and the plugin enforcing it on every Livewire action and route, not just the nav item. Livewire endpoints are a classic place for a UI-level gate to be bypassed if the component re-checks nothing server-side.
  • Key handling (low): the secret key is reportedly never rendered, and test/live mode is inferred from the key prefix for "Open in Stripe" links. The residual risk is operational — a test-mode key in production silently showing test data, or a link sending staff to the wrong Stripe account.

Key questions

  1. What exactly does MRR sum — plan unit amount × quantity? Does it normalize annual plans to monthly, apply discounts, and handle multiple currencies (and if so, at what FX rate or as separate buckets)?
  2. Is churn defined as subscription cancellation count, revenue churn, or logo churn over the 30-day window, and does it include trial conversions and grace-period cancellations?
  3. Does "Sync from Stripe" invoke Cashier's webhook handlers in-process, and can it produce writes that a subsequent real webhook would duplicate, conflict with, or fail to reconcile? Is it idempotent? Is there a dry-run?
  4. How is authorization enforced — only on the Filament page/nav, or on every Livewire component action and the underlying query? Is there a test proving a policy-denied user cannot read another tenant's customer?
  5. What are the cache TTLs, the invalidation triggers, and the behavior when Stripe returns 429/5xx — empty state, stale state, or error?
  6. What is the supported Cashier version range and does it tolerate customized billable models, non-User billables, and multi-tenant/team billing?
  7. Does an "Open in Stripe" link expose any object ID or key material in a way that matters for audit or logging?
  8. License, support expectations, and maintainer responsiveness on issues — is this MIT and safe to vendor/patch?
  9. Are there query indexes assumed on stripe_id, email, and subscription status columns? What happens to the dashboard at 100k+ subscriptions?

Integration Approach

Stack fit

  • Assumes Laravel 12/13, Filament 4/5, and Cashier-for-Stripe. If any of those is off — notably a Laravel 11 or Filament 3 app — this is a non-starter until the app upgrades, and you should not upgrade Filament for this package.
  • Best suited to an existing admin/support panel where staff already have Filament accounts and roles, so the delegated gate/policy plugs into established RBAC rather than creating a new access model.
  • Not a fit if you need multi-currency revenue reporting, revenue recognition, dunning workflows, or any write actions against Stripe. Those remain Stripe Dashboard / a billing platform's job; this package intentionally links out to Stripe for anything deeper.

Migration path

  • No data migration. Nothing to backfill, no schema changes announced. Rollback is removing the plugin line and the composer dependency.
  • The only stateful operation is "Sync from Stripe." Treat it as a repair/backfill tool, not a routine sync: run it first in staging against test-mode keys, diff the resulting Cashier rows, and confirm it is idempotent before it is ever pressed in production. Keep Stripe webhooks as the primary write path.
  • If Cashier tables were populated by webhooks all along, the plugin should be additive from day one — the pilot should be pure read traffic.

Compatibility

  • Verify the package's composer constraints against your lockfile rather than trusting the advertised matrix, and confirm the Filament major you run is the one in the tested pair (Filament 4 + Laravel 12, or Filament 5 + Laravel 13).
  • Check your Stripe API version pin. Contract tests ran against stripe-mock 0.206.0; your account may be pinned to a different Stripe API version, and invoice/charge object shapes do drift.
  • Confirm your Cashier major version and whether you have customized the billable model or subscription table — this is the highest-probability incompatibility.

Sequencing

  1. Spike (0.5–1 day, staging): install with test-mode Stripe keys, register the plugin on a non-production panel, confirm it boots and that no routes/caches collide with existing panels.
  2. Security review (0.5 day): wire the gate/policy, then attempt access as a non-privileged user, a user from another tenant, and via direct Livewire request. Confirm the secret key never appears in HTML, JSON payloads, or logs.
  3. Data validation (0.5 day): compare customer/subscription counts against Stripe and against your own SQL; reconcile MRR against a spreadsheet built from your own data for one month.
  4. Sync rehearsal (staging only): run "Sync from Stripe" against a seeded test account, run it twice, and confirm idempotency and no divergence from webhook-written rows.
  5. Finance/support sign-off: publish the MRR and churn definitions alongside the dashboard; label the widget as list-price MRR if that is what it is.
  6. Pilot: enable via the gate for a small support/finance group, keep the Stripe Dashboard as the documented fallback, and watch error rates and Stripe API usage for two weeks.
  7. Decide on generalization: only then consider exposing it more broadly or relying on the metrics in reporting.

Operational Impact

Maintenance

  • Low code footprint, but you are accepting a dependency on a young, single-maintainer package in a fast-moving ecosystem (Filament majors, Laravel majors, Stripe API versions). Budget a recurring, small "is it still compatible?" check each time Filament or Laravel ships a major.
  • Mitigations: pin the exact version, read changelogs before bumps, and keep the integration isolated to one panel provider so an upstream break is a one-line revert. Confirm the license permits forking and patching internally.
  • The package's own test suite is a genuine asset here: if it ships CI config and the tests are runnable locally, you can fork and validate a patch yourself rather than waiting on upstream.

Support

  • No commercial support; expect GitHub-issue latency. Plan for the realistic answer to "the billing console is broken" being "use the Stripe Dashboard link" — which the plugin itself provides, so degradation is at least graceful and discoverable.
  • Internally, one engineer should own it as a named secondary responsibility. The support burden is mostly questions about the numbers, not bugs: "why does MRR say X?" is the ticket you will actually get, and it is answered by documentation you write, not by the vendor.

Scaling

  • Listing scales with Cashier table size: search by name/email/Stripe ID needs appropriate indexes, and the customer page composes subscriptions + payment method + invoices, which is a classic N+1 shape at list scale. Validate page-load time with a production-sized dataset, not a seeded demo.
  • The MRR/churn dashboard aggregates over subscriptions on every render unless cached — that is the most likely slow query in the whole plugin, and it sits on the panel's landing page. Watch it specifically.
  • Invoices/payments scale with Stripe API, not your DB: rate limits, pagination, and cache effectiveness dominate. Confirm the cache is shared (not per-request) and that a cold cache does not fan out one API call per row.
  • "Past-due and unpaid counted next to the menu item" implies a query or API call on every panel page load. Cheap at small scale, a persistent tax at large scale — check whether it is cached or evaluated on every navigation.

Failure modes

  • Stripe API degraded or rate-limited: invoices/payments views empty, stale, or error. Acceptable if it degrades visibly and does not take down the rest of the panel; unacceptable if an exception in a widget breaks the Filament page.
  • Webhook backlog or misconfiguration: local Cashier data drifts, and the console confidently displays wrong statuses and wrong MRR. Add monitoring on webhook delivery health; do not let this dashboard become the only signal that webhooks are broken (or, worse, the place people trust instead of them).
  • Sync misuse in production: concurrent sync plus live webhooks can produce duplicate or overwritten rows if the operation is not idempotent. Gate the action tightly and rehearse first.
  • Authorization misconfiguration: the most damaging failure — one role granted too broadly exposes every customer's email, plan, and invoice history. Verify server-side, per-action enforcement, and add a regression test rather than trusting the nav-item gate.
  • Key/mode confusion: a test key in production yields an empty or misleading console and "Open in Stripe" links pointing at the test account. Add a visible environment indicator or verify mode parity in the pilot checklist.
  • Upstream break on panel boot: a Filament major could make the plugin's service provider throw, taking down the whole panel rather than just the console. Pinning and staging upgrades contains this.

Ramp-up

  • Engineering: effectively zero — one composer line, one plugin registration, one gate. Half a day including the security check.
  • Support/finance users: low, provided you hand them two artifacts — a one-page definition of MRR and churn as computed here, and an explicit statement that the console is read-only against Stripe with "Open in Stripe" as the escalation path for any real action.
  • Organizational: the real ramp-up cost is social, not technical. Set expectations up front that this is an operational convenience view with a list-price MRR approximation, so it is not later promoted into a revenue-reporting source without re-deriving the numbers.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core