Cara Integrasi Payment Gateway Midtrans dengan Laravel 10 dan React JS
Cara Integrasi Payment Gateway Midtrans dengan Laravel 10 dan React JS
Di era ekonomi digital saat ini, kemampuan menerima pembayaran secara otomatis adalah fitur wajib bagi aplikasi e-commerce maupun SaaS. Di Indonesia, Midtrans adalah salah satu Payment Gateway terpopuler karena dukungannya yang luas (GoPay, VA Bank, Kartu Kredit, dll) dan dokumentasinya yang cukup lengkap.
Namun, mengintegrasikan Midtrans dengan teknologi separation of concern seperti Laravel 10 (sebagai API Backend) dan React JS (sebagai Frontend) seringkali membingungkan bagi pengembang, terutama terkait penanganan Snap Token dan Callback.
Artikel ini akan memandu Anda langkah demi langkah membangun sistem pembayaran yang aman dan scalable.
Arsitektur Alur Pembayaran
Sebelum masuk ke koding, penting untuk memahami alur kerjanya agar tidak tersesat:
- Frontend (React): User klik tombol “Bayar”.
- Backend (Laravel): Menerima request, membuat Order ID, dan meminta Snap Token ke Server Midtrans.
- Frontend (React): Menerima Snap Token, lalu memunculkan Popup Pembayaran (Snap.js).
- User: Melakukan pembayaran.
- Midtrans: Mengirim notifikasi status pembayaran (Webhook) ke Backend Laravel untuk update status database.
Persiapan Awal (Prerequisites)
Pastikan Anda memiliki:
- Akun Midtrans (Mode Sandbox untuk testing).
- Project Laravel 10 yang sudah terinstall.
- Project React JS (Vite atau CRA).
- Koneksi internet stabil.
Langkah 1: Konfigurasi Akun Midtrans
- Login ke Dashboard Midtrans.
- Masuk ke menu Settings > Access Keys.
- Simpan Client Key dan Server Key.
- Pastikan Anda berada di environment Sandbox.
Langkah 2: Setup Backend (Laravel 10)
Kita akan membuat API Endpoint untuk men-generate Snap Token.
1. Install Library Midtrans
Buka terminal di project Laravel Anda dan jalankan:
Bashcomposer require midtrans/midtrans-php
2. Konfigurasi .env
Tambahkan credential Midtrans ke file .env Anda. Jangan pernah hardcode key ini di dalam Controller demi keamanan.
MIDTRANS_SERVER_KEY=SB-Mid-server-xxxxxxxxx
MIDTRANS_CLIENT_KEY=SB-Mid-client-xxxxxxxxx
MIDTRANS_IS_PRODUCTION=false
Buat juga file config agar lebih rapi. Buat config/midtrans.php:
<?php
return [
'server_key' => env('MIDTRANS_SERVER_KEY'),
'client_key' => env('MIDTRANS_CLIENT_KEY'),
'is_production' => env('MIDTRANS_IS_PRODUCTION', false),
'is_sanitized' => true,
'is_3ds' => true,
];
3. Membuat Controller Pembayaran
Buat controller baru: php artisan make:controller Api/PaymentController.
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Midtrans\Config;
use Midtrans\Snap;
class PaymentController extends Controller
{
public function __construct()
{
// Set konfigurasi Midtrans
Config::$serverKey = config('midtrans.server_key');
Config::$isProduction = config('midtrans.is_production');
Config::$isSanitized = config('midtrans.is_sanitized');
Config::$is3ds = config('midtrans.is_3ds');
}
public function createTransaction(Request $request)
{
// Validasi input (sesuaikan dengan kebutuhan bisnis)
// Contoh sederhana: Order ID dibuat acak
$params = [
'transaction_details' => [
'order_id' => 'ORDER-' . rand(),
'gross_amount' => $request->price, // Harga dari frontend/database
],
'customer_details' => [
'first_name' => $request->name,
'email' => $request->email,
],
];
try {
// Ambil Snap Token dari Midtrans
$snapToken = Snap::getSnapToken($params);
return response()->json([
'status' => 'success',
'token' => $snapToken,
'redirect_url' => "https://app.sandbox.midtrans.com/snap/v2/vtweb/" . $snapToken
]);
} catch (\Exception $e) {
return response()->json(['error' => $e->getMessage()], 500);
}
}
}
4. Setup Route API
Buka routes/api.php:
PHPuse App\Http\Controllers\Api\PaymentController;
Route::post('/payment', [PaymentController::class, 'createTransaction']);
Langkah 3: Setup Frontend (React JS)
Tantangan utama di React adalah memanggil script snap.js milik Midtrans karena script ini tidak tersedia via NPM package secara resmi.
1. Custom Hook untuk Load Script
Kita perlu memuat script Midtrans hanya ketika komponen pembayaran dibutuhkan. Tambahkan kode ini di komponen Anda atau buat custom hook.
Script URL Sandbox: https://app.sandbox.midtrans.com/snap/snap.js
2. Komponen Pembayaran (PaymentComponent.jsx)
Reactimport React, { useState, useEffect } from 'react';
import axios from 'axios';
const PaymentComponent = () => {
const [token, setToken] = useState('');
// Masukkan Client Key Anda di sini atau via ENV React
const MIDTRANS_CLIENT_KEY = import.meta.env.VITE_MIDTRANS_CLIENT_KEY;
useEffect(() => {
// Menambahkan script snap midtrans ke tag <head>
const snapScript = "https://app.sandbox.midtrans.com/snap/snap.js";
const clientKey = MIDTRANS_CLIENT_KEY;
const script = document.createElement('script');
script.src = snapScript;
script.setAttribute('data-client-key', clientKey);
script.async = true;
document.body.appendChild(script);
return () => {
document.body.removeChild(script);
};
}, []);
const handlePay = async () => {
try {
// 1. Request Snap Token ke Backend Laravel
const response = await axios.post('http://localhost:8000/api/payment', {
name: "Budi Santoso",
email: "budi@example.com",
price: 50000
});
const snapToken = response.data.token;
// 2. Memunculkan Pop Up Snap
if (window.snap) {
window.snap.pay(snapToken, {
onSuccess: function(result){
alert("Pembayaran Berhasil!");
console.log(result);
},
onPending: function(result){
alert("Menunggu Pembayaran!");
console.log(result);
},
onError: function(result){
alert("Pembayaran Gagal!");
console.log(result);
},
onClose: function(){
alert("Anda menutup popup tanpa menyelesaikan pembayaran");
}
});
}
} catch (error) {
console.error("Gagal memproses transaksi", error);
}
};
return (
<div className="p-5">
<h1 className="text-2xl font-bold mb-4">Integrasi Midtrans</h1>
<button
onClick={handlePay}
className="bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700 transition"
>
Bayar Sekarang (IDR 50.000)
</button>
</div>
);
};
export default PaymentComponent;
Langkah 4: Handling Notification (Webhook) – Sangat Penting
Banyak tutorial berhenti di langkah 3. Padahal, mengandalkan callback frontend (onSuccess) untuk mengupdate status “Lunas” di database adalah tindakan tidak aman. User bisa memanipulasi JavaScript browser.
Anda wajib menangani notifikasi HTTP (Webhook) dari server Midtrans ke server Laravel Anda.
1. Bypass CSRF untuk Webhook
Karena Midtrans mengirim POST request dari luar aplikasi, kita harus menonaktifkan CSRF protection untuk route webhook.
Buka app/Http/Middleware/VerifyCsrfToken.php (atau di Laravel 11 via bootstrap file), tambahkan:
protected $except = [
'api/midtrans-callback', // Route yang akan kita buat
];
2. Callback Controller
Di PaymentController.php, tambahkan method baru:
PHPpublic function callback(Request $request)
{
$serverKey = config('midtrans.server_key');
$hashed = hash("sha512", $request->order_id.$request->status_code.$request->gross_amount.$serverKey);
// Verifikasi Signature Key untuk keamanan
if($hashed == $request->signature_key){
if($request->transaction_status == 'capture' || $request->transaction_status == 'settlement'){
// Update status database menjadi 'PAID'
// $order = Order::find($request->order_id);
// $order->update(['status' => 'Paid']);
return response()->json(['status' => 'success']);
}
}
return response()->json(['status' => 'error'], 400);
}
3. Setup Webhook URL di Dashboard Midtrans
- Masuk Dashboard Midtrans > Settings > Configuration.
- Pada Notification URL, masukkan URL API Laravel Anda yang sudah di-hosting (contoh:
https://api-domain-anda.com/api/midtrans-callback).
Catatan: Webhook tidak bisa berjalan di localhost kecuali menggunakan tunneling seperti Ngrok.
Kesimpulan
Integrasi Midtrans dengan Laravel 10 dan React JS membutuhkan pemahaman yang kuat tentang alur data antara Client, Server, dan Payment Gateway. Kunci utama keberhasilan integrasi ini adalah:
- Menjaga keamanan Server Key di Backend.
- Menggunakan React Effect untuk memuat script Snap.
- Mengandalkan Webhook (Backend Notification) untuk update status pembayaran, bukan Frontend callback.
Dengan mengikuti panduan ini, Anda telah membangun fondasi sistem pembayaran yang robust dan siap untuk fase produksi.