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 Ipn Bundle Laravel Package

orderly/paypal-ipn-bundle

A Symfony bundle for integrating PayPal Instant Payment Notifications (IPN). It validates incoming IPN callbacks and dispatches events, letting your application handle payment status updates through configurable listeners and services.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Symfony2 bundle, not a Laravel package, and the repository is archived. There is no ServiceProvider, no config/paypal-ipn.php, and no facade to composer require into a Laravel app. Treat it as a reference implementation for PayPal IPN handling rather than a drop-in dependency.

Where to look first in the source:

  1. The IPN validation service — this is the core. It takes the raw $_POST from PayPal and posts it back to PayPal's cmd=_notify-validate endpoint to confirm authenticity. This is the only genuinely non-obvious piece of logic in the bundle.
  2. The IPN log entity/repository — the bundle persists each incoming notification (raw payload, validation result, timestamp) via Doctrine. This is the model you will re-implement as an Eloquent model + migration.
  3. The event dispatch point — after validation, the bundle fires a Symfony event carrying the IPN data. This is the extension point where you would hook business logic, and the pattern you would mirror with a Laravel event() / listener or a queued job.

First use case to reproduce in Laravel: a single POST /webhooks/paypal route that (a) reads the raw request body, (b) posts it back to PayPal with cmd=_notify-validate, (c) writes the raw payload and validation verdict to an ipn_logs table, and (d) if VERIFIED, dispatches a job. That is the entire functional surface of this bundle.

Implementation Patterns

The bundle's structure maps cleanly onto a small Laravel module. The patterns worth copying:

Postback validation as a dedicated service. Isolate the "send raw body back to PayPal, check for the literal string VERIFIED" logic in a single class (App\Services\PayPalIpnValidator) with the endpoint as a config value. The bundle does this via a Symfony service with a configurable sandbox flag; mirror that with config/services.php:

'paypal' => [
    'ipn_url' => env('PAYPAL_IPN_URL', 'https://ipnpb.paypal.com/cgi-bin/webscr'),
],

Log-before-act. The bundle writes the notification to storage before firing events. Do the same: insert an ipn_logs row (raw body, txn_id, payment_status, verified boolean, received_at) inside the controller, then hand off. This gives you an audit trail for disputed payments and a replay source when something breaks.

Idempotent processing keyed on txn_id. PayPal retries IPNs. Add a unique index on txn_id (or ipn_track_id) and use insertOrIgnore / a firstOrCreate guard so duplicate deliveries are no-ops. The bundle's entity-per-IPN model naturally accommodates this; a raw save() in Laravel does not.

Validate-then-dispatch. Only after receiving VERIFIED (and after checking receiver_email, payment_status = Completed, mc_currency, and mc_gross against your order) should you fire side effects. In Laravel terms: controller → validator → dispatch(new ProcessPayPalPayment($payload)) on the queue. Return 200 OK to PayPal immediately; never do order fulfilment synchronously in the webhook request.

Event-driven extension. The bundle exposes a post-validation event so consumers don't modify vendor code. Reproduce with event(new PayPalIpnVerified($payload)) and multiple listeners, so one listener handles fulfilment, another handles notifications, another syncs accounting. This keeps the webhook controller thin as your PayPal surface grows.

Gotchas and Tips

  • Archived, Symfony2-era code. Expect old PHP constraints, Doctrine annotations rather than attributes, and Symfony\Component\HttpFoundation idioms. Don't try to shoehorn it in; port the ~200 lines of meaningful logic.
  • Send the raw body, not a re-encoded array. The single most common cause of INVALID responses is building the postback with http_build_query($request->all()) — parameter order and URL-encoding shift, and PayPal compares bytes. Use $request->getContent() verbatim, prefixed with cmd=_notify-validate&.
  • Endpoint matters. The modern host is https://ipnpb.paypal.com/cgi-bin/webscr (sandbox: ipnpb.sandbox.paypal.com). Older tutorials point at www.paypal.com, which still responds but is legacy — the bundle predates ipnpb, so don't copy its URL blindly.
  • VERIFIED is case-sensitive and must match exactly. PayPal returns the literal string with no body decoration; anything else (HTML error page, timeout body, empty response) means treat as invalid.
  • Never trust the POST before validation. Attackers can hit your webhook endpoint directly with forged payloads. Only the postback proves origin.
  • PayPal's postback is synchronous and can be slow. Set an explicit timeout on the HTTP client (10s is generous) and return a non-200 to trigger a PayPal retry if validation itself fails, so transient PayPal outages don't drop payments.
  • Check the business fields, not just the signature. VERIFIED only means "PayPal sent this." Compare receiver_email to your configured merchant, mc_gross and mc_currency to the order total, and payment_status to the expected value before fulfilling.
  • Keep the raw payload. Store the untouched JSON/form body alongside parsed columns. When a seller disputes a transaction three months later, the raw body is your evidence.
  • Log validation failures loudly. A spike in INVALID responses usually means a deployment changed proxy/body handling (e.g. TrimStrings middleware or PHP's post_max_size) and you're no longer echoing the original bytes.
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.
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route