gusmanwidodo / laravel-billing-stripe
Stripe payment provider for gusmanwidodo/laravel-billing. Implements the PaymentProvider contract: Checkout Session charge, Stripe-Signature webhook verification, event mapping, and refund.
Package info
github.com/gusmanwidodo/laravel-billing-stripe
pkg:composer/gusmanwidodo/laravel-billing-stripe
Requires
- php: ^8.3
- gusmanwidodo/laravel-billing: ^0.4
- illuminate/http: ^12.0
- illuminate/support: ^12.0
Requires (Dev)
- orchestra/testbench: ^10.0
- pestphp/pest: ^3.0
- pestphp/pest-plugin-laravel: ^3.0
README
Stripe payment provider for
gusmanwidodo/laravel-billing.
Implements the billing PaymentProvider contract using Stripe Checkout, so you
can charge invoices via a hosted Checkout page and settle them from verified
webhooks.
Features
- Checkout charge — creates a Checkout Session and returns its hosted URL.
- Webhook verification — validates the
Stripe-Signatureheader (t=<ts>,v1=<HMAC-SHA256(ts + "." + payload, whsec)>) with a timestamp tolerance to reject replays. - Event mapping —
checkout.session.completed(paid) /payment_intent.succeeded→ succeeded,expired→ canceled,payment_failed→ failed,charge.refunded→ refunded. - Refund — creates a refund for the session's payment intent.
- Auto-registers itself into laravel-billing's provider registry.
Requirements
- PHP
^8.3 gusmanwidodo/laravel-billing^0.4- Laravel 12
- A Stripe account (secret key + webhook signing secret)
Installation
composer require gusmanwidodo/laravel-billing-stripe php artisan vendor:publish --tag=billing-stripe-config
STRIPE_SECRET_KEY=sk_live_or_test STRIPE_WEBHOOK_SECRET=whsec_... STRIPE_SUCCESS_URL=https://your-app.test/billing/success STRIPE_CANCEL_URL=https://your-app.test/billing/cancel STRIPE_AS_DEFAULT=false
Usage
use Gusmanwidodo\Billing\Facades\Billing; // 1. Charge an invoice via Stripe Checkout -> pending intent with the hosted URL. $intent = Billing::charge($invoice, provider: 'stripe'); return redirect($intent->meta['redirect_url']); // Stripe Checkout page // 2. Stripe webhook route — pass the RAW body + headers; the signature is verified. Route::post('/webhooks/stripe', function (Illuminate\Http\Request $request) { try { Billing::handleWebhook('stripe', $request->getContent(), $request->headers->all()); } catch (\RuntimeException $e) { abort(403); // signature verification failed } return response('', 200); }); // 3. Refund a succeeded intent. Billing::refund($intent);
On a verified checkout.session.completed (payment_status paid) event, a real
Payment is recorded and the invoice becomes paid. Settlement is idempotent,
keyed by the Checkout Session id (the intent's external_id).
Amounts
Stripe's unit_amount is the smallest currency unit (cents) — the same as
laravel-billing's integer minor units — so amounts pass through directly, no
conversion needed.
Security
Signature verification is mandatory and includes replay protection:
Billing::handleWebhook('stripe', ...) throws if the HMAC-SHA256 signature does
not match or the timestamp is outside signature_tolerance (default 300s), so a
forged, tampered, or replayed notification never records a payment.
Testing
composer test # 12 tests, all HTTP mocked via Http::fake (no real API key needed)
License
MIT © Gusman Widodo. See LICENSE.