Skip to main content
The shopper/payment package handles payment processing through a driver-based architecture. It sits between your storefront and payment providers, giving you a single API to initiate, authorize, capture, and refund payments, regardless of which provider you use. Every payment operation is recorded as a transaction, giving you a complete audit trail. The package automatically keeps your order’s payment status in sync as transactions succeed or fail.

How It Works

The payment system has four main pieces:
  1. PaymentManager resolves payment drivers by name (stripe, manual, paypal, etc.)
  2. PaymentDriver is the contract every provider must implement
  3. PaymentProcessingService wraps driver calls with transaction recording and status sync
  4. PaymentTransaction stores every operation for audit and debugging
Payment architecture showing how a payment flows from the Storefront through Shopper to the Payment Provider and back

Payment Drivers

Available Drivers

Using the Facade

The Payment facade gives you access to the driver manager:

The PaymentDriver Contract

Every driver implements Shopper\Payment\Contracts\PaymentDriver: Shopper provides an abstract Driver class with default implementations that throw PaymentException::notSupported(). Extend it and override only the methods your provider supports.

Processing Payments

The PaymentProcessingService is the recommended way to process payments. It wraps every driver call with:
  • Automatic transaction recording in the database
  • Order payment status synchronization
  • Consistent error handling

Initiating a Payment

This is the first step in any payment flow. It creates a payment session with the provider and records an initiate transaction. Here’s how the demo store initiates a payment at checkout:
The PaymentResult tells you what to do next:
  • clientSecret is set. Redirect the customer to a page with the Stripe.js Payment Element
  • redirectUrl is set. Redirect the customer to the provider (PayPal, 3D Secure, etc.)
  • Neither. The payment completed immediately (manual driver, for example)

Authorizing a Payment

Confirms a previously initiated payment. On success, the order’s payment_status is updated to Authorized.

Capturing a Payment

Captures an authorized payment. This is when funds are actually collected from the customer. On success, the order’s payment_status is updated to Paid.

Refunding a Payment

Refunds a captured payment. The service automatically determines whether the order becomes PartiallyRefunded or Refunded by comparing the total refunded amount against the order total.

Cancelling a Payment

Cancels a payment that hasn’t been captured yet. On success, the order’s payment_status is updated to Voided. No funds are collected.

Querying Transactions

Getting Available Payment Methods for a Zone

The service filters payment methods by zone and only returns methods whose driver is properly configured:
This is used at checkout to show only the payment methods available in the customer’s region. Here’s how the demo store loads payment methods:

Data Transfer Objects

PaymentResult

Every driver operation returns a PaymentResult. This is an immutable object that carries the outcome of the operation.

WebhookResult

Webhook handlers return a WebhookResult that tells you what happened on the provider side:

Payment Status

The PaymentStatus enum on the Order model tracks the overall payment state. It is updated automatically by the PaymentProcessingService as transactions succeed.

Status Transitions

Transaction Model

Every payment operation is recorded as a PaymentTransaction:

Database Schema

Enums

Querying Transactions

The paymentTransactions relationship is registered automatically when the payment package is installed.

Capture Methods

Shopper supports two capture strategies. This determines when the customer’s funds are actually collected.

Manual Capture (Authorize-then-Capture)

Recommended for physical goods. Funds are held on the customer’s card at checkout but only collected when you decide to capture. Checkout Authorize flow: customer places order, Shopper initiates payment with capture_method manual, provider holds funds, transaction recorded as authorized This gives you the flexibility to:
  • Verify stock availability before collecting payment
  • Cancel an order without processing a refund (and without refund fees)
  • Capture only when the order is ready to ship
When the order is ready to ship, the merchant captures the payment from the admin panel: Capture flow: merchant clicks Capture on order detail, Shopper calls capturePayment on the provider, funds are transferred, transaction recorded as captured and order marked as Paid

Automatic Capture

Funds are collected immediately when the customer confirms payment. Use this for digital products, subscriptions, or when fulfillment is instant.
Manual capture is the default for the Stripe driver. Authorization holds typically last 7 days (varies by card network), so you must capture within that window or the hold is released automatically.

Custom Drivers

You can create drivers for any payment provider: PayPal, Mollie, Razorpay, NotchPay, etc.

Step 1: Create the Driver Class

Extend the abstract Driver class and implement the methods your provider supports:

Step 2: Register the Driver

In a service provider, use Payment::extend() to register your driver. The closure is called lazily, only when the driver is first accessed.

Step 3: Add Configuration

Add the driver credentials to config/shopper/payment.php:
And in your .env:

Step 4: Create the Payment Method

Link the driver to a payment method record. This is what makes it selectable at checkout:
The driver column connects this payment method to your registered driver. When a customer selects “PayPal” at checkout and the PaymentProcessingService processes the order, it resolves the paypal driver and calls initiatePayment().

Payment Method Model

The Shopper\Core\Models\PaymentMethod model represents a payment option available at checkout. Each method is linked to a driver (Stripe, manual, PayPal, etc.) and can be scoped to specific zones. The model uses the HasSlug trait and the HasZones trait for zone-based availability:

Storefront Checkout Example

Here is a complete checkout flow showing how the demo store creates an order and processes payment.

Checkout Session

The checkout wizard stores each step’s data in the session:

Creating the Order

After the customer completes the checkout steps, convert the cart to an order and set the payment method:

Processing the Payment

Once the order exists, initiate the payment and handle the result:

Routes