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

Laravel Payable Redirect Mollie Laravel Package

sander-van-hooft/laravel-payable-redirect-mollie

A Laravel package that adds Mollie payment redirect support to the Laravel Payable ecosystem, helping you wire up Mollie checkout redirects and payment flows with less boilerplate.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install the package. It lives in the sander-van-hooft/laravel-payable-redirect-mollie namespace and is a companion driver for sander-van-hooft/laravel-payable, so make sure that core package is also required at a compatible version.

    composer require sander-van-hooft/laravel-payable-redirect-mollie
    
  2. Publish config and migrations.

    php artisan vendor:publish --provider="SanderVanHooft\Payable\PayableServiceProvider"
    php artisan migrate
    

    Check config/payable.php (or whatever the published filename is) for the Mollie key, currency, and return-route settings. If both the core package and this driver ship migrations, only publish one payments table to avoid duplicate-table errors.

  3. Configure Mollie. Set MOLLIE_KEY in .env. For local/dev work use a test_... key, not a live live_... key — the test_ prefix is the sandbox switch, and it is easy to leave a live key in .env during testing.

  4. Mark a model as payable by adding the SanderVanHooft\Payable\Traits\Payable (or PayableRedirect-equivalent) trait. This gives the model a polymorphic payments relation.

    use SanderVanHooft\Payable\Traits\Payable;
    
    class Order extends Model
    {
        use Payable;
    }
    
  5. First use case — pay for an order with a redirect.

    Route::get('/orders/{order}/pay', function (Order $order) {
        return $order->payment()
            ->create(4999, 'Order #'.$order->id)   // amount in cents
            ->redirect();
    });
    

    The redirect() response is a Mollie checkout URL. After the customer pays, Mollie redirects back to the package's return route, which reads the payment status and updates the local Payment record.

  6. Where to look first. Read the driver's routes/*.php, the return controller, and the Payment model. Those three files are where 90% of behavior lives, and you'll need to know them to customize return handling or status mapping.

Implementation Patterns

Trait-based payments on any model

The core idea is that the trait makes any Eloquent model payable via a morph relation. Use this for orders, invoices, subscriptions, tickets — anything with a single settlement. Keep the business model (Order) separate from the Payment record; don't try to jam payment state back into Order beyond convenience accessors like $order->payments()->where('status', 'paid')->exists().

Redirect-then-verify flow

The idiomatic flow is:

  1. Create a payment on the payable model → local Payment row with status = pending and a Mollie ID.
  2. Redirect the customer to the Mollie checkout URL.
  3. Return through the package's return route, which loads the Mollie payment and updates local status.
  4. Reconcile in your own controller/observer: on paid, mark the order fulfilled; on failed/canceled, let the user retry.

Wrap steps 3–4 in your own listener or extend the return controller, because the package's default controller is intentionally minimal.

Idempotent "create" methods

A "pay" route should be safe to refresh. Either:

  • Let the user land on the checkout URL and only persist the payment when the redirect completes, or
  • Look up an existing pending payment for the payable model and reuse its checkout URL before creating a new one.
$payment = $order->payments()->where('status', 'open')->latest()->first()
    ?? $order->payment()->create($order->total_cents, $order->description);

return $payment->redirect();

Status sync via webhook or polling

The package (as of 2018) leans on the browser redirect, which is fragile — the customer can close the tab before returning. For anything production-grade, add a webhook handler or a scheduled reconciliation job that queries Mollie for each pending payment and re-derives status. Use the same mapping logic in both paths so a status is never set in two divergent ways.

Multi-model / polymorphic usage

Because payments() is a morph relation, the same payments table serves many payables. In reports, join via payable_type + payable_id carefully; payable_type is a full class name, so renaming or namespacing a model silently orphans rows. Add a morphMap in a service provider to stabilize this:

Relation::morphMap([
    'order' => \App\Models\Order::class,
    'invoice' => \App\Models\Invoice::class,
]);

Extension points

  • Custom Payment model — bind your own subclass extending the package's Payment in the container so you can add paid_at, provider_refund_id, etc.
  • Custom return controller — register your own route pointing at a controller that calls the package's completion logic, then does your domain work.
  • Events — listen for the package's payment status events if emitted; otherwise emit your own from the return handler.
  • Config overrides — currency, return URL, and the payable model class are typically all in config/payable.php (or payable-mollie.php in some versions).

Testing pattern

Use Mollie's sandbox or mock the client in Laravel tests:

  • Bind a fake Mollie\Api\MollieApiClient into the container.
  • Or feature-test against test_ mode with a payment ID you control.
  • Assert both the local Payment row and what you sent to Mollie (amount, description, redirect URL) to catch cents-vs-euros bugs early.

Gotchas and Tips

  • It is a 2018 package. Last release is Feb 2018, 21 stars, zero dependents. Assume Laravel 5.5–5.8 compatibility. Check the composer constraints before installing on Laravel 9/10/11 — you'll likely need composer require with --ignore-platform-reqs or a fork. Do not assume it works on current Laravel without an audit.

  • Two packages, one relation. laravel-payable-redirect-mollie is a driver for sander-van-hooft/laravel-payable. Version mismatches between the two are the most common install failure. Pin both and read the driver's composer.json.

  • Amounts are cents (integer). 4999 means €49.99, not €4999. Every "off by 100x" refund bug in packages like this comes from sending a decimal through an integer column or vice versa. Cast in your model accessor, not at the call site.

  • Currency is a config, not a parameter. Mollie infers currency from your account, but a mismatch between your configured currency and the amount can produce cryptic errors. For non-EUR shops, confirm config/payable.php (or the payment create() call) accepts a currency override before going live.

  • Return URL vs. APP_URL. The package builds the return URL from routing and APP_URL. Behind a proxy, custom domain, or in a subdirectory, the wrong scheme/host breaks the redirect. Set APP_URL, trust the proxy (TrustProxies), and verify with php artisan route:list that the return route exists with the expected name and methods.

  • Browser redirect ≠ payment confirmation. A user closing the tab leaves a pending row. Never fulfill an order from a redirect() call or from the client. Confirm via Mollie's API (webhook or scheduled poll). Treat paid status server-side as the only trigger for fulfillment.

  • Sandbox vs. live key is a one-character mistake. test_... and live_... differ only in prefix; swapping .env files is the #1 way to accidentally charge real money in staging. Add a boot-time guard that throws if APP_ENV !== 'production' and str_starts_with(config('payable.mollie_key'), 'live_').

  • Route collisions. The package registers its own routes; if you also define a /payable/* path or a payments route group, Laravel may pick the wrong one. Check order in routes/web.php and use php artisan route:list | grep payable.

  • Migrations may clash with the core laravel-payable migrations if both are published. Publish once, diff the files, and delete duplicates.

  • Debugging checklist:

    1. storage/logs/laravel.log — package exceptions are usually there.
    2. Mollie dashboard → is the payment visible (in test mode)?
    3. php artisan route:list | grep payable — does the return route exist?
    4. Payment row — status, mollie_id, payable_type, payable_id.
    5. Network tab — is the redirect URL actually a https://www.mollie.com/... URL?
  • Extension point to reach for first: overriding the return controller. It's smaller and safer than monkey-patching the package, and it lets you keep the driver for redirect creation while owning the post-return business logic.

  • Long-term viability. With zero dependents and a seven-year-old codebase, treat this as glue you may fork and maintain yourself. Budget time to either upgrade it (Mollie API v2, Laravel 10/11 support) or replace it with direct mollie/mollie-api-php calls plus a thin Payment model of your own.

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.
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib