Mollie verwerkt miljarden aan betalingen per jaar. Voor maatwerk betaalflows buiten het standaard Shopify/Magento-pad — subscription modellen, split payments, B2B-facturatie — is Laravel + Mollie de juiste combinatie.
Laravel + Mollie: betaalflows buiten Shopify en Magento
Mollie verwerkte in 2023 meer dan €30 miljard aan betalingen. Voor standaard webshops is de Shopify of Magento plugin voldoende. Maar zodra je afwijkt van het standaard checkout-pad — abonnementen, split payments, B2B-facturatie op 30 dagen, klantspecifieke betaalportalen — zijn de standaard plugins te beperkend.
Laravel + Mollie geeft je volledige controle over de betaalflow. Dit is hoe je het correct implementeert.
Wat je leert in dit artikel
- Mollie API integratie in Laravel via de officiële SDK
- Payment methods dynamisch ophalen en tonen
- Webhooks correct verwerken en beveiligen
- Refunds programmatisch uitvoeren
- Recurring payments en subscription-logica bouwen
Mollie SDK installeren en configureren
Mollie heeft een officiële PHP SDK die uitstekend werkt met Laravel.
composer require mollie/mollie-api-php
Wij wikkelen de SDK in een eigen service class. Zo hou je de Mollie-logica op één plek en kun je makkelijk testen via mocks.
// app/Services/MollieService.php
use Mollie\Api\MollieApiClient;
class MollieService
{
private MollieApiClient $mollie;
public function __construct()
{
$this->mollie = new MollieApiClient();
$this->mollie->setApiKey(config('services.mollie.api_key'));
}
}
Sla de API key op in .env. Gebruik een test-key tijdens development — Mollie heeft een uitgebreide test-omgeving met gesimuleerde betaalstatussen.
Payment methods: dynamisch ophalen
Mollie ondersteunt iDEAL, creditcard, Bancontact, SEPA, PayPal, Klarna en meer. Welke methoden beschikbaar zijn, hangt af van je Mollie-account en het betaalbedrag. Haal ze dynamisch op — niet hardcoden.
public function getBeschikbareMethoden(int $bedragInCenten, string $valuta = 'EUR'): array
{
$methoden = $this->mollie->methods->allActive([
'amount' => [
'value' => number_format($bedragInCenten / 100, 2, '.', ''),
'currency' => $valuta,
],
'locale' => 'nl_NL',
'sequenceType' => 'oneoff',
]);
return collect($methoden)
->map(fn($methode) => [
'id' => $methode->id,
'description' => $methode->description,
'image' => $methode->image->size2x,
'issuers' => $methode->issuers ?? [],
])
->toArray();
}
Voor iDEAL heb je de issuers nodig: de lijst met banken. Die zitten direct in het methode-object als je includeWallets=1 of de issuers embed meegeeft.
Betaling aanmaken
Een betaling aanmaken in Mollie is één API-call. Het kritieke punt is de webhookUrl — die moet bereikbaar zijn vanuit het internet, ook in testomgevingen (gebruik ngrok of een staging URL).
public function betalingAanmaken(Order $order, string $methode): string
{
$betaling = $this->mollie->payments->create([
'amount' => [
'value' => number_format($order->total_amount / 100, 2, '.', ''),
'currency' => 'EUR',
],
'description' => "Order #{$order->order_number}",
'redirectUrl' => route('checkout.bedankt', $order->uuid),
'webhookUrl' => route('webhooks.mollie'),
'method' => $methode,
'metadata' => [
'order_id' => $order->id,
'order_number' => $order->order_number,
],
]);
// Sla het Mollie payment ID op voor latere referentie
$order->update(['mollie_payment_id' => $betaling->id]);
return $betaling->getCheckoutUrl();
}
Stuur de klant door naar $betaling->getCheckoutUrl(). Mollie handelt de betaalinterface af en stuurt de klant terug naar je redirectUrl.
Webhooks correct verwerken
De redirectUrl is niet betrouwbaar voor betaalstatus. Een klant kan de tab sluiten na betaling. Gebruik altijd de webhook voor de definitieve statuswijziging.
// app/Http/Controllers/MollieWebhookController.php
class MollieWebhookController extends Controller
{
public function handle(Request $request, MollieService $mollie): Response
{
$paymentId = $request->input('id');
if (! $paymentId) {
return response('Geen payment ID', 400);
}
// Haal de actuele betaalstatus op via de API — vertrouw nooit de webhook-body
$betaling = $mollie->getBetaling($paymentId);
$order = Order::where('mollie_payment_id', $paymentId)->first();
if (! $order) {
// Mollie stuurt ook webhooks voor testbetalingen
return response('OK', 200);
}
match ($betaling->status) {
'paid' => VerwerkBetaling::dispatch($order->id),
'failed' => BetalingMislukt::dispatch($order->id),
'canceled' => BetalingGeannuleerd::dispatch($order->id),
'expired' => BetalingVerlopen::dispatch($order->id),
default => null,
};
// Altijd 200 teruggeven — anders herprobeert Mollie de webhook
return response('OK', 200);
}
}
Twee punten zijn hier kritiek. Vertrouw nooit de webhook-body voor de status — haal altijd de actuele status op via de API. En geef altijd een 200 terug. Als je webhook faalt, herprobeert Mollie tot 10 keer in 24 uur.
Webhook route buiten CSRF-bescherming
Mollie's webhook is een externe POST-request. Laravel's CSRF-middleware blokkeert dit standaard.
// app/Http/Middleware/VerifyCsrfToken.php
protected $except = [
'webhooks/mollie',
];
Of gebruik de web-middleware stack niet voor webhook routes:
// routes/api.php
Route::post('/webhooks/mollie', [MollieWebhookController::class, 'handle'])
->name('webhooks.mollie');
Refunds programmatisch uitvoeren
Mollie maakt refunds eenvoudig. Je kunt een volledige of gedeeltelijke terugbetaling uitvoeren.
public function terugbetaling(Order $order, int $bedragInCenten): void
{
$betaling = $this->mollie->payments->get($order->mollie_payment_id);
if (! $betaling->canBeRefunded()) {
throw new BetalingKanNietWordenTerugbetaald(
"Betaling {$order->mollie_payment_id} kan niet worden terugbetaald."
);
}
$refund = $betaling->refund([
'amount' => [
'value' => number_format($bedragInCenten / 100, 2, '.', ''),
'currency' => 'EUR',
],
'description' => "Terugbetaling order #{$order->order_number}",
]);
$order->update([
'mollie_refund_id' => $refund->id,
'refund_status' => $refund->status,
'refunded_at' => now(),
]);
}
Recurring payments en subscriptions
Mollie ondersteunt recurring payments via Mandates en Subscriptions. Dit is interessant voor SaaS-producten, abonnementen of periodieke B2B-bestellingen.
De flow werkt in drie stappen. Eerste betaling met sequenceType: first. Daarna een mandate aanmaken. Vervolgens automatische incasso's via sequenceType: recurring.
// Eerste betaling — klant geeft mandate via iDEAL of creditcard
public function eersteBetalingMetMandate(Customer $customer, int $bedragInCenten): string
{
$betaling = $this->mollie->payments->create([
'amount' => ['value' => number_format($bedragInCenten / 100, 2, '.', ''), 'currency' => 'EUR'],
'description' => 'Eerste betaling — abonnement activeren',
'redirectUrl' => route('abonnement.bevestigd'),
'webhookUrl' => route('webhooks.mollie'),
'sequenceType' => 'first',
'customerId' => $customer->mollie_customer_id,
'method' => 'ideal',
]);
return $betaling->getCheckoutUrl();
}
// Automatische incasso na mandate
public function periodiekeIncasso(Customer $customer, int $bedragInCenten, string $beschrijving): void
{
$this->mollie->payments->createFor($this->getMollieKlant($customer), [
'amount' => ['value' => number_format($bedragInCenten / 100, 2, '.', ''), 'currency' => 'EUR'],
'description' => $beschrijving,
'webhookUrl' => route('webhooks.mollie'),
'sequenceType' => 'recurring',
]);
}
Veelgemaakte fouten
Betaalstatus ophalen uit redirect URL. De redirect URL bevat geen status. Een klant kan de URL manueel openen. Haal de status altijd op via de webhook of via een expliciete API-call. Webhook niet beveiligen. Mollie heeft geen HMAC-signing op webhooks. Beveilig je webhook door de status altijd op te halen via de API in plaats van de webhook-body te vertrouwen. Mollie customer ID niet opslaan. Voor recurring payments heb je een Mollie customer ID nodig. Sla het op bij klantregistratie. Bedragen als float. Gebruik altijd integers (centen) intern. Converteer alleen naar string met exact twee decimalen bij de API-call.19.999999 afronden naar 20.00 geeft problemen.
Conclusie
Laravel + Mollie is een krachtige combinatie voor betaalflows buiten de standaard checkout. De SDK is goed onderhouden, de webhooks zijn betrouwbaar en de recurring payment-functionaliteit is productieklaar.
Het verschil zit in de details: webhooks correct beveiligen, bedragen als integers bewaren, altijd de status ophalen via de API. Die gewoonten scheiding correcte en incorrecte implementaties.
De Mollie API documentatie en de Mollie Laravel package zijn de referenties voor de implementatie. Voor webhook-beveiliging, zie ook de Laravel webhook-documentatie.
Gerelateerde artikelen:- Webhook verwerking in Laravel — betrouwbaar webhooks afhandelen
- Laravel + Exact Online koppeling — de boekhoudzijde
- Laravel Queues voor e-commerce — asynchroon verwerken
- Shopify-diensten en Magento-diensten — standaard betaalintegraties
Wil je een betaalflow bouwen buiten Shopify of Magento? Bekijk onze Laravel-diensten of neem contact op.

Geschreven door Ruthger Idema
15+ jaar ervaring in e-commerce development. Gespecialiseerd in Magento, Shopify en Laravel maatwerk.
Meer over ons team →