25

I want to create a simple transaction on my Web Site where after the person's transaction completes, I want paypal to redirect the user to go to a place on my site and I want PayPal to provide me with details so I can use PHP to parse it and email them the link to their purchase. I'm not sure what notify_url does? Thanks

jmasterx
  • 52,639
  • 96
  • 311
  • 557

4 Answers4

60

PayPal works like this:

You have a form with a "buy" button. When that is clicked, it sends information (product, price, your account name, etc) to PayPal.

The buyer then agrees to pay you and when the transaction is completed, PayPal send an "IPN" (instant payment notification) to your notify URL - it sends POST data to that URL for your server to process. You reply to PayPal to ask if they sent the POST data (rather than an imposter) and if they then answer that it is a real transaction, you can release the product to the customer. Note that this all happens in the background while your buyer is still "at" the PayPal website.

There is a final optional stage, which is that PayPal returns the buyer to your website. In this case, they send the buyer back to your "return" url, and they can (optionally) pass back the transaction data again, (they call this PDT). And you can again check with Paypal if this is a valid transaction and provide a download etc at that point.

The most difficult bit that nobody explains is that the buyer doesn't get redirected to your notify URL. i.e. the "visitor" to your website's notify URL is PayPal, not the buyer, so this doesn't happen as part of your buyer's session. If you wish to persist a session across the three parts of this process, then you need to create a means of tracking the buyer in your form, and pass that to PayPal in a field of the form called "custom". This data is passed back to you in the IPN and PDT data, and you can use this to re-establish a connection with the original user session.

You really need to implement both IPN and PDT - if the IPN email fails then you have PDT as a backup. And if the user closes their web browser before they are redirected back to your PDT page, then you have sent an IPN email as a backup.

Search on IPN and PDT and you'll find quite a lot of information. PayPal also have full documentation and example scripts.

Jason Williams
  • 56,972
  • 11
  • 108
  • 137
  • Perhaps I am misunderstanding, but I thought that it's either/or. I thought that you can either have PDT on your merchant profile, or IPN, but not both. Can you show me how to setup both PDT and IPN at the same time? – Volomike Oct 03 '11 at 19:30
  • @Volomike: Read the last two paragraphs [here (paypal)](https://cms.paypal.com/uk/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_admin_IPNIntro) and other SO answers like [this one](http://stackoverflow.com/questions/2836779/paypal-ipn-vs-pdt) – Jason Williams Oct 09 '11 at 12:30
  • @JasonWilliams The link seems broken. – Bhargav Nanekalva Feb 08 '15 at 06:51
  • Broken, and after only 3 years? :-) ... here's [a more current one](https://developer.paypal.com/docs/classic/ipn/ht_ipn/), on the PayPal developer site. Their docs are really pretty good, and worth reading through several times until you are sure you understand everything. If still confused, web search engines will bring up a lot more info. – Jason Williams Feb 08 '15 at 19:11
  • A small correction: `The buyer then agrees to pay you and when the transaction is completed, PayPal send an "IPN" (instant payment notification) to your notify URL` well an IPN is send even if transaction is not completed (as in payment is pending). Also, `Note that this all happens in the background while your buyer is still "at" the PayPal website` is not technically true, Paypal will send notifications to the listener (or handler) long after (days after) the user is back to the website, in at least two cases: handler didn't respond or when dealing with subscriptions etc. – bg17aw Dec 16 '15 at 21:52
6

Notify URL should lead to the script that saves the returned data from PayPal, such as:

   /** Fetch order from PayPal (IPN reply)
    * @return int received ID of inserted row if received correctly, 0 otherwise
    */
   function FetchOrder()
   {
   $transactionID=$_POST["txn_id"];
   $item=$_POST["item_name"];
   $amount=$_POST["mc_gross"];
   $currency=$_POST["mc_currency"];
   $datefields=explode(" ",$_POST["payment_date"]);
   $time=$datefields[0];
   $date=str_replace(",","",$datefields[2])." ".$datefields[1]." ".$datefields[3];
   $timestamp=strtotime($date." ".$time);
   $status=$_POST["payment_status"];
   $firstname=$_POST["first_name"];
   $lastname=$_POST["last_name"];
   $email=$_POST["payer_email"];
   $custom=$_POST["option_selection1"];
   if ($transactionID AND $amount)
      {
      // query to save data
      return $this->insertID;
      }
   else
      {
      return 0;
      }
   }

You can also choose to verify an order later on:

/** Verify PayPal order (IPN)
    * PayPal returns VERIFIED or INVALID on request
    * @return bool verified 1 if verified, 0 if invalid
    */
   function VerifyOrder()
   {
   $_POST["cmd"]="_notify-validate";
   $ch=curl_init();
   curl_setopt($ch,CURLOPT_HEADER,0);
   curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
   curl_setopt($ch,CURLOPT_USERAGENT,"your agent - replace");
   curl_setopt($ch,CURLOPT_URL,"https://www.paypal.com/cgi-bin/webscr");
   curl_setopt($ch,CURLOPT_POST, 1);
   foreach ($_POST as $key=>$value)
      {
      $string.="&".$key."=".urlencode(stripslashes($value));
      }
   curl_setopt($ch, CURLOPT_POSTFIELDS, $string);
   $result=curl_exec($ch);
   if ($result=="VERIFIED") return 1;
   else return 0;
   }
dusoft
  • 11,289
  • 5
  • 38
  • 44
3
$tx=$_REQUEST['tx'];

$paypal_url='https://www.paypal.com/cgi-bin/webscr?cmd=_notify-synch&tx='.$tx.'&at=token here';

$curl = curl_init($paypal_url);

$data = array(

"cmd" => "_notify-synch",

"tx" => $tx,

"at" => "token here"


);                                                                    

$data_string = json_encode($data); 

curl_setopt ($curl, CURLOPT_HEADER, 0);

curl_setopt ($curl, CURLOPT_POST, 1);

curl_setopt ($curl, CURLOPT_POSTFIELDS, $data_string);

curl_setopt ($curl, CURLOPT_SSL_VERIFYPEER, 0);

curl_setopt ($curl, CURLOPT_RETURNTRANSFER, 1);

curl_setopt ($curl, CURLOPT_SSL_VERIFYHOST, 1);

$headers = array (

'Content-Type: application/x-www-form-urlencoded',

'Host: www.paypal.com',

'Connection: close'

);

curl_setopt ($curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);

curl_setopt ($curl, CURLOPT_HTTPHEADER, $headers);

$response = curl_exec($curl);

$lines = explode("\n", $response);

$keyarray = array();

if (strcmp ($lines[0], "SUCCESS") == 0) {

for ($i=1; $i<count($lines);$i++){

list($key,$val) = explode("=", $lines[$i]);

$keyarray[urldecode($key)] = urldecode($val);

}


$first_name=$keyarray['first_name'];

$last_name=$keyarray['last_name'];

$payment_status=$keyarray['payment_status'];

$business=$keyarray['business'];

$payer_email=$keyarray['payer_email'];

$payment_gross=$keyarray['payment_gross'];

$mc_currency=$keyarray['mc_currency']; 

}
krishna singh
  • 1,023
  • 1
  • 11
  • 15
0

When parsing the PDT response I'm using parse_str. Since the body of the response is url encoded it's just a matter of replacing the line breaks with ampersands- like this

$result = curl_exec($ch);    
//replace the breaks with '&'
$r_string = str_replace("\n", "&", $result);
//parse the response into a key->value array
                    parse_str($r_string, $this->details);
                    if(!isset($this->details['SUCCESS'])){
                 //the "SUCCESS" or "FAIL" response is the first key   
    return FALSE;
                    }
                    else{
//the values of the response are now in an array
                        return TRUE;

                    }

depending on the application you can even leave out the second parameter ($this->details) and the values are set as global variables.

EthanK
  • 600
  • 5
  • 17