Sunday, January 6, 2013

Disabled PayPal IPN when using Magento and eBay

The Problem

If you use the same PayPal account to collect payment for multiple stores (Magento, eBay, etc...), you may encounter an issue in which IPN is constantly being disabled on the PayPal side.  If you're struggling with this, the following may help.

Here's what's happening:  You've setup your PayPal "Notification URL" to point to Magento's IPN listener (https://{mydomain.com}/paypal/ipn (or something to that affect)).  The other storefront (like eBay) uses this same Notification URL you setup in PayPal.  So, with the Notification URL pointing to   https://{mydomain.com}/paypal/ipn specifically for Magento, when you get an order from your eBay store, PayPal tries to send an IPN message to your Magento listener.  Magento doesn't know what to do with it since the order didn't originate here so an error message is sent back to PayPal.  After a handful of these, PayPal disables IPN for your account.

The Solution

Magento sends the "Notification URL" to PayPal and that overrides whatever has been setup in your PayPal settings, so nothing to do as far as Magento goes.  What we need to do is to create another "listener" for the other store... this one will be a null/void listener, but will send a "success" message back to PayPal when called.  We'll set the "Notification URL" in PayPal to point to this null listener.  As stated before, Nofication URLs are baked into Magento requests and this null Notification URL will be ignored for all Magento IPNs and that'll hum along just fine.

  1. Over at paypaltech.com, there's a utility that will create a IPN listener script.  Go to https://www.paypaltech.com/SG2/ and copy the generated file (UPDATE: file has been removed.  See below.  Copy everything between the <-start-> and <-end-> in order to create your null_ipn.php file).  Paste this text into a file named null_ipn.php in the root of your Magento web folder.  
  2. Go to PayPal and log in.  Next, select "My Account" on the tab.  Next, navigate to profile->My Selling Tools->Instant Payment Notifications->Edit Settings.  For the "Notification URL", use the file that you just created (http://{yourdomain.com}/null_ipn.php

That's it.  IPNs received by Magento will be posted to your Magento orders and IPNs received by the null listener will send back a success message to PayPal.  No more disabled IPN every few days.

Note:  there are other ways to deal with these stray IPN notifications if you're so inclined... check them out at https://www.paypaltech.com/SG2/


I hope this helps,

webmaster, All American Hats

<--------------start null_ipn.php ------------------>

<?php

// Revision Notes
// 11/04/11 - changed post back url from https://www.paypal.com/cgi-bin/webscr to https://ipnpb.paypal.com/cgi-bin/webscr
// For more info see below:
// https://www.x.com/content/bulletin-ip-address-expansion-paypal-services
// "ACTION REQUIRED: if you are using IPN (Instant Payment Notification) for Order Management and your IPN listener script is behind a firewall that uses ACL (Access Control List) rules which restrict outbound traffic to a limited number of IP addresses, then you may need to do one of the following:
// To continue posting back to https://www.paypal.com  to perform IPN validation you will need to update your firewall ACL to allow outbound access to *any* IP address for the servers that host your IPN script
// OR Alternatively, you will need to modify  your IPN script to post back IPNs to the newly created URL https://ipnpb.paypal.com using HTTPS (port 443) and update firewall ACL rules to allow outbound access to the ipnpb.paypal.com IP ranges (see end of message)."


// read the post from PayPal system and add 'cmd'
$req = 'cmd=_notify-validate';

foreach ($_POST as $key => $value) {
$value = urlencode(stripslashes($value));
$req .= "&$key=$value";
}

// post back to PayPal system to validate
$header  = "POST /cgi-bin/webscr HTTP/1.1\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Content-Length: " . strlen($req) . "\r\n\r\n";

  //If testing on Sandbox use:
//$fp = fsockopen ('ssl://www.sandbox.paypal.com', 443, $errno, $errstr, 30);
$fp = fsockopen ('ssl://ipnpb.paypal.com', 443, $errno, $errstr, 30);


if (!$fp) {
// HTTP ERROR
} else {
fputs ($fp, $header . $req);
while (!feof($fp)) {
$res = fgets ($fp, 1024);
if (strcmp ($res, "VERIFIED") == 0) {
// check the payment_status is Completed
// check that txn_id has not been previously processed
// check that receiver_email is your Primary PayPal email
// check that payment_amount/payment_currency are correct
// process payment


// echo the response
echo "The response from IPN was: <b>" .$res ."</b><br><br>";

//loop through the $_POST array and print all vars to the screen.

foreach($_POST as $key => $value){

        echo $key." = ". $value."<br>";



}


}
else if (strcmp ($res, "INVALID") == 0) {
// log for manual investigation

// echo the response
echo "The response from IPN was: <b>" .$res ."</b>";

  }

}
fclose ($fp);
}
?>

<----------------end null_ipn.php ----------------->

3 comments:

  1. Hi,

    I like your solution. Works fine except that when sent back to Magento after a Paypal payment, I now land on the "empty cart" screen. With the standard IPN setup, I was sent on a "Thank you for your purchase" page. Any idea about how to solve this?

    Thanks,
    Marc

    ReplyDelete
  2. Seems like it works fine without an IPN URL in Paypal ... Magento indicates to Paypal where it should post the payment notification.

    ReplyDelete
  3. This comment has been removed by the author.

    ReplyDelete