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

freddyhaddad/paypal-ipn-bundle

A Symfony bundle for validating PayPal Instant Payment Notifications (IPN), with configurable listener services to verify payments and handle confirmed or invalid IPN callbacks in your application.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Symfony2-era bundle (last touched around the Symfony 2.x/3.x transition), so the first decision is whether it fits your stack at all. On Symfony 4+ it will not autowire cleanly without shims; on a legacy 2.8/3.4 app it drops in almost unchanged.

Minimal steps:

  1. composer require freddyhaddad/paypal-ipn-bundle (expect to pin "*@dev" or a specific tag; the package has effectively no release cadence).
  2. Register the bundle in app/AppKernel.php:
    new FreddyHaddad\PaypalIpnBundle\PaypalIpnBundle(),
    
  3. Import its routing so PayPal has an endpoint to POST to:
    # app/config/routing.yml
    paypal_ipn:
        resource: "@PaypalIpnBundle/Resources/config/routing.yml"
        prefix:   /paypal
    
  4. Publish/verify the bundle config (sandbox flag, PayPal endpoint, persistence options) under app/config/config.yml, then run the bundle's migration or doctrine:schema:update if it ships an IPN log entity.

Where to look first: the bundle's controller and its IPN entity/repository. The controller is the listener PayPal hits; the entity shows you exactly which raw fields are persisted before you decide what to do with them.

First use case: point the PayPal Sandbox IPN simulator at https://your-host/paypal/ipn (or your ngrok URL), send a test Completed payment, and confirm a row lands in the IPN log table. That single round trip validates routing, Doctrine mapping, and outbound verification against PayPal in one shot.

Implementation Patterns

Listener endpoint as the only entry point. Let the bundle's route be the URL you register in PayPal's account profile (or per-transaction notify_url). Don't build your own controller until you've confirmed the bundle's verification path works — it re-POSTs the raw body back to PayPal with cmd=_notify-validate, which is the part most people get wrong by hand.

Log-then-process. Treat the bundle as a durable inbox: it writes the raw IPN, you act on it afterward. A typical flow:

// inside your own service, triggered after the IPN row is persisted
if ($ipn->getPaymentStatus() !== 'Completed') {
    return; // handle Refunded/Reversed/Pending separately
}
if ($this->orders->findByTxnId($ipn->getTxnId())) {
    return; // idempotency: PayPal will retry
}
$this->orders->markPaid($ipn->getCustom(), $ipn->getMcGross(), $ipn->getMcCurrency());

Reconcile against your own records, never trust the payload alone. Verify receiver_email/business matches your PayPal account, mc_gross and mc_currency match the expected order total, and that custom maps to a real pending order. The bundle gives you the fields; the comparison is yours.

Bridge to domain events. Persist the IPN, then dispatch an application event (OrderPaid, PaymentRefunded) so controllers and mailers stay decoupled from the bundle. Keep the IPN row ID in the event so you can trace back to the raw payload during support.

Fast 200, slow work elsewhere. PayPal expects a prompt 200 OK and will retry on non-2xx or timeouts. Do the persistence and verification inline, then push anything heavy (inventory, emails, ERP sync) onto a queue or a kernel.terminate listener.

Sandbox and live in parallel. Run the bundle in sandbox mode against www.sandbox.paypal.com in dev/staging with the IPN simulator, and flip the endpoint to www.paypal.com in production via environment-specific config. Keep separate log tables or tag rows by environment so sandbox noise never pollutes real reconciliation.

Gotchas and Tips

  • Symfony2 EOL is the headline risk. With zero stars and no dependents, expect no security patches and no Symfony 4/5 support. Budget for forking it or replacing it with PayPal's Webhooks API (IPN is legacy and PayPal nudges new integrations toward webhooks).
  • PayPal sends application/x-www-form-urlencoded, not JSON. Read from $request->request, not $request->getContent() decoded as JSON. If you proxy through nginx, ensure the body isn't consumed before PHP sees it.
  • Verification must echo the exact raw body. Any reordering or re-encoding of parameters during the validate round trip causes a INVALID response. If you rewrite the controller, capture php://input verbatim.
  • Duplicates are normal, not bugs. PayPal retries IPNs for days. Enforce a unique index on txn_id (or txn_id + payment_status) and treat insert conflicts as success.
  • Firewall and CSRF exclusions. The IPN route must be anonymous — no form_login redirect, no CSRF token, and no locale/session middleware that could 302 the request. PayPal treats a redirect as failure.
  • Sandbox/live endpoint mix-ups. The most common "it worked in dev" failure is a sandbox-issued IPN being validated against the live endpoint (or vice versa). Assert the environment in config and log which endpoint was used.
  • Log the raw payload before parsing. Store the untouched POST body alongside the parsed columns; when PayPal support asks what was sent, this is the only reliable record.
  • Debugging checklist: route reachable anonymously → body parsed → validate response body is exactly VERIFIED → payment_status handled → receiver_email matches → amount/currency match → txn_id unique. Log each step with the IPN row ID.
  • Extension points are thin. The bundle's real value is the verified fetch + persistence; wrap it rather than modify it. Subclass or decorate the IPN service, and listen on Doctrine's postPersist for the entity if you need a hook without patching vendor code.
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/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
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