PayPal Digital Goods Express Checkout Ė Working Sample


Zero Gravity Programming

The PayPal Digital Goods Express Checkout API is an answer to the problem of merchants wanting to keep customers on their site while completing a standard PayPal transaction. Previously the only way to fully remain on the merchantís site was to implement the monthly-fee product Payments Pro or Payflow. For DG Express Checkout, it is halfway true that the customer stays on your site. The reality is that a new browser window pops up, hovering over the web page (linked to the page by an iFrame inside a Div). The merchantís page remains in the background while the PayPal URL loads in the new floating browser, and thatís where the entire login and payment transaction occurs.

Letís look at an example. I built a sample app, which is a stripped-down version of an integration I built for a client recently. It starts with a cart page containing 3 products that you can individually pay for.



So we click a PAY with PayPal button...



...and a bit of PayPal javascript magic loads a div (containing an iFrame) in the browser window. And in this iFrame loads the PayPal payments web page. Click the Continue button, and the new browser window pops up, hovering over the top of your merchant site. To achieve this, start by placing this in your html's head section:

<script type="text/javascript" src="https://www.paypalobjects.com/js/external/dg.js"></script>

Then, place the following javascript right before your closing body tag:

<script type="text/javascript">
var embeddedPPFlow1 = new PAYPAL.apps.DGFlow( {trigger : 'btnS3KMCGMP3'});
var embeddedPPFlow2 = new PAYPAL.apps.DGFlow( {trigger : 'btnS3KMFMMP3'});
var embeddedPPFlow3 = new PAYPAL.apps.DGFlow( {trigger : 'btnS3KMHHMP3'});

function MyEmbeddedFlow(embeddedFlow) {
this.embeddedPPObj = embeddedFlow;
this.paymentSuccess = function() {
this.embeddedPPObj.closeFlow();
window.location.href = "http://www.zerogravityprogramming.com/PayPal/Articles/DigitalGoodsExpressCheckout/App/success.php";
};
this.paymentCanceled = function() {
this.embeddedPPObj.closeFlow();
window.location.href = "http://www.zerogravityprogramming.com/PayPal/Articles/DigitalGoodsExpressCheckout/App/fail.html";
};

}
var myEmbeddedPaymentFlow1 = new MyEmbeddedFlow(embeddedPPFlow1);
var myEmbeddedPaymentFlow2 = new MyEmbeddedFlow(embeddedPPFlow2);
var myEmbeddedPaymentFlow3 = new MyEmbeddedFlow(embeddedPPFlow3);
</script>


Please note the 2 urls listed. The first one is the success url, the second one is the cancel/failure url. After clicking PAY with PayPal, another thing that happens under the hood (and invisible to the end user) is the invocation of the SetExpressCheckout PayPal API method. The PHP code looks like this:

<?php
require_once("PayPal_API.php");

$Item = $_GET["item_number"];
$Desc = "";
$Price = 0.00;

if($Item == "S3KMCGMP3"){
$Desc = "Zero Gravity Widget #1";
$Price = 125.50;
}

if($Item == "S3KMFMMP3"){
$Desc = "Zero Gravity Widget #2";
$Price = 75.50;
}

if($Item == "S3KMHHMP3"){
$Desc = "Zero Gravity Widget #3";
$Price = 45.25;
}

$nvps = array();
$nvps["VERSION"] = "97.0";

// Single-item purchase
$nvps["METHOD"] = "SetExpressCheckout";
$nvps["RETURNURL"] = "http://www.zerogravityprogramming.com/PayPal/Articles/DigitalGoodsExpressCheckout/App/success.php";
$nvps["CANCELURL"] = "http://www.zerogravityprogramming.com/PayPal/Articles/DigitalGoodsExpressCheckout/App/fail.html";
$nvps["PAYMENTREQUEST_0_PAYMENTACTION"] = "Sale";
$nvps["PAYMENTREQUEST_0_NOTIFYURL"] = "http://www.yourdomain.com/PayPal/YourPayPalListener.php";
$nvps["PAYMENTREQUEST_0_AMT"] = "$Price";
$nvps["PAYMENTREQUEST_0_CURRENCYCODE"] = "USD";
$nvps["PAYMENTREQUEST_0_ITEMAMT"] = "$Price";
$nvps["L_PAYMENTREQUEST_0_NAME0"] = "$Desc";
$nvps["L_PAYMENTREQUEST_0_NUMBER0"] = "$Item";
$nvps["L_PAYMENTREQUEST_0_AMT0"] = "$Price";
$nvps["L_PAYMENTREQUEST_0_QTY0"] = "1";
$nvps["L_PAYMENTREQUEST_0_ITEMCATEGORY0"] = "Digital"; // specific to Digital Goods
$nvps["SOLUTIONTYPE"] = "Sole"; // accept plain old credit cards in addition to paypal accounts!

// IMPORTANT: Setting SOLUTIONTYPE to "Sole" enables guest checkout (pay with credit card). And since it's a digital good (and not physical), we don't need a shipping address.
$nvps["REQCONFIRMSHIPPING"] = "0";
$nvps["NOSHIPPING"] = "1";

// Send the API call to PayPal.
$response = RunAPICall($nvps);

// Did we get an error back from PayPal? Did PayPal not give us a token? If so, fail now.
if(($response["ACK"] != "Success" && $response["ACK"] != "SuccessWithWarning") || !strlen($response["TOKEN"])){
echo "Failure in PayPal API call: SetExpressCheckout<br>";
echo outputArrayValues($response);
die();
}

// If successful, grab our token and redirect the buyer to PayPal.
header("Location: https://www.sandbox.paypal.com/incontext?token=" . $response["TOKEN"]); // SANDBOX PayPal URL
//header("Location: https://www.paypal.com/incontext?token=" . $response["TOKEN"]); // LIVE PayPal URL
?>


Now click Login.



The first time I did a Digigoods integration I assumed I was doing something wrong at this point, because I thought the PayPal stuff would load into the iFrame (instead of a new popup window), which would be quite nice, elegant, and tightly integrated. So I called PayPal. Different Developer Support employees had different opinions and different levels of understanding on this, so for awhile I had to sift through misinformation. But ultimately I learned that PayPal will not allow Digigoods to be fully embedded in the merchant browser until after the user checks the 'Remember me' box--and thus the initial popup.



Click the Pay Now button.



At this point the transaction has completed, and PayPal (optionally) sends back to you a lot of useful info about the transaction. Although you already had most of this info, the value is in the fact that PayPal is acknowledging all this info, effectively handshaking and tying off the transaction. The PHP code to get that info looks like this:

<?php
require_once("PayPal_API.php");

$Token = $_GET["token"];
$PayerID = $_GET["PayerID"];

$nvps = array();
$nvps["VERSION"] = "65.1";

// get details of transaction (needed for Name & Desc in DoExpressCheckoutPayment)
$nvps["METHOD"] = "GetExpressCheckoutDetails";
$nvps["TOKEN"] = $Token;
$response = RunAPICall($nvps); // Send the API call to PayPal.

// Do the final action - complete the payment!
$nvps["METHOD"] = "DoExpressCheckoutPayment";
$nvps["PAYERID"] = $response["PAYERID"];
$nvps["PAYMENTREQUEST_0_PAYMENTACTION"] = "Sale";
$nvps["PAYMENTREQUEST_0_AMT"] = $response["AMT"];
$response = RunAPICall($nvps); // Send the API call to PayPal.
?>


At this point you may want to redirect either the iFrame or the parent window (you can do either). To redirect the parent you'll need to use a little javascript: top.location.href='AnotherPage.php'.

Try out the app  |  Download source code

If you need any help with your PayPal integration, I am a Certified PayPal Developer, and I charge competitive rates. Contact me.

Zero Gravity Programming