Payments facade and PaymentType contract sit in front of whichever provider is configured, so a storefront authorizes, captures, and refunds the same way regardless of which driver is behind it.
Overview
Every payment provider, including the one Lunar ships by default, is a driver: a class implementingLunar\Core\Contracts\PaymentType and registered with the payment manager. Lunar ships an OfflinePayment driver out of the box for cash-in-hand or manual payment scenarios. Anything else, card payments included, is added as a driver.
lunarphp/stripeandlunarphp/paypalare Lunar’s first-party drivers. See Stripe and PayPal for installation and configuration.- Any other provider is added as a third-party driver registered through
Payments::extend().
Configuration
Payment configuration lives inconfig/lunar/payments.php. It defines the default payment type and a list of available types, each mapped to a driver.
Each type entry requires a
driver key naming the registered driver to resolve. Any other keys added to a type are opaque to Lunar itself: they are passed straight through to the driver’s setConfig() method, so a driver can read whatever configuration it needs from its own type entry.
driver must already be registered, either by a first-party add-on’s service provider or by a custom Payments::extend() call. See Registering a driver.
Taking a payment
Resolving a driver
Pass a payment type to thePayments facade to resolve the driver registered for it.
Setting the cart or order
Before authorizing, tell the driver what it is being paid against. Usecart() when paying from checkout; the driver creates the order if one does not already exist.
order() instead when paying against an order that already exists, for example capturing a deferred payment or taking payment on an order created outside of checkout. Setting a cart clears any previously set order and vice versa, so only one is active on the driver at a time.
Passing additional data
Providers that need data from the frontend, such as a payment intent ID or a token, receive it throughwithData().
withData() is driver-specific. The OfflinePayment driver, for example, merges a meta key onto the order’s own meta column when it authorizes.
Authorizing
Callauthorize() once the driver has a cart or order and any required data. All setter methods return self, so the call is typically chained.
authorize() returns Lunar\Core\DataObjects\PaymentAuthorize, or null when the driver could not do anything with the request.
A driver dispatches
Lunar\Core\Events\PaymentAttemptEvent with the PaymentAuthorize response when it attempts an authorization; listen for it to log attempts or trigger post-payment processing.
Allowing partial payments
allowPartialPayment() toggles whether the driver accepts less than the full cart or order total, for a deposit or part-payment. It defaults to false. First-party drivers read this from their own config (for example lunar.stripe.allow_partial_payment) rather than expecting it to be set per call, but it can be called directly on the driver too.
Intent and capture
Some providers authorize a payment immediately and charge the card in the same step; others authorize an intent that is captured, in full or in part, at a later time (for example once stock is confirmed, or an order ships). Whetherauthorize() captures immediately or only creates an intent depends on the driver and, for Stripe, its policy configuration (automatic or manual; see Stripe).
Either way, the outcome is recorded on the order’s Lunar\Core\Models\Transaction ledger: an intent-only authorization creates a transaction of type intent, and capturing it creates a related capture transaction. Once an intent exists, capture it with Order::capture():
Transaction model, its fields, and the capture guard rules (a capture can never exceed its intent).
Refunds
Refunds target a specificcapture transaction and can cover order lines, shipping, and a manual adjustment in a single request, through Order::refund():
Order::refund() validates the requested amount against the order’s available-to-refund balance and each line’s remaining refundable quantity, then calls the underlying transaction’s driver to perform the refund. Lunar\Core\DataObjects\PaymentRefund is what a driver’s refund() method returns:
Line-item refund allocations, the
RefundLine model, and the full validation rules are covered in the Refunds section of the Orders reference — this is the same Order::refund() call described there, from the payment side of the operation.
A refund can also be issued directly against a Transaction without going through Order::refund()’s line-allocation and balance checks:
Payment checks
Some providers return verification checks alongside a payment, such as 3D Secure, AVS, postal code, or CVC results. A transaction exposes these throughpaymentChecks(), which resolves the transaction’s driver and asks it for its checks.
paymentChecks() returns Lunar\Core\DataObjects\PaymentChecks, an iterable collection of Lunar\Core\DataObjects\PaymentCheck objects. Checking is opt-in per driver: it is not part of the PaymentType contract, so a driver that performs no verification returns an empty collection. See Payment checks in the extending guide for how a driver populates it.
Building a custom driver
To support a provider Lunar does not ship, implementLunar\Core\Contracts\PaymentType (typically by extending Lunar\Core\PaymentTypes\AbstractPayment) and register it with Payments::extend(). See Extending Payments for the full contract, amount and currency verification, and how transactions should be recorded.