subscribe to the RSS Feed

Saturday, February 4, 2012

PayPal Instant Payment Notification (IPN)

Posted by leepeng on December 27, 2008

Consider the basic architecture of my previous Post (PayPal Integration)

At point A, we have stored the order record in the database as “Pending Payment” status. We will update the status to either “Paid” or “Failed” after PayPal redirect back to Thank you or Transaction cancelled page.

In some circumstances like internet failure or user accidentally close the browser while PayPal is redirecting back to the merchant’s page; the status of the oder will not be updated. Depends on the setup of the merchant page, this might cause other problem like email notification / e-receipt not been sent out, inconsistent of inventory etc.

Instant Payment Notification (IPN) is a facility provided by PayPal, which PayPal will notify the merchant website of the status of the transaction in the background via HTTP post to a specific URL. You can then perform the necessary actions like the Thank you page or the Transaction cancelled page to update the order status.

Here are the steps to setup IPN

- Login to PayPal, under Profile, click the Instant Payment Notification Preference link

- Turn IPN ON and put in your notification URL

- In the notification URL, you can have the sample code (in PHP) like the following:

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

$dumpinfo = “”;
foreach ($_POST as $key => $value) {
$value = urlencode(stripslashes($value));
$req .= “&$key=$value”;
$dumpinfo .= $key . ” = ” . urldecode($value) . “\n”;
}

// post back to PayPal system to validate
$header .= “POST /cgi-bin/webscr HTTP/1.0\r\n”;
$header .= “Content-Type: application/x-www-form-urlencoded\r\n”;
$header .= “Content-Length: ” . strlen($req) . “\r\n\r\n”;
$paypalurl = “www.paypal.com”;
$sockfptr = fsockopen ($paypalurl, 80, $errno, $errstr, 30);

// assign posted variables to local variables
$item_name = $_POST['item_name'];
$item_number = $_POST['item_number'];
$payment_status = $_POST['payment_status'];
if ($payment_status == “Pending”) {
$pending_reason = $_POST['pending_reason'];
}
$payment_amount = $_POST['mc_gross'];
$payment_currency = $_POST['mc_currency'];
$txn_id = $_POST['txn_id'];
$receiver_email = $_POST['receiver_email'];
$payer_email = $_POST['payer_email'];
$logfile = “paypal_log/”.gmdate(“Ymd”).”.log”;

if (!$sockfptr) {
$fptr = fopen($logfile, “a”);
fwrite($fptr, “[".gmdate("H:i:s")."]\nError opening socket to “.$paypalurl.”\n\n”);
fclose($fptr);
}
else {
fputs ($sockfptr, $header . $req);
$data = “”;
while (!feof($sockfptr)) {
$res = fgets ($sockfptr, 1024);
if (strcmp ($res, “VERIFIED”) == 0) {
$fptr = fopen($logfile, “a”);
fwrite($fptr, “[".gmdate("H:i:s")."]\n”.
“VERIFIED\n”.
“txn_id=”.$txn_id.”\n”.
“receiver_email=”.$receiver_email.”\n”.
“item_number=”.$item_number.”\n”.
“item_name=”.$item_name.”\n”.
“payment_status=”.$payment_status.”\n”.
($payment_status==”Pending”? (“pending_reason=”.$pending_reason.”\n”) : “”).
“payment_amount=”.$payment_amount.”\n”.
“payment_currency=”.$payment_currency.”\n”.
“payer_email=”.$payer_email.”\n\n”.
“—————————————-\n”.
$dumpinfo.”\n\n\n”);
fclose($fptr);

if ($payment_status == “Completed” || ($payment_status == “Pending” && $pending_reason==”verify”) || ($payment_status == “Pending” && $pending_reason==”multi_currency”)) {
//Payment successfull

}
else {
//Payment failed

}
}
else if (strcmp ($res, “INVALID”) == 0) {
$fptr = fopen($logfile, “a”);
fwrite($fptr, “[".gmdate("H:i:s")."]\n”.
“INVALID\n”.
“txn_id=”.$txn_id.”\n”.
“receiver_email=”.$receiver_email.”\n”.
“item_number=”.$item_number.”\n”.
“item_name=”.$item_name.”\n”.
“payment_amount=”.$payment_amount.”\n”.
“payment_currency=”.$payment_currency.”\n”.
“payment_currency=”.$payment_currency.”\n”.
“payer_email=”.$payer_email.”\n\n”.
“—————————————-\n”.
$dumpinfo.”\n\n\n”);
fclose($fptr);
}
$data .= $res;
}
fclose ($sockfptr);

fclose($fptr);
}

Basically PayPal will POST some information to our URL.
We need to then POST everything back to PayPal to verify (this is to prevent fraud post to our script)
PayPal will then return the status of the verification.
If the status is VERIFIED, then we can check the transaction status and process accordingly.

This sample script writes information received from PayPal to a log file for debugging purposes.

Note that when you use normal PayPal return URL and IPN together, please remember to check the status of your order before performing update. Return URL will be called once PayPal returned to Thank you page (or cancelled page) but IPN will be called by PayPal’s scheduler. We do not know which script will be called first hence checking like following is needed…

In either return / IPN script

….. assume PayPal return “Success”
if ($orderInfo["status"] == “Pending”) {
//process update script
}

Leave a comment, and if you'd like your own picture to show up next to your comments, go get a gravatar!

home | top