Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Stripe Laravel Package

shopper/stripe

Stripe payment integration for the Shopper e-commerce admin panel, adding Stripe as a payment method at checkout so customers can pay by card securely. Handles Stripe payment intents and transactions within the Shopper ecosystem.

View on GitHub
Deep Wiki
Context7

Getting Started

shopper/stripe is the Stripe payment driver for Shopper, the Laravel e-commerce admin framework from Shopper Labs. Treat it as a component of the framework rather than a standalone library: it plugs a Stripe gateway into Shopper's payment-method abstraction so checkout, order state, and refunds flow through the same admin UI as any other driver.

First steps

  1. Install it alongside the core framework, not on its own:
    composer require shopperlabs/framework shopper/stripe
    
  2. Publish and inspect the config, then set credentials in .env:
    php artisan vendor:publish --tag=shopper-stripe
    
    STRIPE_KEY=pk_test_...
    STRIPE_SECRET=sk_test_...
    STRIPE_WEBHOOK_SECRET=whsec_...
    
  3. Look here first, in this order — the README is thin because it is a subtree split, so the source is the documentation:
    • composer.json → autoload namespace and the pinned stripe/stripe-php / framework versions
    • src/*ServiceProvider.php → what gets registered, config merges, route/webhook registration
    • config/stripe.php → keys, currency, capture mode, webhook path
    • the payment driver class (typically under src/Payments/ or src/Drivers/) → the methods Shopper calls at checkout
    • routes/ → the webhook endpoint and its middleware (CSRF exclusion matters)

First use case: enable Stripe as a payment method in the Shopper admin, run a test checkout that creates a PaymentIntent, confirm the card, and confirm the order flips to paid only after the payment_intent.succeeded webhook lands — not on the browser redirect.

Implementation Patterns

Drive everything from the order, not the session. Create the PaymentIntent server-side with the order total and attach your own identifiers in metadata (order_id, order_reference). The webhook handler is then a pure lookup, with no dependence on cart/session state that may have expired by the time Stripe calls you.

$intent = $stripe->paymentIntents->create([
    'amount'   => $order->total,          // minor units — see gotchas
    'currency' => config('shopper.stripe.currency'),
    'metadata' => ['order_id' => $order->id],
    'automatic_payment_methods' => ['enabled' => true],
]);

Persist $intent->id on the order/payment record immediately; that column is your join key for webhooks, refunds, and support tickets.

Webhook as the source of truth. Structure the handler as: verify signature → find order by metadata.order_id → guard on current state → transition. Keep it idempotent, because Stripe retries.

$event = \Stripe\Webhook::constructEvent(
    $request->getContent(),
    $request->header('Stripe-Signature'),
    config('shopper.stripe.webhook_secret')
);

match ($event->type) {
    'payment_intent.succeeded' => $this->markPaid($event->data->object),
    'payment_intent.payment_failed' => $this->markFailed($event->data->object),
    'charge.refunded' => $this->syncRefund($event->data->object),
    default => null,
};

Keep it behind Shopper's abstraction. Where possible, resolve the gateway through the container or Shopper's payment-method registry rather than new-ing Stripe classes in your controllers. That makes swapping to a test double, or adding a second provider later, a config change instead of a refactor.

Local development loop: use stripe listen --forward-to localhost:8000/stripe/webhook and copy the CLI-printed signing secret into your local env. It is a different secret from the dashboard endpoint's, and it changes each session.

Refunds and partial capture should be initiated from your admin against the stored PaymentIntent/Charge ID, then reconciled by the charge.refunded webhook — never assume the synchronous API response is the final word on order state.

Gotchas and Tips

  • Read-only split — this is the single biggest caveat. This repo is a mirror of shopperlabs/framework; issues and PRs belong upstream, and commits here can be force-pushed by the split job. Never vendor-patch it in place; fork or override instead.
  • Zero community signal. Zero stars and zero dependents means no Stack Overflow trail, no blog posts, no third-party tutorials. Budget real time for reading vendor/shopper/stripe/src. Pin the version in composer.json and read the upstream changelog before upgrading — the split gives you no release notes of its own.
  • Version alignment. The split's stripe/stripe-php constraint must agree with the framework version you run. A mismatch surfaces as confusing "class not found" or changed method signatures deep in the driver, not as a clean composer conflict.
  • Amounts are minor units. Stripe wants cents; if Shopper stores decimals you must convert. Watch zero-decimal currencies (JPY, KRW) and three-decimal ones (BHD, KWD) — naive * 100 silently overcharges.
  • Don't trust the redirect. Marking an order paid on return_url is the classic bug: users close the tab, or 3DS/SCA redirects interrupt the flow. Poll the intent on return for UX, but gate fulfilment on the webhook.
  • Webhook hygiene. Exclude the route from CSRF, raise the payload limits, and make the handler fast — return 200 promptly and push heavy work to a queue. Duplicate deliveries are normal; guard transitions rather than appending.
  • Config caching bites. php artisan config:cache after env changes; a stale cached config is the usual cause of "wrong webhook secret" in staging.
  • Extension points: the service provider's bindings and the published config are your levers. If you need custom behaviour (multi-currency routing, BACS-style delayed methods), prefer binding your own implementation of the driver interface over editing vendor code — that is the only upgrade-safe path with a subtree split.
  • Debugging tip: log the raw event.id and event->type for every webhook before parsing. When something "didn't work," the answer is almost always that the event never arrived or failed signature verification — Stripe's dashboard → Webhooks → attempt log tells you which within seconds.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource