Advertisement

Panduan Lengkap Integrasi Payment Gateway Midtrans dengan Laravel

Midtrans adalah salah satu payment gateway terpopuler di Indonesia yang menyediakan berbagai metode pembayaran mulai dari kartu kredit, transfer bank, e-wallet, hingga gerai retail. Dalam tutorial ini, kita akan membahas cara mengintegrasikan Midtrans dengan aplikasi Laravel Anda secara step-by-step.

Panduan Lengkap Integrasi Payment Gateway Midtrans dengan Laravel

Sebelum memulai integrasi, pastikan Anda sudah memiliki beberapa hal berikut:

  • Akun Midtrans (daftar di midtrans.com)
  • Laravel versi 8 atau lebih baru sudah terinstall
  • Composer untuk manajemen dependency
  • Server Key dan Client Key dari dashboard Midtrans

Setelah mendaftar di Midtrans, Anda akan mendapatkan akses ke dashboard Sandbox untuk testing. Ambil Server Key dan Client Key dari menu Settings → Access Keys.

Langkah 1: Install Package Midtrans

Midtrans menyediakan package official untuk PHP yang bisa kita install melalui Composer. Jalankan perintah berikut di terminal:

composer require midtrans/midtrans-php

Tunggu hingga proses instalasi selesai. Package ini akan memudahkan kita dalam berkomunikasi dengan API Midtrans.

Langkah 2: Konfigurasi Environment

Tambahkan konfigurasi Midtrans di file .env Anda:

MIDTRANS_SERVER_KEY=your-server-key
MIDTRANS_CLIENT_KEY=your-client-key
MIDTRANS_IS_PRODUCTION=false
MIDTRANS_IS_SANITIZED=true
MIDTRANS_IS_3DS=true

Ganti your-server-key dan your-client-key dengan key yang Anda dapatkan dari dashboard Midtrans. Set MIDTRANS_IS_PRODUCTION menjadi true saat aplikasi sudah siap production.

Selanjutnya, buat file konfigurasi baru di 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' => env('MIDTRANS_IS_SANITIZED', true),
    'is_3ds' => env('MIDTRANS_IS_3DS', true),
];

Langkah 3: Membuat Model dan Migration

Kita perlu membuat tabel untuk menyimpan data transaksi. Buat migration dengan perintah:

php artisan make:migration create_transactions_table

Edit file migration yang baru dibuat di folder database/migrations:

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateTransactionsTable extends Migration
{
    public function up()
    {
        Schema::create('transactions', function (Blueprint $table) {
            $table->id();
            $table->string('order_id')->unique();
            $table->decimal('gross_amount', 10, 2);
            $table->string('payment_type')->nullable();
            $table->string('transaction_status')->default('pending');
            $table->string('transaction_id')->nullable();
            $table->text('snap_token')->nullable();
            $table->timestamps();
        });
    }

    public function down()
    {
        Schema::dropIfExists('transactions');
    }
}

Jalankan migration:

php artisan migrate

Kemudian buat model Transaction:

php artisan make:model Transaction

Edit file app/Models/Transaction.php:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Transaction extends Model
{
    protected $fillable = [
        'order_id',
        'gross_amount',
        'payment_type',
        'transaction_status',
        'transaction_id',
        'snap_token'
    ];
}

Langkah 4: Membuat Controller Payment

Buat controller untuk menangani proses payment:

php artisan make:controller PaymentController

Edit file app/Http/Controllers/PaymentController.php:

<?php

namespace App\Http\Controllers;

use App\Models\Transaction;
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 checkout(Request $request)
    {
        $request->validate([
            'gross_amount' => 'required|numeric|min:1',
        ]);

        // Generate unique order ID
        $orderId = 'ORDER-' . time();

        // Siapkan parameter transaksi
        $params = [
            'transaction_details' => [
                'order_id' => $orderId,
                'gross_amount' => $request->gross_amount,
            ],
            'customer_details' => [
                'first_name' => auth()->user()->name ?? 'Customer',
                'email' => auth()->user()->email ?? '[email protected]',
            ],
        ];

        try {
            // Dapatkan Snap Token
            $snapToken = Snap::getSnapToken($params);

            // Simpan transaksi ke database
            Transaction::create([
                'order_id' => $orderId,
                'gross_amount' => $request->gross_amount,
                'snap_token' => $snapToken,
                'transaction_status' => 'pending',
            ]);

            return response()->json([
                'snap_token' => $snapToken,
                'order_id' => $orderId
            ]);

        } catch (\Exception $e) {
            return response()->json([
                'error' => $e->getMessage()
            ], 500);
        }
    }

    public 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
        if ($hashed == $request->signature_key) {
            $transaction = Transaction::where('order_id', $request->order_id)->first();

            if ($transaction) {
                $transaction->update([
                    'transaction_status' => $request->transaction_status,
                    'transaction_id' => $request->transaction_id,
                    'payment_type' => $request->payment_type,
                ]);
            }
        }

        return response()->json(['status' => 'success']);
    }
}

Langkah 5: Setup Routes

Tambahkan routes untuk payment di file routes/web.php:

<?php

use App\Http\Controllers\PaymentController;
use Illuminate\Support\Facades\Route;

Route::get('/payment', function () {
    return view('payment');
})->name('payment.page');

Route::post('/payment/checkout', [PaymentController::class, 'checkout'])
    ->name('payment.checkout');

Route::post('/payment/callback', [PaymentController::class, 'callback'])
    ->name('payment.callback');

Langkah 6: Membuat View Payment

Buat file view di resources/views/payment.blade.php:

<!DOCTYPE html>
<html lang="id">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="csrf-token" content="{{ csrf_token() }}">
    <title>Payment Gateway</title>
    <script src="https://app.sandbox.midtrans.com/snap/snap.js" 
            data-client-key="{{ config('midtrans.client_key') }}"></script>
</head>
<body>
    <div class="container">
        <h1>Checkout Payment</h1>
        
        <form id="payment-form">
            <label>Jumlah Pembayaran:</label>
            <input type="number" id="amount" name="amount" required>
            <button type="submit">Bayar Sekarang</button>
        </form>
    </div>

    <script>
        document.getElementById('payment-form').addEventListener('submit', function(e) {
            e.preventDefault();
            
            const amount = document.getElementById('amount').value;

            fetch('{{ route("payment.checkout") }}', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content
                },
                body: JSON.stringify({
                    gross_amount: amount
                })
            })
            .then(response => response.json())
            .then(data => {
                snap.pay(data.snap_token, {
                    onSuccess: function(result) {
                        alert('Pembayaran berhasil!');
                        console.log(result);
                    },
                    onPending: function(result) {
                        alert('Menunggu pembayaran Anda');
                        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('Error:', error);
            });
        });
    </script>
</body>
</html>

Langkah 7: Konfigurasi Notification URL

Agar Midtrans dapat mengirimkan notifikasi status pembayaran ke aplikasi Anda, masuk ke dashboard Midtrans dan setting Notification URL ke:

https://yourdomain.com/payment/callback

Pastikan URL ini dapat diakses secara public. Jika masih dalam tahap development, Anda bisa menggunakan tools seperti ngrok untuk expose localhost Anda.

Langkah 8: Testing Integrasi

Untuk melakukan testing di environment sandbox, Midtrans menyediakan beberapa nomor kartu test:

  • Kartu Kredit Sukses: 4811 1111 1111 1114
  • CVV: 123
  • Expired Date: 01/25 (atau tanggal yang akan datang)

Jalankan aplikasi Laravel Anda dan akses halaman payment. Masukkan jumlah pembayaran dan klik tombol bayar. Popup Snap Midtrans akan muncul dengan berbagai pilihan metode pembayaran.

Tips dan Best Practices

Beberapa hal yang perlu diperhatikan dalam implementasi payment gateway:

  • Keamanan: Jangan pernah expose Server Key di frontend. Semua komunikasi dengan Midtrans API harus dilakukan di backend.
  • Validasi Callback: Selalu validasi signature key yang dikirim Midtrans untuk memastikan request berasal dari server Midtrans.
  • Handle Status: Midtrans memiliki beberapa status transaksi (pending, settlement, expire, cancel). Pastikan aplikasi Anda handle semua status dengan baik.
  • Logging: Simpan semua response dari Midtrans untuk keperluan audit dan debugging.
  • Testing Menyeluruh: Test berbagai skenario pembayaran termasuk success, pending, dan failed sebelum go live.

Kesimpulan

Integrasi Midtrans dengan Laravel cukup straightforward dengan bantuan package official yang disediakan. Dengan mengikuti langkah-langkah di atas, Anda sudah bisa menerima pembayaran melalui berbagai metode yang disediakan Midtrans. Jangan lupa untuk melakukan testing menyeluruh di environment sandbox sebelum mengaktifkan mode production.

Untuk dokumentasi lebih lengkap dan fitur-fitur advanced seperti subscription, tokenization, atau 3D Secure, Anda bisa mengunjungi dokumentasi official Midtrans.

...

Berlangganan Gratis Untuk Melanjutkan Membaca.