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

Paypal Web Checkout Bundle Laravel Package

paymentsuite/paypal-web-checkout-bundle

Symfony bundle for adding PayPal Web Checkout to PHP applications. It provides configuration and service integration for initiating PayPal checkout payments and handling responses, helping developers implement PayPal payment flows with less boilerplate and consistent PaymentSuite wiring.

View on GitHub
Deep Wiki
Context7

Getting Started

The bundle is a thin Symfony 2.x integration around the PayPal Express Checkout (redirect) flow, built on top of paymentsuite/payment-core-bundle. Treat it as legacy glue rather than a self-contained payment SDK.

  1. Install: composer require paymentsuite/paypal-web-checkout-bundle. This will pull in paymentsuite/payment-core-bundle and the underlying PayPal library. Expect PHP 5.x / Symfony 2.3–2.8 constraints — on any modern Symfony/PHP you will need to fork or vendor-patch the composer.json.
  2. Enable the bundle in app/AppKernel.php:
    new PaymentSuite\PaypalWebCheckoutBundle\PaypalWebCheckoutBundle(),
    
    The core bundle (PaymentSuite\PaymentCoreBundle\PaymentCoreBundle) must be registered before it.
  3. Where to look first: DependencyInjection/Configuration.php and DependencyInjection/PaypalWebCheckoutExtension.php. Every config key (business, username, password, signature, sandbox, etc.) is defined there — do not guess from the README, the README is largely a stub.
  4. Configure credentials in config.yml, using sandbox values from developer.paypal.com (Classic API → API Signature):
    paymentsuite_paypal_web_checkout:
        business:    "[email protected]"
        username:    "…"
        password:    "…"
        signature:   "…"
        sandbox:     true
        debug:       true
    
  5. First use case: on your cart/checkout page, render the PayPal button that hits the bundle's "process" route. The user is redirected to PayPal, approves, comes back to your "success" controller, which calls SetExpressCheckout/DoExpressCheckoutPayment — the bundle handles the redirect and the DoExpressCheckoutPayment call for you.

The whole day-to-day surface is: one PaymentMethod service, three routes (process/success/fail), and a PaymentBridge that you own.

Implementation Patterns

1. Implement your PaymentBridge. This is the only class you write. The core bundle needs a bridge to convert your order into a monetary amount and to persist the transaction result:

use PaymentSuite\PaymentCoreBundle\PaymentBridge\PaymentBridgeInterface;

class OrderPaymentBridge implements PaymentBridgeInterface
{
    public function getAmount()      { return $this->order->getTotal(); }
    public function getCurrency()    { return 'EUR'; }
    public function getTransactionId() { return $this->order->getPaypalToken(); }
}

Register the bridge as a tagged service (paymentsuite.payment.bridge in Symfony 2.x).

2. Drive the flow through events. The bundle emits paymentsuite.payment.success / paymentsuite.payment.failed events from the success/fail controllers. Subscribe to them instead of putting business logic in controllers:

public function onPaymentSuccess(PaymentOrderSuccessEvent $event)
{
    $this->orderManager->markPaid($event->getPaymentBridge()->getTransactionId());
}

This is the only reliable extension point the bundle exposes — keep the controller thin, do the work in a listener.

3. Support multiple payment methods. The core bundle is designed for several methods side by side; register PayPal as one PaymentMethod, gate it behind a config flag, and branch on the PaymentMethod chosen in your checkout controller. Don't couple your order entity to PayPal directly.

4. Server-side redirect only. The bundle never exposes a JS SDK — the button is a plain form POST to your own route, and the bundle returns a RedirectResponse to paypal.com. This is fine for legacy integration but means no on-page card fields, no Apple Pay, no SCA-aware flows.

5. Test loop: sandbox buyer account (paypal.com → Developer → Sandbox accounts) → your process route → approve → your success URL. Use ngrok or a publicly reachable sandbox host — PayPal must be able to redirect back to you.

Gotchas and Tips

  • Abandoned. Last release April 2015, 0 dependents, 1 star. There is no maintenance, no security fixes, and PayPal has since deprecated the Classic NVP/SOAP API this bundle depends on. For anything new, use the PayPal Checkout REST SDK or paypal/paypal-checkout-sdk instead. Only reach for this if you are maintaining an existing Symfony 2 shop.
  • sandbox: true is a footgun in production. It silently redirects to sandbox.paypal.com, and payments look "successful" in tests only. Make it environment-driven (%kernel.debug%-adjacent), and assert it is false in your deploy checklist.
  • Credentials are three-part, not one. username/password/signature come from the Classic API Signature, not the REST client ID/secret. Mixing these up yields Authentication/Authorization Failed (10002) on the first SetExpressCheckout call.
  • Token expiry. PayPal TOKENs expire after ~15 minutes and are single-use. If the user sits on the PayPal page too long, the success callback arrives with an already-consumed token. Handle 10415/10416 gracefully and re-initiate rather than marking the order failed.
  • No IPN/webhook support here. The bundle relies on the synchronous redirect-back plus DoExpressCheckoutPayment. It does not subscribe to IPN. Without an IPN listener of your own, you cannot reconcile orders where the user closes the browser after paying — you will lose sales.
  • Amount/currency are float-sensitive. The bridge's getAmount() is passed straight through; PayPal expects a decimal string with 2 places and rejects mismatches between SetExpressCheckout, GetExpressCheckoutDetails, and DoExpressCheckoutPayment. Round once, in one place, in getAmount().
  • Debugging: set debug: true and inspect the bundle's logger channel; it dumps the raw NVP request/response. The single most useful thing during integration is the raw ACK/L_LONGMESSAGE0 pair — the exception messages are otherwise generic.
  • Extension points are scarce. Beyond the event listeners, your only hooks are replacing the PaymentBridge and overriding route names in config. If you need fee breakdown, shipping callbacks, or multi-currency, you will be patching the vendored bundle.
  • Firewall/CSRF: the success route must be reachable without an authenticated session (PayPal POSTs to it from outside), but still validate that the returned token matches a pending order you created — otherwise the endpoint is trivially forgeable.
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.
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels