laravel-billing-midtrans maintained by gusmanwidodo
Laravel Billing — Midtrans
Midtrans (Snap) payment provider for
gusmanwidodo/laravel-billing.
It implements the billing PaymentProvider contract, so once installed you can
charge invoices through Midtrans and settle them from verified webhooks.
Features
- Snap charge — opens a Snap transaction and returns its token + redirect URL.
- Webhook verification — validates the Midtrans SHA512
signature_key(order_id + status_code + gross_amount + serverKey). Forged/tampered notifications are rejected. - Status mapping — settlement/capture(accept) → succeeded, pending → pending, deny → failed, cancel/expire → canceled, refund → refunded.
- Refund — calls the Midtrans refund endpoint.
- Auto-registers itself into laravel-billing's provider registry.
Requirements
- PHP
^8.3 gusmanwidodo/laravel-billing^0.4- Laravel 12
- A Midtrans account (server + client keys)
Installation
composer require gusmanwidodo/laravel-billing-midtrans
php artisan vendor:publish --tag=billing-midtrans-config
Set your keys in .env:
MIDTRANS_SERVER_KEY=your-server-key
MIDTRANS_CLIENT_KEY=your-client-key
MIDTRANS_PRODUCTION=false
MIDTRANS_AS_DEFAULT=false
# minor-unit decimals used by your invoices (2 = cents; IDR gross is whole rupiah)
MIDTRANS_DECIMALS=2
Usage
use Gusmanwidodo\Billing\Facades\Billing;
// 1. Charge an invoice via Midtrans -> pending intent with the Snap redirect URL.
$intent = Billing::charge($invoice, provider: 'midtrans');
$snapUrl = $intent->meta['redirect_url']; // send the customer here
$snapToken = $intent->meta['snap_token']; // or use with Snap.js
// 2. In your Midtrans webhook route, hand the raw body + headers to billing.
// The signature is verified before anything is recorded.
Route::post('/webhooks/midtrans', function (Illuminate\Http\Request $request) {
try {
Billing::handleWebhook('midtrans', $request->getContent(), $request->headers->all());
} catch (\RuntimeException $e) {
abort(403); // signature verification failed
}
return response()->json(['ok' => true]);
});
// 3. Refund a succeeded intent.
Billing::refund($intent);
On a verified settlement/capture(accept) notification, a real Payment is
recorded and the invoice becomes paid automatically. Settlement is idempotent
(Midtrans may resend), keyed by the intent's external_id (the order_id).
Amounts & currency
laravel-billing stores money as integer minor units. Midtrans gross_amount
is whole rupiah. This package converts using MIDTRANS_DECIMALS (default 2):
1_000_000 minor units → gross_amount = 10000. Set MIDTRANS_DECIMALS=0 if
your invoices already store whole rupiah.
Security
Webhook signature verification is mandatory — Billing::handleWebhook('midtrans', ...) throws if the SHA512 signature_key does not match, so a forged or tampered
notification never records a payment. Always also confirm status_code=200,
fraud_status=accept, and a settlement/capture status (this package's mapping
already enforces the fraud/status logic).
Testing
composer test # 12 tests, all HTTP mocked via Http::fake (no real API key needed)
License
MIT © Gusman Widodo. See LICENSE.