memberflow/plorea
Plorea is a Laravel package for building membership workflows: define plans, manage member access, and add subscription-ready features to your app with a clean, configurable API. It streamlines gated content and member management.
->merchant(orgNr: ...), always the invoice issuer's, never the platform's). That is a product decision, not a technical one: it means funds and KYC sit with your customers, you stay out of money-transmission territory, and you can sell to gyms/clubs/studios who want their own payouts. If the roadmap instead assumes you collect and split revenue yourself, this package is the wrong primitive.RecurringType::Subscription) plus subscriptions()->needingAttention() unlocks recurring membership billing, dunning, card-expiry recovery, and failed-charge win-back — provided you accept that card setup, cancel and reactivate emit no webhook and require a scheduled poller.firstOrCreate() with per-reference locking, suffix chaining, and PaymentAlreadyPaidException supports a "resend invoice / pay now" loop without duplicating charges — useful for collections, reminders, and self-serve renewal.Consider it when most of these hold:
Plorea::fake() so payments are testable in CI and the API key never leaves the server, rather than hand-rolled HTTP against Adyen.Cache::lock() around link creation, queued webhook listeners that persist before processing, a polling backstop, and alerts on 4xx/ConnectionException.Look elsewhere when:
authorised is terminal.500 loses the event permanently. If you cannot guarantee persistence-before-ack plus a poller, this is the wrong rail.PLOREA_RETRY_TIMES=0 (retried link creation or charges double-bill).To executives: This is a revenue-enablement dependency, not a feature. It lets us invoice and take card payments for our customers' memberships — including recurring billing — without holding funds, obtaining a money-transmitter license, or owning KYC. Money routes to each customer's own org number; onboarding is triggered by their first payment and pays out 1–5 business days after approval, which we should surface honestly in the sales pitch. Time-to-first-paid-invoice is a config file plus one endpoint, against months for a bespoke integration. The strategic ask is small; the constraint to accept is that we are an early adopter of a thin vendor SDK, so we fund the reliability work (pollers, alerting, idempotent booking) as part of the launch, not after it.
To engineering: Laravel-native facade, typed DTOs, Plorea::fake() for CI, server-side sessions only, toCheckout() serialization so we never leak tenant/shopper/customer ids. Everything painful is on our side and must be scoped: per-reference locks and firstOrCreate() for link creation, idempotent booking (webhook, poll and return page all race), persist-then-process webhook listeners deduplicating on eventId, CSRF exclusion on the webhook path, a scheduled backstop for the events that are never emitted (card setup, cancel, reactivate, lost subscription.charge_failed), refund polling sized in hours, and alerts on 4xx plus stuck links and pending_setup past expiry. Do not expose capture(). Embedded/native checkout adds CSP for Adyen hosts, origin and app-id whitelisting, and a return page that completes redirectResult and strips it via history.replaceState.
To the delivery team / launch gate: Ship hosted links first, prove one low-value live payment per surface with a KYC-approved merchant, verify the webhook is booked exactly once, then run a refund. Add embedded checkout only when a customer-facing conversion problem justifies the whitelisting and CSP work; treat Android, native 3DS2, live environment and wallets as unproven until observed.
How can I help you explore Laravel packages today?