LaravelPHP 8.1+ · Laravel 10+ · moncashconnect/php-sdk

Intégrer MonCash avec Laravel

Intégrez les paiements MonCash dans votre application Laravel : contrôleur de paiement, middleware de vérification webhook et exclusion CSRF correcte.

Sandbox

Commencez en Sandbox

Avant d'implémenter le code ci-dessous avec votre clé live (sk_proj_…), nous recommandons de tester d'abord en mode Sandbox avec sk_test_proj_…. Le code est identique — vous ne changez que la valeur de la variable d'environnement. Lisez le Guide Sandbox avant de continuer.

Prérequis

  • PHP 8.1+
  • Laravel 10+ (ou 11+)
  • Composer
  • Un projet MonCashConnect avec clé secrète — créer un projet

Installation

composer require moncashconnect/php-sdk

Configuration

Ajoutez vos variables dans .env :

MCC_SECRET_KEY=sk_proj_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
MCC_WEBHOOK_SECRET=whsec_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Puis exposez-les dans config/services.php :

<?php
return [
    // ... autres services
    'moncashconnect' => [
        'secret_key'     => env('MCC_SECRET_KEY'),
        'webhook_secret' => env('MCC_WEBHOOK_SECRET'),
    ],
];

Contrôleur de paiement

Créez app/Http/Controllers/PaymentController.php :

<?php

namespace App\Http\Controllers;

use MonCashConnect\Client;
use MonCashConnect\Exception\MonCashException;
use Illuminate\Http\Request;

class PaymentController extends Controller
{
    private Client $client;

    public function __construct()
    {
        $this->client = new Client(config('services.moncashconnect.secret_key'));
    }

    public function initiate(Request $request)
    {
        $request->validate([
            'order_id' => 'required|string|max:100',
            'amount'   => 'required|integer|min:1|max:1000000',
        ]);

        try {
            $payment = $this->client->createPayment(
                $request->integer('amount'),
                $request->string('order_id'),
                [
                    'returnUrl'    => route('payment.return'),
                    'customerName' => $request->user()?->name,
                ]
            );
        } catch (MonCashException $e) {
            return back()->withErrors(['payment' => $e->getMessage()]);
        }

        return redirect($payment['paymentUrl']);
    }

    public function returnPage(Request $request)
    {
        $ref = $request->query('ref');
        if (!$ref) return redirect('/')->withErrors(['Référence manquante.']);

        try {
            $tx = $this->client->getPaymentStatus($ref);
        } catch (MonCashException $e) {
            return view('payment.error', ['message' => $e->getMessage()]);
        }

        return view('payment.return', ['tx' => $tx]);
    }
}

Contrôleur webhook

Créez app/Http/Controllers/WebhookController.php. Lisez le corps brut via $request->getContent() avant toute désérialisation.

<?php

namespace App\Http\Controllers;

use MonCashConnect\Webhook;
use MonCashConnect\Exception\MonCashException;
use Illuminate\Http\Request;
use App\Models\Order;

class WebhookController extends Controller
{
    public function handle(Request $request)
    {
        $rawBody   = $request->getContent();
        $signature = $request->header('X-MCC-Signature', '');
        $timestamp = $request->header('X-MCC-Timestamp', '');

        try {
            $event = Webhook::constructEvent(
                $rawBody,
                $signature,
                $timestamp,
                config('services.moncashconnect.webhook_secret'),
            );
        } catch (MonCashException $e) {
            return response($e->getMessage(), $e->getCode() ?: 400);
        }

        match ($event['event']) {
            'payment.completed' =>
                Order::where('reference', $event['reference'])
                     ->update(['status' => 'paid']),
            'payment.failed' =>
                Order::where('reference', $event['reference'])
                     ->update(['status' => 'failed']),
            default => null,
        };

        return response('OK');
    }
}

Routes & exclusion CSRF

Dans routes/web.php (ou api.php) :

<?php
use App\Http\Controllers\PaymentController;
use App\Http\Controllers\WebhookController;

// Routes web (avec session)
Route::post('/payment/initiate', [PaymentController::class, 'initiate'])->name('payment.initiate');
Route::get('/payment/return',    [PaymentController::class, 'returnPage'])->name('payment.return');

// Webhook — doit être accessible sans CSRF
Route::post('/webhooks/moncash', [WebhookController::class, 'handle'])->name('webhooks.moncash');

Excluez la route webhook de la vérification CSRF dans app/Http/Middleware/VerifyCsrfToken.php :

<?php

namespace App\Http\Middleware;

use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;

class VerifyCsrfToken extends Middleware
{
    protected $except = [
        'webhooks/moncash',
    ];
}
Sur Laravel 11+, ajoutez plutôt l'exclusion dans bootstrap/app.php : ->withMiddleware(fn ($m) => $m->exceptFromCsrf(['webhooks/moncash']))
La vérification de signature MonCashConnect remplace le CSRF. Ne supprimez la protection CSRF que pour la route webhook, pas pour l'ensemble de l'application.

Liste de contrôle avant mise en production

MCC_SECRET_KEY et MCC_WEBHOOK_SECRET sont dans les variables d'environnement du serveur de production

La route /webhooks/moncash est exclue du middleware CSRF

Le WebhookController utilise $request->getContent() (corps brut) avant toute désérialisation

Votre contrôleur webhook est idempotent (peut recevoir le même événement plusieurs fois)

La vérification du statut sur la page de retour utilise getPaymentStatus() — pas les paramètres URL

L'URL webhook https://votresite.com/webhooks/moncash est configurée dans le tableau de bord MonCashConnect