Integrasi Payment Gateway Midtrans di Laravel

Midtrans adalah salah satu payment gateway paling populer di Indonesia, mendukung kartu kredit, transfer bank (VA), e-wallet seperti GoPay dan ShopeePay, hingga QRIS. Tutorial ini...

Integrasi Payment Gateway Midtrans di Laravel

Midtrans adalah salah satu payment gateway paling populer di Indonesia, mendukung kartu kredit, transfer bank (VA), e-wallet seperti GoPay dan ShopeePay, hingga QRIS. Tutorial ini menunjukkan integrasi Midtrans Snap di Laravel dari awal: memasang SDK, membuat token pembayaran, menampilkan popup pembayaran, lalu menangani webhook notifikasi untuk memperbarui status order dengan benar.

Sebelum masuk ke kode, penting memahami gambaran besar alurnya. Midtrans bekerja dengan model server-to-server: aplikasi Anda tidak pernah menyentuh data kartu atau saldo e-wallet pelanggan secara langsung. Sebaliknya, server Anda meminta sebuah token ke Midtrans, pengguna menyelesaikan pembayaran di antarmuka milik Midtrans, dan Midtrans mengabari server Anda lewat webhook ketika status berubah. Pemisahan ini membuat aplikasi Anda jauh lebih aman dan mengurangi beban kepatuhan PCI-DSS, karena data sensitif tidak pernah singgah di database Anda.

1. Memasang SDK Midtrans

Instal package resmi Midtrans lewat Composer:

composer require midtrans/midtrans-php

Daftar akun di dashboard Midtrans, lalu ambil Server Key dan Client Key dari menu Settings → Access Keys. Selama pengembangan gunakan mode sandbox.

2. Menyimpan Konfigurasi di .env

Jangan pernah menaruh key langsung di kode. Simpan di .env:

MIDTRANS_SERVER_KEY=SB-Mid-server-xxxxxxxxxxxx
MIDTRANS_CLIENT_KEY=SB-Mid-client-xxxxxxxxxxxx
MIDTRANS_IS_PRODUCTION=false

Buat file config/midtrans.php agar rapi:

return [
    'server_key'    => env('MIDTRANS_SERVER_KEY'),
    'client_key'    => env('MIDTRANS_CLIENT_KEY'),
    'is_production' => env('MIDTRANS_IS_PRODUCTION', false),
];

Dengan menaruh key di config, Anda bisa memanggil config('midtrans.server_key') di mana pun tanpa mengakses env() langsung. Ini penting karena saat Anda menjalankan php artisan config:cache di produksi, pemanggilan env() di luar file config akan mengembalikan null. Membedakan Server Key dan Client Key juga krusial: Server Key bersifat rahasia dan hanya dipakai di backend untuk membuat token serta memverifikasi webhook, sedangkan Client Key boleh tampil di HTML karena hanya dipakai memuat antarmuka pembayaran.

3. Membuat Snap Token

Snap adalah antarmuka pembayaran siap pakai dari Midtrans. Alurnya: server Anda membuat Snap token, lalu frontend memakainya untuk memunculkan popup pembayaran. Keunggulan Snap adalah Anda tidak perlu membangun halaman pembayaran sendiri untuk setiap metode; Midtrans menyediakan tampilan lengkap yang sudah mendukung VA, e-wallet, kartu, dan QRIS sekaligus. Buat controller untuk memproses checkout:

use Midtrans\Config;
use Midtrans\Snap;

class PaymentController extends Controller
{
    public function __construct()
    {
        Config::$serverKey    = config('midtrans.server_key');
        Config::$isProduction = config('midtrans.is_production');
        Config::$isSanitized  = true;
        Config::$is3ds        = true;
    }

    public function pay(Order $order)
    {
        $params = [
            'transaction_details' => [
                'order_id'     => $order->code,
                'gross_amount' => (int) $order->total,
            ],
            'customer_details' => [
                'first_name' => $order->customer_name,
                'email'      => $order->customer_email,
            ],
        ];

        $snapToken = Snap::getSnapToken($params);

        return view('checkout', compact('order', 'snapToken'));
    }
}

Penting: order_id harus unik untuk setiap transaksi. Jika Anda memakai ID yang sama dua kali, Midtrans akan menolaknya. Gunakan kode order unik, bukan sekadar ID auto-increment yang bisa terulang saat retry.

4. Menampilkan Popup Pembayaran dengan snap.js

Di view checkout, muat script snap.js dari Midtrans dan panggil snap.pay() dengan token tadi:

<script src="https://app.sandbox.midtrans.com/snap/snap.js"
        data-client-key="{{ config('midtrans.client_key') }}"></script>

<button id="pay-button">Bayar Sekarang</button>

<script>
document.getElementById('pay-button').onclick = function () {
    snap.pay('{{ $snapToken }}', {
        onSuccess: function (result) {
            window.location.href = '/order/success';
        },
        onPending: function (result) {
            window.location.href = '/order/pending';
        },
        onError: function (result) {
            alert('Pembayaran gagal.');
        }
    });
};
</script>

Untuk produksi, ganti URL script menjadi https://app.midtrans.com/snap/snap.js.

5. Menangani Webhook Notifikasi

Callback JavaScript di atas hanya untuk UX; jangan pernah mempercayainya untuk mengubah status pembayaran. Sumber kebenaran adalah webhook notifikasi server-to-server dari Midtrans. Buat endpoint POST untuk menerimanya:

use Midtrans\Notification;

public function notification(Request $request)
{
    Config::$serverKey    = config('midtrans.server_key');
    Config::$isProduction = config('midtrans.is_production');

    $notif = new Notification();

    $order = Order::where('code', $notif->order_id)->firstOrFail();
    $status = $notif->transaction_status;
    $fraud  = $notif->fraud_status;

    if ($status === 'capture' && $fraud === 'accept') {
        $order->update(['status' => 'paid']);
    } elseif ($status === 'settlement') {
        $order->update(['status' => 'paid']);
    } elseif (in_array($status, ['cancel', 'deny', 'expire'])) {
        $order->update(['status' => 'failed']);
    } elseif ($status === 'pending') {
        $order->update(['status' => 'pending']);
    }

    return response()->json(['message' => 'OK']);
}

Daftarkan route-nya dan kecualikan dari CSRF karena request datang dari server Midtrans, bukan dari browser pengguna:

Route::post('/midtrans/notification', [PaymentController::class, 'notification']);

Di Laravel 11, kecualikan URI ini di bootstrap/app.php pada bagian validateCsrfTokens(except: ['midtrans/*']). Terakhir, daftarkan URL webhook ini di dashboard Midtrans pada Settings → Configuration → Payment Notification URL.

6. Praktik Keamanan yang Wajib

  • Verifikasi signature: class Notification otomatis memvalidasi terhadap server key Anda, jadi tetap gunakan SDK resmi, bukan membaca payload mentah.
  • Cek ulang jumlah: bandingkan gross_amount notifikasi dengan total order di database sebelum menandai lunas.
  • Idempoten: webhook bisa dikirim beberapa kali. Pastikan meng-update status aman diulang dan tidak menggandakan efek (misalnya kirim email hanya sekali).
  • Selalu balas HTTP 200: jika Anda mengembalikan error, Midtrans akan terus mengirim ulang notifikasi.

7. Menguji dan Debug di Sandbox

Saat mengembangkan secara lokal, webhook Midtrans tidak bisa menjangkau localhost. Gunakan tunnel seperti Ngrok untuk mengekspos server lokal Anda ke internet, lalu daftarkan URL tunnel tersebut sebagai Payment Notification URL di dashboard. Untuk mensimulasikan pembayaran, Midtrans menyediakan nomor kartu uji dan tombol simulasi status di dashboard sandbox, sehingga Anda bisa menguji seluruh alur — sukses, pending, gagal, dan kedaluwarsa — tanpa uang sungguhan. Selalu log payload notifikasi yang masuk selama pengembangan agar Anda tahu persis field apa yang dikirim Midtrans untuk setiap skenario.

Perlu juga dipahami perbedaan status transaksi Midtrans agar logika Anda tepat. Untuk pembayaran kartu, status awal adalah capture yang masih perlu diperiksa fraud_status-nya. Untuk metode lain seperti VA atau e-wallet, status lunas ditandai settlement. Status pending berarti pengguna sudah memilih metode tapi belum membayar, misalnya nomor VA sudah terbit namun belum ditransfer. Memahami peta status ini mencegah kesalahan umum menandai order lunas terlalu dini.

Dengan Snap token dari server, popup snap.js di frontend, dan webhook sebagai sumber kebenaran, Anda memiliki integrasi Midtrans yang aman dan siap produksi. Pola ini sama untuk semua metode pembayaran karena Snap menyatukan VA, e-wallet, dan kartu dalam satu alur. Setelah dasar ini berjalan, Anda bisa mengembangkannya lebih jauh dengan mengirim email struk otomatis, menampilkan riwayat transaksi, atau menambahkan fitur pembayaran ulang untuk order yang kedaluwarsa.

Yudhi
Ditulis oleh
Yudhi
Founder & Lead Developer, GudangCode

Yudhi adalah founder GudangCode dan developer Laravel dengan pengalaman membangun puluhan sistem informasi bisnis siap pakai — mulai dari POS, HRIS, hingga aplikasi manajemen. Ia menulis panduan dan artikel di GudangCode untuk membantu developer Indonesia menjalankan, memahami, dan men-deploy source code Laravel dengan benar.

Laravel PHP MySQL Sistem Informasi Bisnis
Lihat semua artikel Yudhi
Mau source code & aplikasi lengkapnya?

Daftar gratis untuk mengunduh aplikasi bisnis, sistem informasi, dan source code Laravel siap pakai.

Daftar Gratis & Download
Laravel Midtrans Payment Gateway Pembayaran
📚 Free Learning Hub

Learn Coding for Free at DhieCoderWeb

Explore Laravel, PHP, JavaScript tutorials, source code, web development guides, and practical programming tips.

DhieCoderWeb
100+
Tutorials
Free
Learning
SEO
Tips
Visit Dhiecoderweb.com →

Dapatkan Akses Penuh Sekarang!

Bergabunglah menjadi member kami dan dapatkan akses eksklusif ke seluruh fitur unggulan aplikasi ini. Proses cepat, mudah, dan langsung bisa Anda gunakan.

Daftar Members Sekarang
Tim Support
Online
Isi data dulu untuk mulai chat:
Beri rating & testimoni sebelum menutup:
Live chat by gudangcode.com