Skip to content

Repository files navigation

Laravel Payment Gateways

A Laravel application integrating six payment gateways, with emphasis on server-side verification and secure webhook handling.

Overview

Product page with all payment options

A single product page offering checkout through multiple providers — each implemented as an independent gateway controller.

Supported Gateways

Gateway Status Notes
Stripe ✅ Complete Checkout Session + signed webhook
Mollie ✅ Working Payment creation + return verification
Paystack ✅ Working Inline JS + server-side verification
PayPal ✅ Working Order creation + capture
Razorpay ✅ Working
2Checkout ⚠️ Limited Requires merchant account activation

Screenshots

Stripe

Stripe Checkout

Hosted Checkout Session with multi-currency display and Link support.

Mollie

Mollie Checkout

PayPal

PayPal Checkout

Paystack

Paystack Inline

Inline modal with test-flow simulation — success, bank authentication, and declined states.

2Checkout

2Checkout Form

Tokenized card fields via 2Pay.js — card data never touches the server.

Webhook Handling

Stripe webhook log showing 400 and 200 responses

Live output from stripe listen. The 400 block is a deliberate test with an invalid signing secret — every event is rejected before reaching the database. The 200 block below it is the same flow with the correct secret.

Note that Stripe fires several events per checkout (product.created, charge.succeeded, payment_intent.*, checkout.session.completed). All return 200, since a non-2xx response on an unhandled event would trigger indefinite retries — only checkout.session.completed is acted upon.

Triggering test events

Requirements

  • PHP 8.2+
  • Laravel 12
  • MySQL

Installation

git clone <repo-url>
cd Laravel_Payments_Methods
composer install
cp .env.example .env
php artisan key:generate
php artisan migrate
php artisan serve

Configuration

Add your gateway keys to .env:

STRIPE_SK=sk_test_xxx
STRIPE_WEBHOOK_SECRET=whsec_xxx

MOLLIE_KEY=test_xxx

PAYSTACK_PUBLIC_KEY=pk_test_xxx
PAYSTACK_SECRET_KEY=sk_test_xxx

PAYPAL_CLIENT_ID=xxx
PAYPAL_SECRET=xxx

Testing Webhooks Locally

stripe login
stripe listen --forward-to localhost:8000/stripe/webhook
stripe trigger checkout.session.completed

Copy the whsec_... printed by stripe listen into .env, then run php artisan config:clear.

Note the webhook route is excluded from CSRF verification in bootstrap/app.php — Stripe posts server-to-server and carries no token.

Concepts Implemented

Signature verification — every webhook is validated via HMAC against the raw request body before processing. Using $request->getContent() rather than $request->all() matters here: re-encoding the JSON would alter the bytes and break the signature.

Idempotency — a unique constraint on session_id prevents duplicate records when Stripe retries an event. Retries are expected behaviour, not edge cases, and the database constraint holds even under concurrent delivery where an exists() check alone would race.

Server-side verification — payment status is always read back from the gateway's API, never trusted from browser parameters.

Currency handling — amounts are stored in minor units (cents) as integers to avoid floating-point drift. Gateways differ here: Mollie expects a decimal string, Paystack and Stripe expect integers.

Test Cards

Gateway Card
Stripe 4242 4242 4242 4242
Mollie 4242 4242 4242 4242
Paystack 4084 0840 8408 4081
2Checkout 5555 5555 5555 4444

Any future expiry date and CVV.

License

MIT

About

Six payment gateway integrations in Laravel 12 — with signed webhooks, idempotency handling, and server-side verification

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages