PayPal Embedded Chained Payments Working Example

Zero Gravity Programming

The PayPal embedded Chained Payments API is an answer to the problem of merchants wanting to keep customers on their site while completing a split payment transaction. Previously there was no way to remain on the merchantís site for a chained payment transaction. 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. However, if the customer checks the For faster checkout... box, the next time they buy something on your site, the transaction will occur inside a slick and elegant, truly embedded div, instead of a popup window.

Letís look at an example. This is a stripped-down, barebones embedded chained payment module that you could drop into your own site and have up and running in 2 minutes. It starts with one or more Pay with Paypal buttons:

So we click the 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 Log In button. To achieve this embedded flow, start by placing this in your html's head section:

<script type="text/javascript" src=""></script>

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

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

function MyEmbeddedFlow(embeddedFlow) {
this.embeddedPPObj = embeddedFlow;
this.paymentSuccess = function() {
this.paymentCanceled = function() {

var myEmbeddedPaymentFlow1 = new MyEmbeddedFlow(embeddedPPFlow1);

Click Log In

After clicking PAY, two different paypal functions are called under the hood: Pay() and SetPaymentOptions(). The unabridged Pay() function looks like this:

function Pay($isTest, $itemName, $amount, $primaryRecipientEmail, $secondaryRecipientEmail)
global $rootURL;
$nvpstr = "";
$lineBreak = <br>;
$ipnURL = $rootURL . "IPN.php"; // Let us know if you need something more custom!
$secondaryCut = 0.2; // represents 20% of the total amount -- you can change this to ANYTHING -- you can do percent or fixed amount, up to you
$returnURL = $rootURL . "success.php"; // this page is 100% customizable
$cancelURL = $rootURL . "fail.html"; // this page is 100% customizable
$invoiceID = "ZGP-" . generateTrackingID(); // change this to whatever you want, but make sure that each Invoice ID is unique!

$actionType = "CREATE";
$nvpstr .= "actionType=" . $actionType . $lineBreak; // standard payment
$nvpstr .= "¤cyCode=USD" . $lineBreak; // use any valid currency code
$nvpstr .= "&returnUrl=" . urlencode($returnURL) . $lineBreak; // the URL where customer is returned to after purchase
$nvpstr .= "&cancelUrl=" .urlencode($cancelURL) . $lineBreak; // the URL where customer is returned to after cancellation or abandonded purchase
$nvpstr .= "&feesPayer=PRIMARYRECEIVER" . $lineBreak; // Possible options in most cases: PRIMARYRECEIVER or SECONDARYONLY
$nvpstr .= "&memo=" . urlencode($itemName) . $lineBreak; // a note/description for this purchase
$nvpstr .= "&trackingId=" . $invoiceID . $lineBreak; // can be used to store your Invoice ID, or anything else you want
$nvpstr .= "&ipnNotificationUrl=" . urlencode($ipnURL) . $lineBreak;

// PRIMARY Recipient
$nvpstr .= "&receiverList.receiver(0).email=" . urlencode($primaryRecipientEmail) . $lineBreak; // must be a VERIFIED paypal account
$nvpstr .= "&receiverList.receiver(0).amount=" . $amount . $lineBreak; // must be the FULL amount before any splits to secondary recipients
$nvpstr .= "&receiverList.receiver(0).invoiceId=" . $invoiceID . $lineBreak; // recommend making this the same as the secondary invoiceId(s), but it can be different
$nvpstr .= "&receiverList.receiver(0).primary=true" . $lineBreak; // PRIMARY recipient (you can only have one PRIMARY!)
$nvpstr .= "&receiverList.receiver(0).paymentType=DIGITALGOODS" . $lineBreak; // for DIGITAL GOODS ONLY (see notes below for possible Payment Types)

// SECONDARY Recipient
$nvpstr .= "&receiverList.receiver(1).email=" . urlencode($secondaryRecipientEmail) . $lineBreak; // must be a VERIFIED paypal account
$nvpstr .= "&receiverList.receiver(1).amount=" . round(($amount * $secondaryCut),2) . $lineBreak; // must be equal to or less than the full transaction amount
$nvpstr .= "&receiverList.receiver(1).invoiceId=" . $invoiceID . $lineBreak; // recommend making this the same as the primary invoiceId, but it can be different
$nvpstr .= "&receiverList.receiver(1).primary=false" . $lineBreak; // SECONDARY recipient (you can have multiple SECONDARYs)
$nvpstr .= "&receiverList.receiver(1).paymentType=DIGITALGOODS" . $lineBreak; // for DIGITAL GOODS ONLY

// ================================================================================================================================================
// IMPORTANT: You can add up to 5 more SECONDARY recipients by simply repeating the SECONDARY Recipient block above, but incrementing the index. For example:

// SECONDARY Recipient #2 (3rd recipient)
//$nvpstr .= "&receiverList.receiver(2).email=" . urlencode($anotherEmail) . $lineBreak;
//$nvpstr .= "&receiverList.receiver(2).amount=" . ($amount) . $lineBreak;
//$nvpstr .= "&receiverList.receiver(2).invoiceId=" . $invoiceID . $lineBreak;
//$nvpstr .= "&receiverList.receiver(2).primary=false" . $lineBreak;
//$nvpstr .= "&receiverList.receiver(2).paymentType=DIGITALGOODS" . $lineBreak; // see notes below for possible Payment Types
// ================================================================================================================================================

/* Make the Pay call to PayPal */
$response = hash_call("Pay", $nvpstr, $isTest);

/* Return the response array */
return $response;

Click Close and arrive at the final page: success.php

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'.

IMPORTANT: If you want this module to require SHIPPING address, make the following 2 changes to the source code:
(1) Locate this line in PayPal_API.php: &receiverList.receiver(0).paymentType=DIGITALGOODS - change DIGITALGOODS to either GOODS or SERVICE.
(2) Uncomment this line in PayPal_API.php: &senderOptions.requireShippingAddressSelection=true (that's in SetPaymentOptions)

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