codewithdiki/payment-module
A Laravel payment module for integrating and managing payment flows, with support for payment methods, transactions, and gateway configuration. Designed to plug into Laravel applications through a simple, configurable structure.
composer require <vendor>/laravel-paypal
php artisan vendor:publish --tag=paypal-config
.env:
PAYPAL_MODE=sandbox
PAYPAL_CLIENT_ID=...
PAYPAL_CLIENT_SECRET=...
PAYPAL_BRAND_NAME="Acme Store"
config/paypal.php — that is where brand_name lands in v1.6.3 — then at the package service provider to see what is bound into the container and how the client is constructed.The fastest first use case is a single checkout flow: create an order server-side, redirect the buyer to PayPal, capture on return. The brand name is the label PayPal displays to the buyer on the PayPal-hosted pages, so setting it is a one-line config change that immediately makes the checkout look less like a generic integration.
$order = PayPal::createOrder([
'intent' => 'CAPTURE',
'purchase_units' => [[
'amount' => ['currency_code' => 'USD', 'value' => '49.99'],
]],
]);
return redirect($order['links'][1]['href']);
Keep brand name in config, not in code. Set it once per environment. For a single-tenant app this is the whole story: PAYPAL_BRAND_NAME in .env, config:cache, done.
Multi-tenant / white-label overrides. If one deployment serves multiple storefronts, override at runtime before building the order:
config(['paypal.brand_name' => $tenant->display_name]);
$order = app(PayPalClient::class)->createOrder($payload);
This only works reliably if the client reads config lazily. If the package resolves config in the constructor, resolve a fresh client per request (or per tenant) rather than injecting a singleton. Check the service provider binding before relying on this.
Wrap order creation in your own action/service. Don't scatter PayPal:: calls through controllers. A small CreatePayPalOrder action gives you one place to set the brand name, attach custom_id/invoice_id metadata, and normalize the response.
Capture on return, verify webhooks for truth. Redirect-based capture is fine for UX, but treat the webhook (PAYMENT.CAPTURE.COMPLETED) as the source of truth for fulfilment. Idempotency keys on capture prevent double-fulfilment on refresh.
Testing. Use the sandbox mode plus Http::fake() around the package's HTTP layer. Assert the outgoing payload includes the expected brand_name when you override it per tenant — this is the regression most likely to appear after a config refactor.
PAYPAL_BRAND_NAME, run php artisan config:cache in environments that cache config, or the old value persists. This bites people in staging constantly.How can I help you explore Laravel packages today?