I recommended to implement PayPal Express Checkout API.
There is a lot benefits to use this method instead that you use for creating a wordpress plugin. The main reason is that the response will be delivered immediately and you will not use a IPN methods to check if transaction is successful. Also you can add several recurring and one time payments in one session, including taxes and benefits. You will have the freedom to add all this stuff, practically everything - that's need for your wordpress plugin to be cool!
This is just as recommendation. Here one simple (PHP) example how to set a transaction with several products (also recurring payment):
// Parameters for SetExpressCheckout, which will be sent to PayPal
$padata['L_BILLINGAGREEMENTDESCRIPTION0'] = 'Product description';
$padata['L_BILLINGAGREEMENTDESCRIPTION0'] = $padata['L_BILLINGAGREEMENTDESCRIPTION0'] .
' $'.$product->price.'/month';
$padata['L_PAYMENTREQUEST_0_DESC0'] = $padata['L_BILLINGAGREEMENTDESCRIPTION0'] .
' $'.$product->price.'/month';
$padata['PAYMENTREQUEST_0_NOTIFYURL'] = 'http://site_url/paypal/ipn';
$padata['PAYMENTREQUEST_0_DESC'] = $product->name;
$padata['RETURNURL'] = 'http://site_url/paypal/returnurl';
$padata['CANCELURL'] = 'http://site_url/paypal/cancelurl';
$padata['PAYMENTREQUEST_0_CURRENCYCODE'] = 'USD';
$padata['PAYMENTREQUEST_0_PAYMENTACTION'] = 'SALE';
$padata['PAYMENTREQUEST_0_ITEMAMT'] = $product->price;
$padata['PAYMENTREQUEST_0_AMT'] = $product->price;
$padata['L_BILLINGTYPE0'] = 'RecurringPayments';
$padata['L_PAYMENTREQUEST_0_NAME0'] = $product->name;
$padata['L_PAYMENTREQUEST_0_NUMBER0'] = '322';
$padata['L_PAYMENTREQUEST_0_QTY0'] = '1';
$padata['L_PAYMENTREQUEST_0_AMT0'] = $product->price;
$padata['L_PAYMENTREQUEST_0_NAME1'] = 'Second Product name';
$hosteddata['L_PAYMENTREQUEST_0_DESC1'] = 'second product description';
$hosteddata['L_PAYMENTREQUEST_0_NUMBER1'] = $secondproduct->id;
$hosteddata['L_PAYMENTREQUEST_0_QTY1'] = '1';
$hosteddata['L_PAYMENTREQUEST_0_AMT1'] = $secondproduct->price;
$paypal_data = http_build_query($padata);
$httpParsedResponseAr = $this->PPHttpPost('SetExpressCheckout', $paypal_data);
//Respond according to message we receive from Paypal
if("SUCCESS" == strtoupper($httpParsedResponseAr["ACK"]) || "SUCCESSWITHWARNING" == strtoupper($httpParsedResponseAr["ACK"])){
//Redirect user to PayPal store with Token received.
$paypalurl ='https://www.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token='.$httpParsedResponseAr["TOKEN"].'';
header('Location: '.$paypalurl);
}else{
echo 'Error : '.urldecode($httpParsedResponseAr["L_LONGMESSAGE0"]).'';
}
Page returnurl:
$hosteddata['L_BILLINGAGREEMENTDESCRIPTION0'] = 'Recurring Description';
$hosteddata['L_BILLINGAGREEMENTDESCRIPTION0'] = $hosteddata['L_BILLINGAGREEMENTDESCRIPTION0'] . ' $'.$pr->price.'/month';
$hosteddata['L_PAYMENTREQUEST_0_NAME0'] = $pr->name;
$hosteddata['PROFILEREFERENCE'] = $GetExpressCheckoutDetails['L_PAYMENTREQUEST_0_NUMBER0'];
$hosteddata['PROFILESTARTDATE'] = date('Y-m-d') . 'T' . date('H:i:s').'Z';
$hosteddata['SUBSCRIBERNAME'] = $GetExpressCheckoutDetails['FIRSTNAME'] . ' ' . $GetExpressCheckoutDetails['LASTNAME'];
$hosteddata['TOKEN'] = urlencode($_POST['token']);
$hosteddata['DESC'] = $hosteddata['L_BILLINGAGREEMENTDESCRIPTION0'];
$hosteddata['AMT'] = $pr->price;
$hosteddata['BILLINGPERIOD'] = 'Month';
$hosteddata['BILLINGFREQUENCY'] = '1';
$hosteddata['TOTALBILLINGCYCLES'] = '12';
$hosteddata['REGULARTOTALBILLINGCYCLES'] = '1';
$hosteddata['VERSION'] = '74.0';
$hosteddata['MAXFAILEDPAYMENTS'] = '1';
$hosteddata['L_PAYMENTREQUEST_0_QTY0'] = '1';
$hosteddata['L_BILLINGTYPE0'] = 'RecurringPayments';
$hosteddata['L_PAYMENTREQUEST_0_ITEMCATEGORY0'] = 'Digital';
$hosteddata['L_PAYMENTREQUEST_0_AMT0'] = $pr->price;
$hosteddata['INITAMT'] = $pr->price;
$hosteddata['L_PAYMENTREQUEST_0_NUMBER0'] = $pr->id;
$hosteddata['PAYMENTREQUEST_0_NOTIFYURL'] = 'http://site_url/paypal/ipn';
$padata['L_PAYMENTREQUEST_0_NAME1'] = 'Second Product name';
$hosteddata['L_PAYMENTREQUEST_0_DESC1'] = 'second product description';
$hosteddata['L_PAYMENTREQUEST_0_NUMBER1'] = $secondproduct->id;
$hosteddata['L_PAYMENTREQUEST_0_QTY1'] = '1';
$hosteddata['L_PAYMENTREQUEST_0_AMT1'] = $secondproduct->price;
$paypal_data = http_build_query($hosteddata);
$hosted_saas_response = $this->PPHttpPost('CreateRecurringPaymentsProfile', $paypal_data);
I used a separate method to post parameters to paypal
private function PPHttpPost( $methodName_, $nvpStr_ ) {
$api_username = '[email protected]';
$api_password = 'QWEQWEWQEQWEQEQWE';
$api_signature = 'WQEQWEQWEQWEWQEQWEQWEQWEQWEQWE.cT';
$api_endpoint = "https://api-3t.paypal.com/nvp";
$version = '124.0';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $api_endpoint);
curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
$nvpreq = "METHOD=$methodName_&VERSION=$version&PWD=$api_password&USER=$api_username&SIGNATURE=$api_signature&$nvpStr_";
curl_setopt($ch, CURLOPT_POSTFIELDS, $nvpreq);
$httpResponse = curl_exec($ch);
if(!$httpResponse) {
exit("$methodName_ failed: ".curl_error($ch).'('.curl_errno($ch).')');
}
// Extract the response details.
$httpResponseAr = explode("&", $httpResponse);
$httpParsedResponseAr = array();
foreach ($httpResponseAr as $i => $value) {
$tmpAr = explode("=", $value);
if(sizeof($tmpAr) > 1) {
$httpParsedResponseAr[$tmpAr[0]] = $tmpAr[1];
}
}
if((0 == sizeof($httpParsedResponseAr)) || !array_key_exists('ACK', $httpParsedResponseAr)) {
exit("Invalid HTTP Response for POST request($nvpreq) to $api_endpoint.");
}
return $httpParsedResponseAr;
}