Skip to content
This repository was archived by the owner on Oct 25, 2026. It is now read-only.

Payments

Syed Ahmer Shah edited this page Oct 25, 2026 · 1 revision

Payments

Shoppers pay by card or cash on delivery. Card payments use Stripe Checkout in production and a built-in sandbox gateway locally (refused when APP_ENV=production).

Flow

  1. The order is created awaiting payment with its stock reserved for 30 minutes (PAYMENTS_EXPIRES_MINUTES).
  2. The shopper pays on the gateway.
  3. Only a signed, fresh, never-seen-before webhook with the right amount and currency marks the order paid. The return page never does.
  4. Unpaid orders are cancelled and restocked by payments:expire (every 5 minutes), and their offers released. Money that arrives after that is refunded automatically.

Refunds

Owners refund part or all of an order from the admin panel. Refunds can never exceed what was captured, and cancelling a paid order refunds the card.

Stripe setup

PAYMENTS_DRIVER=stripe
STRIPE_SECRET=sk_live_...
STRIPE_WEBHOOK_SECRET=whsec_...

Add a webhook endpoint at POST /webhooks/payments/stripe with these events:

  • checkout.session.completed
  • checkout.session.expired
  • checkout.session.async_payment_failed
  • charge.refunded

Safeguards

  • Amounts are computed on the server.
  • Webhooks are verified with HMAC-SHA256 (t=…,v1=…, constant-time compare, 5-minute replay window).
  • Every event id is stored once in webhook_events.
  • Order and payment rows are locked for every state change; gateway calls carry idempotency keys.

Code: app/Services/Payments/ (PaymentService, StripeGateway, SandboxGateway).

Clone this wiki locally