johnrivera7/filament-flow
Filament Flow is a Laravel/Filament plugin for building and managing flow-based workflows directly inside your admin panel. Model multi-step processes, visualize progress, and move records between stages without leaving your existing resources, forms, and tables. Simple to install and extend.
php artisan migrate — Flow order/token persistence is what makes getStatus and refunds workable later.apiKey / secretKey / sandbox toggle from the UI rather than hand-editing .env. If your team prefers env-driven config, confirm the settings page falls back to config values before relying on it in CI.FlowGateway, call create() with an amount, commerceOrder, subject, email, and your return/confirmation URLs. Persist the returned token alongside your own order record before redirecting. Then send the user to the checkout redirect view (url?token=...).The three things to read first: the FlowGateway class (it's your whole public API), the credentials schema (to know what's configurable per panel), and the redirect blade view (to know what you can restyle).
Wrap the gateway, don't call it from controllers. FlowGateway is a thin HTTP client. Put it behind your own PaymentService or action class so your domain owns the order state machine and the gateway stays swappable/mockable in tests.
Model the token as first-class state. Treat the Flow token as the join key between your order and theirs. Store it with the order, index it, and use it as the idempotency handle for getStatus and refunds. Never rely on commerceOrder alone — mismatches between your ID and theirs are the most common source of "I paid but the order says pending".
Return flow: confirm, don't trust. Flow sends the user back to your url with ?token=.... Do not mark anything paid on that redirect. Call getStatus($token), verify the status and the amount/currency match your order, then transition state. Use the same code path for a scheduled reconciliation job that sweeps stale pending orders — Flow webhooks/confirmation URLs can be missed, and a poller is cheaper than support tickets.
Separate the three URLs deliberately. url (user return), urlConfirmation (server-to-server), and urlReturn are distinct concerns. Point confirmation at a queued, idempotent endpoint. Make every handler replay-safe: the same token will hit it more than once.
Email-first flows. createEmail() issues a payment request without a redirect — good for dunning, invoicing, or admin-initiated charges. Pair it with a Filament action on the order resource so support staff can resend a payment link without engineering.
Refunds as admin actions. Expose refund as a Filament table action on your order resource, guarded by policy, confirming amount, and writing the Flow response to an audit log. Start with full refunds only; partial refunds need a ledger of what's already been refunded per order or you'll double-refund.
Multi-panel / multi-tenant. Because credentials live in a settings page, the schema is reusable — you can scope credentials per panel or tenant. Decide early whether Flow credentials are global (simplest, recommended for v1) or per-tenant; the latter means the gateway must resolve credentials at call time, not at container build time.
Translations. ES/EN are bundled for the settings page and checkout view. Publish the lang files if you need to change wording, and check that Chilean-specific terms (RUT, CLP formatting) read correctly — the default English strings are a translation, not a localization strategy.
s parameter is computed over parameters sorted alphabetically and concatenated as key=value pairs (then appended as s). If the package does this for you, don't hand-roll requests; if you extend it, any parameter you add must be included in the signing set. A wrong signature returns an error that looks like an auth problem.s itself. Obvious in hindsight, a five-minute debugging session every time someone forgets.& break the signature if signed pre-encoding and sent post-encoding (or vice versa). Pass plain strings to the gateway and let it handle encoding; if you build a custom call, test with a subject containing ñ and &.1500.00 becomes a validation error or, worse, a 100× charge. Add a cast/validation rule at your order boundary rather than trusting callers.config() in a long-running queue worker to see a credential change made mid-deploy.create() call, not a retry of the old token. Surface "regenerate payment link" as a user-visible action.apiKey prefix on every gateway call at debug level, and add a boot-time guard that refuses to run production base URL with a key that looks like a sandbox key.create() is not safely retryable without idempotency — a timeout may mean the order was created. Wrap create in a guard keyed on your commerceOrder and reconcile via getStatus before retrying.Http:: facade or an injected client). If it does, you can Http::fake() in tests and add global middleware for logging. If it constructs its own client, you'll need to bind a fake implementation of the gateway itself — check before writing your test suite.How can I help you explore Laravel packages today?