0

How to verify POST data comes from PayPal ?

I am working on a store that sells some products. The payment gateway is PayPal. Initially I set up a custom PayPal form and used the IPN responses to validate the data that is sent to me from PayPal.

Now my client has bought PayPal Advance Payment that uses PayPal PayFlow. The responses are not sent anymore through IPN (or are they?) instead they are returned by SILENT POST, basically when a transaction is perfomed on their end it is sent to a link of my choice and I process data through that link.

How do I validate the source of the POST data, so I know it is coming from PayPal and not a bad intentions user. I can not find any documentation on this. Also I want the same think when a users clicks "Cancel" button on paypal page and it is redirected to cancelation page on my website. I want that POST data source also verified.

Any thoughts on this ?

Suciu Lucian
  • 430
  • 4
  • 12
  • Are you saying that IPN doesn't work anymore? I still use it in my projects... – esqew Jun 28 '14 at 20:06
  • Doesn't paypal provide sample scripts? I found a Developer Guide: https://developer.paypal.com/docs/classic/payflow/integration-guide/ – user4035 Jun 28 '14 at 20:07
  • @esqew PayPal IPN works, but not for PayPal Advanced Payment. I have integrated Layout C from PayPal PayFlowLink and when paying through debit/credit card it send validations through IPN also through SILENT POST, but when Checkout with PayPal is selected the returned data is only sent through SILENT POST only. – Suciu Lucian Jun 28 '14 at 23:13
  • @user4035 I have integrated it, and it works, I also can validated my database based upon the SILENT POST, but it does not specify how to check if the POST data is coming from PayPal. – Suciu Lucian Jun 28 '14 at 23:16
  • IPN is in itself a silent POST, so I'm confused by what you're saying here. To my knowledge Payments Advanced should trigger IPN's just like any other PayPal payment would. Almost sounds like you were combining PDT and IPN before, and PDT is what doesn't work with Advanced. Does that sound like that could be what's going on? – Drew Angell Jun 29 '14 at 00:20
  • @Andrew Angell IPN and SILENT POST are two different things on PayPal. Here is the response I got from PayPal support: "Dear Lucian, You have to use Silent POST it is not Possible to use Notify URL with PayFlow link. Using the Silent Post URL ensures that the transaction data is passed back to your website when a transaction is completed. This occurs even if a customer closes his browser before returning to your site or if the PayPal-hosted Receipt page is disabled. " I think I know how do verify, I succeed I will post it as answers. Until Then All answers are welcomed! – Suciu Lucian Jul 01 '14 at 00:00
  • I don't think he's telling you that IPN doesn't work, he's simply saying you can't trigger it with the NotifyURL parameter. Instead, you have to have it configured in the PayPal account profile. I'd be interested to see some documentation that refers to "silent POST" as something separate from IPN. – Drew Angell Jul 01 '14 at 03:10
  • Look at [this link](https://www.paypalobjects.com/en_US/vhelp/paypalmanager_help/configuration.htm) seems like PayFlow simply refers to IPN as silent POST, but it's talking about the same thing. Remember, PayFlow was acquired by PayPal so some of the terminology that exists within PayFlow doesn't match what PayPal calls it. – Drew Angell Jul 01 '14 at 03:16
  • @andrew I will read the documentation in the next days. But look at the answer from support above, it clearly sates "You have to use SILENT POST, it is NOT possible to use Notify URL with PayFlow link". P.S I have the IPN link setup in the account profile, and it still does not trigger it when paying over Credit Card/Debit Card – Suciu Lucian Jul 02 '14 at 08:56
  • He's just talking about the parameter names. In the PayPal API's the parameter name is NotifyURL, but in the PayFlow Gateway API it's called SILENTPOST. Functionally, it's the same thing. – Drew Angell Jul 02 '14 at 12:31
  • @andrew They both do pretty much the same thing, but their are different things on PayPal and validation of source is done differently. I posted the solution I found below. If you are interested on the subject I can forward you the e-mails I sent back and forth to PayPal support. – Suciu Lucian Jul 09 '14 at 22:33

1 Answers1

1

First solution than I found, also some PayPal support guy has mentioned something similar but he could not offer details as he said he is not an expert.

Basically you have to run a TRANSACTION of type INQUIRY with the received PNREF from SILENT POST, if the response returns ORIGRESULT equal to 0 then the transaction exists in PayPal database under your account.

I also send the SECURE TOKEN ID and SECURE TOKEN with the inquiry, I do not know if it helps or not, I saw this as a solution somewhere and I tried sending just TOKEN and TOKEN ID without ORIGID and sometimes it worked sometimes not.

On the developer reference from PayPal is specified that on a TRXTYPE=I (INQUIRY TRANSACTION) the ORIGID must be specified.

Code below:

//GET POST DATA FROM SILENT POST
$data = $_POST;
$result = $data['RESULT'];
$pnref = $data['PNREF'];
$secure_token = $data['SECURETOKEN'];
$secure_token_id = $data['SECURETOKENID'];
$fee_amount = $data['AMT'];

if(!isset($result) || $result != '0'){
  //DO TRANSACTION FAILED OPERATIONS
  exit;
}

//CHECK IF PNREF ID EXISTS ON PAYPAL
$post_data = "PARTNER=yourpartnerid"
            ."&VENDOR=your_vendor"
            ."&USER=your_user"
            ."&PWD=your_password"
            ."&SECURETOKENID=" . $secure_token_id
            ."&SECURETOKEN=" . $secure_token
            ."&ORIGID=" . $pnref
            ."&TRXTYPE=I"
            ."&VERBOSITY=HIGH";


$ch = curl_init('https://payflowpro.paypal.com');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);       
$resp = curl_exec($ch);

$inquiry = array();
parse_str($resp, $inquiry);

//IF ORIGRESULT is 0 then PNREF/transaction exists.
if($inquiry['ORIGRESULT'] == '0' && $inquiry['RESPMSG'] == 'Approved'){ $validated = true; }
else{ $validated = false; }

if($result != 0 || $amount != 'your_correct_fee' || $validated == false){
  // DO TRANSACTION NOT VALID OR HAS FAILED OPERATIONS
  exit;
}

//DO TRANSACTION SUCCESSFULL OPERATIONS

The response from a INQUIRY looks this way:

RESULT=0&PNREF=ETHPC0BBF5FB&TRANSSTATE=8&ORIGRESULT=0&ORIGPNREF=ELFPB0E766F5&RESPMSG=Approved&AVSADDR=N&AVSZIP=N&ORIGPPREF=8GT035513B296200N&CORRELATIONID=97306f6456378&SETTLE_DATE=2014-07-09 14:11:36&TRANSTIME=2014-07-09 14:11:36&FIRSTNAME=John&LASTNAME=doe&AMT=0.0

Another way of doing it is checking the IP from which the SILENT POST is coming. I noticed all SILENT POST data comes from 173.0.81.65

$ip_address = $_SERVER['REMOTE_ADDR'];
if($ip_address != '173.0.81.65'){ exit; }

@Andrew Angel SILENT POST and NotifyURL is not the same thing. From the NotifyURL you can use IPN and data verification it is done very differently there because you receive different kind of post data string back.

I talked with PayPal support and they said NotifyURL and IPN is not available for PayPal Advanced Payments only for PayPal Payments Pro.

Indeed they both do the same function, but they are different things and source validation is done differently.

Hope this helps someone, waiting on opinions.

Suciu Lucian
  • 430
  • 4
  • 12