['card'], 'line_items' => [ [ 'price_data' => [ 'currency' => 'usd', 'product_data' => [ 'name' => "Invoice {$invoice->invoice_number}", ], 'unit_amount' => (int) ($invoice->balance_due * 100), ], 'quantity' => 1, ], ], 'mode' => 'payment', 'success_url' => route('stripe.success', $invoice), 'cancel_url' => route('invoices.show', $invoice), 'metadata' => [ 'invoice_id' => $invoice->id, ], ]); return redirect($session->url); } public function webhook(Request $request) { $payload = $request->getContent(); $signature = $request->header('Stripe-Signature'); try { $event = \Stripe\Webhook::constructEvent( $payload, $signature, config('services.stripe.webhook_secret') ); } catch (\Exception $e) { return response('Invalid signature', 400); } match ($event->type) { 'checkout.session.completed' => $this->handleCheckoutSessionCompleted($event->data->object), 'charge.updated' => $this->handleChargeUpdated($event->data->object), default => null, }; return response('OK', 200); } protected function handleCheckoutSessionCompleted($session): void { $invoice = Invoice::find($session->metadata->invoice_id); if (! $invoice) { return; } Stripe::setApiKey(config('services.stripe.secret')); $paymentIntent = \Stripe\PaymentIntent::retrieve([ 'id' => $session->payment_intent, 'expand' => ['latest_charge.balance_transaction'], ]); $feeAmount = $paymentIntent->latest_charge?->balance_transaction?->fee ?? 0; Payment::create([ 'invoice_id' => $invoice->id, 'payment_date' => now(), 'status' => PaymentStatus::COMPLETED, 'payment_method' => PaymentMethod::CARD, 'reference' => $session->payment_intent, 'stripe_payment_intent_id' => $session->payment_intent, 'amount' => $session->amount_total / 100, 'fee_amount' => $feeAmount / 100, ]); } protected function handleChargeUpdated($charge): void { if (! $charge->payment_intent || ! $charge->balance_transaction) { return; } $payment = Payment::where('stripe_payment_intent_id', $charge->payment_intent)->first(); if (! $payment) { return; } Stripe::setApiKey(config('services.stripe.secret')); $balanceTransaction = \Stripe\BalanceTransaction::retrieve($charge->balance_transaction); // Always update the fee - handles both initial capture and any corrections $payment->updateQuietly([ 'fee_amount' => $balanceTransaction->fee / 100, ]); } public function checkoutTutorial() { Stripe::setApiKey(config('stripe.sk')); $session = \Stripe\Checkout\Session::create([ 'line_items' => [ [ 'price_data' => [ 'currency' => 'usd', 'product_data' => [ 'name' => 'send me money', ], 'unit_amount' => 3250, // in cents ], 'quantity' => 1, ], ], 'mode' => 'payment', 'success_url' => route('stripe.success'), 'cancel_url' => route('stripe.index'), ]); return redirect()->away($session->url); } public function success(Invoice $invoice) { return view('stripe.success', compact('invoice')); } }