PayPal Digital goods feature allows you to sell digital goods online like eBooks, music file, video & images, script and programming codes as well.

In our previous blog post, we have covered the PayPal Express Checkout for Single Product using PayPal PHP SDK.

In this blog post, we are going to explain how we can use Paypal Express Checkout for Digital goods to sell goods online.

Paypal Express Checkout for Digital goods feature uses, ‘JavaScript with Express Checkout API’ to unify the checkout process for buyer of digital goods, where merchants wanting to keep customers on their site while completing a standard PayPal transaction.

The buyer can conveniently purchase digital goods during checkout with a minimum of clicks without leaving your website or interrupting their online activities. All transactions happen in an over layer light box.

 


 Paypal Express Checkout for Digital Goods using PayPal PHP Merchant SDK

PayPal Express Checkout in PHP for Digital Goods


Project Integration

In our last post, we have seen how to get Paypal App Id and App Secret, which is necessary to access PayPal PHP Merchant SDK.

Follow that post to learn how to get the credentials and put it in Configuration.php file of this project to setup the required settings.

Then you will be ready to run the project. You can also refer the install.txt file given in download code folder.

 


Digital Goods Flows

Let’s look at an example. Here we built a sample app(image selling site), which will show a copyright image with Buy now button. By clicking on buy now Paypal light box will appear. Now click on Login button which will appear on light box.

 

paypal express checkout for digital goods login

 

After clicking on log in button, one log in Model box will appear in which buyer has to log in via their existing Paypal Credentials.

paypal express checkout for digital goods login via paypal

 

Now buyer will be ready to Buy Digital goods without leaving website.

paypal express checkout for digital goods click on buy and get

 


 

Tutorial Scripts in detail:

Below are the details of the code used in this tutorial with proper explanation.

Index.php

This is the first file showing products details.

<html>
<head>
<title>PayPal Express Checkout - Digital Goods</title>
<link rel="stylesheet" type="text/css" href="css/style.css">
<link rel="stylesheet" href="css/flexslider.css" type="text/css">
</head>
<body>
<div id = "main">
<h1>PayPal Express Checkout for Digital Goods</h1>
<div id = "login">
<h2>FormGet Image Store</h2>
<hr/>
<!-- Place somewhere in the <body> of your page -->
<div class="flexslider">
<!-- image slider start here -->
<ul class="slides">
<li>
<div class="box-shadow-preview">
<img src="images/WMcoffee_cup.png"/>
</div>
<div id="detail">
<div id="description">
<h4>Description</h4>
<ul>
<li>File Name : Coffee Cup With Beans</li>
<li>File type : .png</li>
<li>File size : 800 x 505</li>
</ul>
</div>
<div id="buynow">
<div id="buynowbutton">
<div style="align: auto;">
<form method="POST" action="DGsetExpressCheckout.php">
<input type=hidden size=30 maxlength=32 name=id value="MQ==">
<input type="image" id="submitBtn1" name="submitBtn" src="images/buynow17.png"/>
</form>
</div>
</div>
</div>
</div>
</li>
<li>
<div class="box-shadow-preview">
<img src="images/WMfresh_jelly.png" />
</div>

<div id="detail">
<div id="description">
<h4>Description</h4>
<ul>
<li>File Name : Strawberry</li>
<li>File type : .png</li>
<li>File size : 800 x 505</li>
</ul>
</div>
<div id="buynow">

<div id="buynowbutton">
<div style="align: auto;">
<form method="POST" action="DGsetExpressCheckout.php">
<input type=hidden size=30 maxlength=32 name=id value="Mg==">
<input type="image" id="submitBtn2" name="submitBtn" value="Buy Now $1" src="images/buynow21.png"/>
</form>
</div>
</div>
</div>
</div>
</li>
<li>
<div class="box-shadow-preview">
<img src="images/WMCute_Baby.png" />
</div>
<div id="detail">
<div id="description">
<h4>Description</h4>
<ul>
<li>File Name : Cute Baby</li>
<li>File type : .png</li>
<li>File size : 800 x 505</li>
</ul>
</div>
<div id="buynow">

<div id="buynowbutton">
<div style="align: auto;">
<form method="POST" action="DGsetExpressCheckout.php">
<input type=hidden size=30 maxlength=32 name=id value="Mw==">
<input type="image" id="submitBtn3" name="submitBtn" value="Buy Now $1" src="images/buynow9.png"/>
</form>
</div>
</div>
</div>
</div>
</li>
<li>
<div class="box-shadow-preview">
<img src="images/WMred_flower.png" />
</div>
<div id="detail">
<div id="description">
<h4>Description</h4>
<ul>
<li>File Name : Flowers</li>
<li>File type : .png</li>
<li>File size : 800 x 505</li>
</ul>
</div>
<div id="buynow">

<div id="buynowbutton">
<div style="align: auto;">
<form method="POST" action="DGsetExpressCheckout.php">
<input type=hidden size=30 maxlength=32 name=id value="NA==">
<input type="image" id="submitBtn4" name="submitBtn" value="Buy Now $1" src="images/buynow13.png"/>
</form>
</div>
</div>
</div>
</div>
</li>
<li>
<div class="box-shadow-preview">
<img src="images/WMshopping.png" />
</div>
<div id="detail">
<div id="description">
<h4>Description</h4>
<ul>
<li>File Name : Shopping Sell</li>
<li>File type : .png</li>
<li>File size : 800 x 505</li>
</ul>
</div>
<div id="buynow">

<div id="buynowbutton">
<div style="align: auto;">
<form method="POST" action="DGsetExpressCheckout.php">
<input type=hidden size=30 maxlength=32 name=id value="NQ==">
<input type="image" id="submitBtn5" name="submitBtn" value="Buy Now $1" src="images/buynow7.png"/>
</form>
</div>
</div>
</div>
</div>
</li>
</ul>
</div>
</div>
<img id="paypal_logo" style="margin-left: 722px;" src="images/secure-paypal-logo.jpg">
</div>
<script>
top.dg.closeFlow();
</script>
<script type="text/javascript"
src="https://www.paypalobjects.com/js/external/dg.js">
</script>
<script>
var dg = new PAYPAL.apps.DGFlow({
trigger: "submitBtn1"
});
var dg = new PAYPAL.apps.DGFlow({
trigger: "submitBtn2"
});
var dg = new PAYPAL.apps.DGFlow({
trigger: "submitBtn3"
});
var dg = new PAYPAL.apps.DGFlow({
trigger: "submitBtn4"
});
var dg = new PAYPAL.apps.DGFlow({
trigger: "submitBtn5"
});
</script>
<script src="js/jquery.min.js"></script>
<script src="js/jquery.flexslider.js"></script>
<!-- Place in the <head>, after the three links -->
<script type="text/javascript" charset="utf-8">
$(window).load(function() {
$('.flexslider').flexslider();
});
</script>
</body>
</html>

 

DGsetExpressCheckout.php

This file contains code to set express checkout and process payment to PayPal.

<?php

require_once('../PPBootStrap.php');
session_start();
/*
* Digital goods payments combine JavaScript with the Express Checkout API to streamline the checkout process for buyers of digital goods.
* Digital goods are items such as e-books, music files, and digital images distributed in electronic format. The buyer can conveniently purchase digital goods during checkout with a minimum of clicks without leaving your website or interrupting their online activities
*
*/
$serverName = $_SERVER['SERVER_NAME'];
$serverPort = $_SERVER['SERVER_PORT'];
$url = dirname('http://' . $serverName . ':' . $serverPort . $_SERVER['REQUEST_URI']);

/*
* URL to which the buyer's browser is returned after choosing to pay with PayPal. For digital goods, you must add JavaScript to this page to close the in-context experience.
*/
$returnUrl = $url . "/DGdoExpressCheckout.php";
/*
* URL to which the buyer is returned if the buyer does not approve the use of PayPal to pay you. For digital goods, you must add JavaScript to this page to close the in-context experience
*/
$cancelUrl = $url . "/index.php";

/*
* Total cost of the transaction to the buyer. If shipping cost and tax charges are known, include them in this value. If not, this value should be the current sub-total of the order. If the transaction includes one or more one-time purchases, this field must be equal to the sum of the purchases. Set this field to 0 if the transaction does not include a one-time purchase such as when you set up a billing agreement for a recurring payment that is not immediately charged. When the field is set to 0, purchase-specific fields are ignored
*/
$id = base64_decode($_REQUEST['id']);
if ($id == 1) {
$amount = 17;
$currency = 'USD';
$itemname = 'coffee_cup.png';
} else
if ($id == 2) {
$amount = 21;
$currency = 'USD';
$itemname = 'fresh_jelly.png';
} else
if ($id == 3) {
$amount = 9;
$currency = 'USD';
$itemname = 'Cute_Baby.png';
} else
if ($id == 4) {
$amount = 13;
$currency = 'USD';
$itemname = 'red_flower.png';
} else
if ($id == 5) {
$amount = 7;
$currency = 'USD';
$itemname = 'shopping.png';
}

$orderTotal = new BasicAmountType();
$orderTotal->currencyID = $currency;
$orderTotal->value = $amount;

$taxTotal = new BasicAmountType();
$taxTotal->currencyID = 'USD';
$taxTotal->value = '0.0';

$itemDetails = new PaymentDetailsItemType();
$itemDetails->Name = $itemname;

$itemDetails->Amount = $orderTotal;
/*
* Item quantity. This field is required when you pass a value for ItemCategory. For digital goods (ItemCategory=Digital), this field is required.
*/
$itemDetails->Quantity = '1';
/*
* Indicates whether an item is digital or physical. For digital goods, this field is required and must be set to Digital
*/
$itemDetails->ItemCategory = 'Digital';

$PaymentDetails = new PaymentDetailsType();
$PaymentDetails->PaymentDetailsItem[0] = $itemDetails;

//$PaymentDetails->ShipToAddress = $address;
$PaymentDetails->OrderTotal = $orderTotal;
/*
* How you want to obtain payment. When implementing parallel payments, this field is required and must be set to Order. When implementing digital goods, this field is required and must be set to Sale
*/
$PaymentDetails->PaymentAction = 'Sale';
/*
* Sum of cost of all items in this order. For digital goods, this field is required.
*/
$PaymentDetails->ItemTotal = $orderTotal;
$PaymentDetails->TaxTotal = $taxTotal;

$setECReqDetails = new SetExpressCheckoutRequestDetailsType();
$setECReqDetails->PaymentDetails[0] = $PaymentDetails;
$setECReqDetails->CancelURL = $cancelUrl;
$setECReqDetails->ReturnURL = $returnUrl;
/*
* Indicates whether or not you require the buyer's shipping address on file with PayPal be a confirmed address. For digital goods, this field is required, and you must set it to 0. It is one of the following values:

0 – You do not require the buyer's shipping address be a confirmed address.

1 – You require the buyer's shipping address be a confirmed address.

*/
$setECReqDetails->ReqConfirmShipping = 0;
/*
* Determines where or not PayPal displays shipping address fields on the PayPal pages. For digital goods, this field is required, and you must set it to 1. It is one of the following values:

0 – PayPal displays the shipping address on the PayPal pages.

1 – PayPal does not display shipping address fields whatsoever.

2 – If you do not pass the shipping address, PayPal obtains it from the buyer's account profile.

*/
$setECReqDetails->NoShipping = 1;

$setECReqType = new SetExpressCheckoutRequestType();
$setECReqType->SetExpressCheckoutRequestDetails = $setECReqDetails;

$setECReq = new SetExpressCheckoutReq();
$setECReq->SetExpressCheckoutRequest = $setECReqType;

// storing in session to use in DoExpressCheckout
$_SESSION['amount'] = $amount;
$_SESSION['currencyID'] = $currency;
$_SESSION['ItemName'] = $itemname;

/*
* ## Creating service wrapper object
Creating service wrapper object to make API call and loading
Configuration::getAcctAndConfig() returns array that contains credential and config parameters
*/
$paypalService = new PayPalAPIInterfaceServiceService(Configuration::getAcctAndConfig());
$setECResponse = $paypalService->SetExpressCheckout($setECReq);
//echo '<pre>';
//print_r($setECResponse);
//echo '</pre>';

if ($setECResponse->Ack == 'Success') {

$token = $setECResponse->Token;
$payPalURL = 'https://www.sandbox.paypal.com/incontext?token=' . $token;
header("Location: " . $payPalURL);
/* echo "<br><br><br><br><br><br><br><br><a href=https://www.sandbox.paypal.com/incontext?token=$token />Click here to continue to https://www.sandbox.paypal.com/incontext?token=$token</a>"; */
} else {
var_dump($setECResponse);
echo "error in SetEC API call";
}
?>

 

DGdoExpressCheckout.php

DGdoExpressCheckout will call when  buyer’s browser is returned after choosing to pay with PayPal. For digital goods, you must add JavaScript to this page to close the in-context experience.

<?php
require_once('../PPBootStrap.php');

/*
* Digital goods payments combine JavaScript with the Express Checkout API to streamline the checkout process for buyers of digital goods.
* Digital goods are items such as e-books, music files, and digital images distributed in electronic format. The buyer can conveniently purchase digital goods during checkout with a minimum of clicks without leaving your website or interrupting their online activities
*
*/
$token = urlencode($_REQUEST['token']);
/*
* Unique PayPal buyer account identification number as returned in the GetExpressCheckoutDetails response
*/
$payerId = urlencode($_REQUEST['PayerID']);

//--------------------------------------------------------------
// this section is optional if values are retrieved from your database
$token = $_REQUEST['token'];
$getExpressCheckoutDetailsRequest = new GetExpressCheckoutDetailsRequestType($token);
$getExpressCheckoutReq = new GetExpressCheckoutDetailsReq();
$getExpressCheckoutReq->GetExpressCheckoutDetailsRequest = $getExpressCheckoutDetailsRequest;

$paypalService = new PayPalAPIInterfaceServiceService(Configuration::getAcctAndConfig());
$getECResponse = $paypalService->GetExpressCheckoutDetails($getExpressCheckoutReq);

/*
* The total cost of the transaction to the buyer. If shipping cost (not applicable to digital goods) and tax charges are known, include them in this value. If not, this value should be the current sub-total of the order. If the transaction includes one or more one-time purchases, this field must be equal to the sum of the purchases. Set this field to 0 if the transaction does not include a one-time purchase such as when you set up a billing agreement for a recurring payment that is not immediately charged. When the field is set to 0, purchase-specific fields are ignored.
*/
$orderTotal = new BasicAmountType();
$orderTotal->currencyID = $getECResponse->GetExpressCheckoutDetailsResponseDetails->PaymentDetails[0]->OrderTotal->currencyID;
$orderTotal->value = $getECResponse->GetExpressCheckoutDetailsResponseDetails->PaymentDetails[0]->OrderTotal->value;

//Details about each individual item included in the order.
$itemDetails = new PaymentDetailsItemType();
$itemDetails->Name = $getECResponse->GetExpressCheckoutDetailsResponseDetails->PaymentDetails[0]->PaymentDetailsItem[0]->Name;
$itemDetails->Amount = $orderTotal;
$itemDetails->Quantity = '1';

/*
* Item quantity. This field is required when you pass a value for ItemCategory. For digital goods (ItemCategory=Digital), this field is required
*/
$itemDetails->ItemCategory = 'Digital';

$PaymentDetails = new PaymentDetailsType();
$PaymentDetails->PaymentDetailsItem[0] = $itemDetails;

//$PaymentDetails->ShipToAddress = $address;
$PaymentDetails->OrderTotal = $orderTotal;

/*
* How you want to obtain payment. When implementing parallel payments, this field is required and must be set to Order. When implementing digital goods, this field is required and must be set to Sale.
*/
$PaymentDetails->PaymentAction = 'Sale';

/*
* Sum of cost of all items in this order. For digital goods, this field is required. PayPal recommends that you pass the same value in the call to DoExpressCheckoutPayment that you passed in the call to SetExpressCheckout
*/
$PaymentDetails->ItemTotal = $orderTotal;

$DoECRequestDetails = new DoExpressCheckoutPaymentRequestDetailsType();
$DoECRequestDetails->PayerID = $payerId;
$DoECRequestDetails->Token = $token;
$DoECRequestDetails->PaymentDetails[0] = $PaymentDetails;

$DoECRequest = new DoExpressCheckoutPaymentRequestType();
$DoECRequest->DoExpressCheckoutPaymentRequestDetails = $DoECRequestDetails;
$DoECReq = new DoExpressCheckoutPaymentReq();
$DoECReq->DoExpressCheckoutPaymentRequest = $DoECRequest;

/*
* ## Creating service wrapper object
Creating service wrapper object to make API call and loading
Configuration::getAcctAndConfig() returns array that contains credential and config parameters
*/
$paypalService = new PayPalAPIInterfaceServiceService(Configuration::getAcctAndConfig());
$DoECResponse = $paypalService->DoExpressCheckoutPayment($DoECReq);

if ($DoECResponse->Ack == 'Success') {
?>
<html>
<head>
<script src="js/jquery.min.js"></script>
<script>
$(document).ready(function() {
var link = document.createElement('a');
link.href = 'images/<?php echo $getECResponse->GetExpressCheckoutDetailsResponseDetails->PaymentDetails[0]->PaymentDetailsItem[0]->Name?>';
link.download = 'images/<?php echo $getECResponse->GetExpressCheckoutDetailsResponseDetails->PaymentDetails[0]->PaymentDetailsItem[0]->Name?>';
document.body.appendChild(link);
link.click();
top.dg.closeFlow();
});
</script>
<?php
/*
* TODO: add your logic that handles successful payment
*/
} else {
?>
<script>
alert("Payment failed")
top.dg.closeFlow();
</script>
<?php } ?>
<script type="text/javascript"
src="https://www.paypalobjects.com/js/external/dg.js"></script>
</head>
<body>
</body>
</html>

 

Style.css

Includes basic styling of HTML elements.

@import url(http://fonts.googleapis.com/css?family=Raleway);
h1{
text-align: center;
}
#main {
width: 950PX;
margin: 50PX auto;
font-family: raleway;
}
#login {
width: 834px;
float: left;
border-radius: 10px;
font-family: raleway;
border: 2px solid #ccc;
padding: 10px 40px 11px;
margin: 16PX;
}
h2 {
background-color: #FEFFED;
text-align: center;
border-radius: 10px 10px 0 0;
margin: -10px -40px;
padding: 15px;
}
hr {
border: 0;
border-bottom: 1px solid #ccc;
margin: 10px -40px;
margin-bottom: 30px;
}
#description{
width: 50%;
float:left;
color: white;
padding-left: 3%;
}
#description h4{
margin-top: 5px;
margin-bottom: 5px;
}
#buynow{
width: 47%;
float: right;
}
#buynowbutton {
margin-left: 53%;
margin-top: 8%;
margin-right: 0%;
}
#detail{
width: 98%;
background: rgba(0,0,0,.6);
margin-top: -120px;
height: 100px;
position: absolute;
border-top: 1px solid;
border-bottom: 1px solid;
border-color: rgba(255,255,255,0.1);
margin-left: 1%;
margin-right: 1%;
}

input[type=text]{
width: 90%;
padding: 10px;
margin-top: 20px;
border: 1px solid #ccc;
padding-left: 5px;
font-size: 17px;
font-family: raleway;
}
input[type=image]{
width: 90%;
height: 40%;
border-radius: 3%;
}
input[type=submit]{
width: 100%;
margin-top: 20px;
background-color: #FFBC00;
color: white;
border: 1px solid #FFCB00;
padding: 10px;
font-size: 17px;
cursor: pointer;

margin-bottom: 0px;
}
.box-shadow-preview{
position: relative;
background-color: #FFFFFF;
border-width: 7px;
border-style: solid;
border-color: white;
border-radius: 0px;
box-shadow: 0px 5px 17px 1px #99A3AD, 0px 0px 40px #EEEEEE;
}

 

Conclusion :

After reading the above post, I am sure you will give a try to the script provided and implement it in your own projects as well. Feel free to visit our website again in the future to get in touch with new coding tricks. You can let us know about your feedback in the space provided below :)