Tutorial: Use PayPal Adaptive Payments API (with Embedded Lightbox)

There are two things I am currently working on:

  1. School
  2. Integrating my Post Pay Counter WordPress plugin with PayPal, so that site administrators can pay their writers directly from their blog pages, without having to head to the PayPal website

Apparently, it turns out that you do not get to choose how much time you want to dedicate to the first point. That, matched with the fact that PayPal APIs are horrible and that the documentation is often useless, is making the whole process much longer than I thought. Meanwhile, I am sharing what I have come up with until now (which works pretty well, actually), scheduling a second part of the tutorial for when the job will be completed.

PayPal Adaptive Payments: what it is for

Adaptive payments handles payments between a sender of a payment and one or more receivers of the payment. You are an application owner, such as a merchant that owns a website, the owner of a widget on a social networking site, the provider of a payment application on mobile phones, and so on. Your application is the caller of Adaptive Payments API operations.

Standing to what I have been able to discover about PayPal’s different payment mechanisms over summer, Adaptive Payments represents the most flexible way to transfer funds from one account to another. Also, it seems the only method you can effectively integrate PayPal in your application. Adaptive Payments is in fact for those applications in which your account, as application developer, is not the one you are drawing funds from. Shortly, you need to move money on behalf of someone, and your application is the intermediary.

In my specific case, I needed a way to let administrators put their credentials into my plugin and have PayPal let me get money from their accounts and transfer it to their writers’ ones. Adaptive Payments method was really suitable because it allows six transactions per each request, so that it is possible to send different amounts to several people with only one API request. As bottom line (which I did not need and did not care to dive into), it also allows Chained Payments, in which the primary receiver passes part of the payment to other receivers, splitting the original amount.

We are almost beginning. Just let me give you the link to the complete, detailed, give-a-lot-for-granted PayPal official documentation. There is also a brilliant PHP class I have used (and that will be used in this tutorial) which is Angell EYE’s PayPal Payments Pro PHP Class. Apart from Adaptive Payments, you can execute almost any API-related PHP task with that class.

Application Workflow

This is how the PayPal-related part of the application will work:

  1. A form will contain all the data we need to complete the transaction (i.e. amount(s) and receiver(s) address).
  2. The transaction must then be prepared. When the submit button of the form is clicked, Javascript collects all the data and an AJAX request is issued to a PHP background page that takes them in and arranges the PayPal API request. PayPal will return a Pay Key, that our PHP page will return as result of the AJAX results. At this point we are still on the first page, nothing seems to have happened.
  3. Having the PayPal Pay Key makes it possible to execute the transaction, finally. Thus, the user is shown the PayPal forms and confirmation stuff that let them complete the payment.

Getting started with Adaptive Payments: the front-end

The first thing we are going to set up is the front end. There are two ways you can have it:

  1. In a new window. This is the simplest method, which you will get to work pretty easily. When the user clicks to execute the payment, a new window/tab is opened where the transaction is completed. User are then momentarily forced to leave your website, to which they will be automatically redirected when the payment is done.
  2. In a lightboxed iframe. Although this is a bit harder, it will make the user experience a lot better. Users never leave your website: the transaction happens on top of your page, while the content gets dark. This is what this tutorial walks you through.

First of all, we need two forms, either having its own submit button:

<form id="prepare_payment_form" action="#" method="post">
   <input id="prepare_payment" name="prepare_payment" type="submit" value="Prepare payment with PayPal" />
<form id="execute_payment_form" action="#" method="post" target="PPDGFrame">
   <input id="execute_payment" disabled="disabled" name="execute_payment" type="submit" value="Execute payment with PayPal" />
Note the target=”PPDGFrame” for the second form. The execute_payment submit button is disabled because we do not want users to execute the payment before they have actually prepared it. I have the preparation handled by AJAX, so that no reload is needed. I guess that if you are smart and masochist enough to be willing to deal with PayPal APIs and read this tutorial, you will also know how to Javascript-enable the execute_payment button and the like stuff (I am lazy enough not to provide you with that code, sorry).

You may also want to add somewhere a space for errors to be displayed, that will be invisible until some error comes up:

The first form, apart from its submit button, will also contain the data needed to fulfill the PayPal request. I am really keeping this simple, putting two email addresses and two amounts directly as form data, but you can fetch your data the way you need (e.g. store in the form only the user ID and then pulling from some database the other data when the request will be prepared by PHP).

<form id="prepare_payment_form" action="#" method="post">
   <input name="payment_1" type="text" value="50" /> 
   <input name="user_address_1" type="text" value="my_first_address@domain.com" />
   <input name="payment_2" type="text" value="25" /> 
   <input name="user_address_2" type="text" value="my_second_address@domain.com" />
   <input id="prepare_payment" name="prepare_payment" type="submit" value="Prepare payment with PayPal" />

Now, when the form is submitted, we will need to grab those data and send them to a secondary PHP page that will handle the whole thing.

<script type="text/javascript">// <![CDATA[
jQuery(document).ready(function($) {
   $(“#prepare_payment”).unbind(‘click’).click(function(e) {

So, from Javascript to English, when the prepare_payment button is clicked (row 3), the default action is prevented, so that the form is not sent and we allow AJAX to take over (row 4). As for the unbinding and subsequent binding, I have no clue why this happens, but it prevents the event from firing multiple times.

var data = {
   action: ‘the_php_page_that_will_handle_the_request.php’,
   payment_data: $(‘#prepare_payment_form’).serialize()

Quite easy: preparing the AJAX request data, which is actually simply a serialization of the form data. If you need more stuff, you can add more indexes to the array. You may also want to add a confirmation step, which is what I did:

var agree = confirm(‘You are just about to ask the Post Pay Counter to prepare a PayPal payment on your behalf. Note that this will really take money from your account and into the selected writers ones\’. Please double check what you are doing, it is only your fault if something goes wrong.\n\nIf what you have done is fine, then you can go on with the payment. Just be patient during loading, please. In a couple of seconds the execute payment button will be clickable and you will be able to confirm this action. From this moment on you can not modify the payment selection, but if you reload the page before clicking the execute payment button, nothing will be done.’);

if (!agree)
return false;

From the moment the payment is being prepared on the related button can not be clicked anymore. Moreover, to prevent changes to the form, all the text inputs are disabled:

$(‘#prepare_payment’).attr(“disabled”, “true”);
jQuery(“#prepare_payment_form :text”).each(function() {
   jQuery(this).attr(“disabled”, “true”);

Then we finally fire the AJAX request to get the Pay Key:

$.post(ajaxurl, data, function(response) {

   if(response.indexOf(“Error: “) != -1) {
      $(“#paypal_error”).css(“display”, “block”);
      jQuery(“#prepare_payment_form :text”).each(function() {
      return false;

   //Initialize PayPal embedded payment flow. Not loading it on document ready so that we only have it if user prepares payment, not just loads the page…
   var dgFlow = new PAYPAL.apps.DGFlow({trigger: ‘execute_payment’});

   //Store PayKey in the form action and enable execute payment button
   $(“#execute_payment_form”).attr(“action”, “https://www.sandbox.paypal.com/webapps/adaptivepayment/flow/pay?expType=light&payKey=” + response);

Inside the AJAX request, the first block is for error handling: if something bad happens the form button and inputs are clickable and editable again and the error is shown in the proper div.

If the request is successful, The PayPal flow is initialized, using as trigger parameter the HTML ID of the submit button of the second form, the execute_payment one.
Finally, the action of the execute payment form is updated with the PayPal URL and the Pay Key received as results of the AJAX request, and the submit button is enabled, so that the payment can be executed. (When that will happen, PayPal libraries will take over and do the job).

There is one more thing to add to the document.ready of the page:

jQuery(document).ready(function($) {
   if (window != top) {

This will ensure that when/if the transaction is over, either because the user canceled it or because it was complete, the iframe gets closed automatically. I have not found a better way to handle this, so if you Javascript guys have some better ways, I do really long to get rid of that crappy redirect.

Getting started with PayPal Adaptive Payments: the back-end

That was the front-end. Not let’s focus on the PHP page to which the AJAX request is issued.

include( 'angell_eye_class_dir/Pay.php' );

//Payment data is passed via AJAX serialized. We explode them by & (dividing fields from each other) and then for each of them we explode again, this time by = (separating fields names and fields values). I know it looks awful, but it is not that hard...
$receivers          = array();
$payment_data       = array();
$payment_data_temp  = explode( '&', $_POST['payment_data'] );
foreach( $payment_data_temp as $single ) {
   $yet_another_temp   = explode( '=', $single );
   $userid             = substr( $yet_another_temp[0], -1 );
   $receivers[] = array(
      'Amount'           => $single['payment'.$userid], 					  // Required.  Amount to be paid to the receiver.
      'Email'            => $single['user_address'.$userid], 					  // Receiver's email address. 127 char max.
      'InvoiceID'        => '', 								  // The invoice number for the payment.  127 char max.
      'PaymentType'      => 'PERSONAL', 							  // Transaction type.  Values are:  GOODS, SERVICE, PERSONAL, CASHADVANCE, DIGITALGOODS
      'PaymentSubType'   => '', 								  // The transaction subtype for the payment.
      'Phone'            => array('CountryCode' => '', 'PhoneNumber' => '', 'Extension' => ''),   // Receiver's phone number.   Numbers only.
      'Primary'          => ''								          // Whether this receiver is the primary receiver.  Values are boolean:  TRUE, FALSE

$paypal_result = execute_payment( TRUE, $paypal_API_email, $paypal_API_password, $paypal_API_signature, $paypal_currency_code, 'SENDER', $receivers, $_POST['current_page'] );
if( $paypal_result['Ack'] == 'Failure' )
   die( 'Error: '.$paypal_result['Errors'][0]['Message'] );


An array containing all the payment receivers (up to 6) is created, required fields are only Amount, Email and PaymentType. At this point, the only thing missing is the execute_payment function, which has the following parameters:

  • Whether you want to work in the PayPal sandbox for testing (TRUE) or not (FALSE);
  • The PayPal API email address of the account you are drawing funds from. For example, in my plugin it is the PayPal API email of the blog administrator;
  • The PayPal API password of the account you are drawing funds from;
  • The PayPal API signature of the account you are drawing funds from;
  • The code for the currency you want to use for payments, as EUR, USD, GBP
  • Who will pay for PayPal fees, SENDER or RECEIVER;
  • The page you want the user to be redirected when the Adaptive Payment will be done (or canceled).

That function consists in a customized version of the Angel EYE’s class Pay.php file as follows (I am stripping it of all the inline comments):


function execute_payment( $sandbox, $api_username, $api_password, $api_signature, $currency, $fees_payer, $receivers, $return_page ) { 

// Create PayPal object. 
$PayPalConfig = array( 
   'Sandbox' => $sandbox, 
   'DeveloperAccountEmail' => '', 
   'ApplicationID' => 
   'DeviceID' => '', 
   'IPAddress' => $_SERVER['REMOTE_ADDR'], 
   'APIUsername' => $api_username, 
   'APIPassword' => $api_password, 
   'APISignature' => $api_signature, 
   'APISubject' => '' 

$PayPal = new PayPal_Adaptive($PayPalConfig); 

// Prepare request arrays 
$PayRequestFields = array( 
   'ActionType' => 'CREATE', 
   'CancelURL' => $return_page, 
   'CurrencyCode' => $currency, 
   'FeesPayer' => $fees_payer, 
   'IPNNotificationURL' => '', 
   'Memo' => '', 
   'Pin' => '', 
   'PreapprovalKey' => '', 
   'ReturnURL' => $current_page, 
   'ReverseAllParallelPaymentsOnError' => '', 
   'SenderEmail' => '', 
   'TrackingID' => '' 

$ClientDetailsFields = array( 
   'CustomerID' => '', 
   'CustomerType' => '', 
   'GeoLocation' => '', 
   'Model' => '', 
   'PartnerName' => 'Always Give Back' 

$FundingTypes = array('ECHECK', 'BALANCE', 'CREDITCARD'); 
$SenderIdentifierFields = array( 'UseCredentials' => '' ); 
$AccountIdentifierFields = array( 
   'Email' => '', 
   'Phone' => array('CountryCode' => '', 'PhoneNumber' => '', 'Extension' => '') 

$PayPalRequestData = array( 'PayRequestFields' => $PayRequestFields, 'ClientDetailsFields' => $ClientDetailsFields, 'FundingTypes' => $FundingTypes, 'Receivers' => $receivers, 'SenderIdentifierFields' => $SenderIdentifierFields, 'AccountIdentifierFields' => $AccountIdentifierFields ); 
$PayPalResult = $PayPal->Pay($PayPalRequestData); 

return $PayPalResult; 

It will probably need some tweaking on your part, but I have hopefully explained how the hell PayPal Adaptive Payments are supposed to work!

  • Was this Helpful ?
  • yes   no

28 thoughts on “Tutorial: Use PayPal Adaptive Payments API (with Embedded Lightbox)

  1. Please can you give me the whole source code? because i have to integrate in one of my website , and its very difficult to learn now , can you give me all files ? in the form of zip ? please send me my gmail is yazdanhaider27@gmail.com or send me the link of demo here

    1. The full code I can provide is directly in the article. It is part of my paid product Post Pay Counter PRO, as I wrote, but that is not going to help you much anyway. Keep in mind that Adaptive Payments are part of the old PayPal API, so if developing something new it may be better to use their new API set.

  2. I am getting this error please help

    [Errors] => Array
    [0] => Array
    [Receiver] =>
    [Category] => Application
    [Domain] => PLATFORM
    [ErrorID] => 520003
    [ExceptionID] =>
    [Message] => Authentication failed. API credentials are incorrect.
    [Parameter] =>
    [Severity] => Error
    [Subdomain] => Application


    [Ack] => Failure
    [Build] => 34789162
    [CorrelationID] => 60d1a8b8d8e78
    [Timestamp] => 2017-06-21T21:55:10.921-07:00
    [PayKey] =>
    [PaymentExecStatus] =>
    [RedirectURL] =>
    [XMLRequest] => ReturnAllen_USPAYloclahostpaypal/class/1.2/Pay_Cancel.phpAPP-80W284485P519543TfU6vii_FXmw:APA91bF4ju4fd4k8TQof13UfIhc5IVJ1F1fUDf1EowYZe37d-Y3ya0bby47PEhp9etMALRoi0j0nvtJq3CqiBTKXRYSkMZyuHmHhLzDSOIQmpbvl0pf5pySmvp6C0i1o8eD5xo7HFCHC202.142.180.146Always Give BackUSD10.00anas.sartaj-buyer@armtech.com.pk46297754123-ABCDEFgUSDUSD5.00 anas.sartaj1@armtech.com.pk4084168659123-ABCDEFUSDUSDloclahostpaypal/class/1.2/Pay_Return.php
    [XMLResponse] => 2017-06-21T21:55:10.921-07:00Failure60d1a8b8d8e7834789162520003PLATFORMApplicationErrorApplicationAuthentication failed. API credentials are incorrect.

  3. Hi,
    I tried to implement your code but it gives following error.
    Error: Invalid request: Data validation warning(line 1, col 894): null
    Please help

  4. This script is not working for me

    [Errors] => Array
    [0] => Array
    [Receiver] =>
    [Category] => Application
    [Domain] => PLATFORM
    [ErrorID] => 580022
    [ExceptionID] =>
    [Message] => Invalid request parameter: email gagan3%40gmail.com is invalid
    [Parameter] => email
    [Severity] => Error
    [Subdomain] => Application

    [1] => Array
    [Receiver] =>
    [Category] => Application
    [Domain] => PLATFORM
    [ErrorID] => 580022
    [ExceptionID] =>
    [Message] => Invalid request parameter: email gagan2%40gmail.com is invalid
    [Parameter] => email
    [Severity] => Error
    [Subdomain] => Application


    [Ack] => Failure
    [Build] => 11853342
    [CorrelationID] => b03e23d615c90
    [Timestamp] => 2014-07-21T23:44:27.335-07:00
    [PayKey] =>
    [PaymentExecStatus] =>
    [RedirectURL] =>
    [XMLRequest] => ReturnAllen_USPAYhttp://localhost/payp/test.phpAPP-80W284485P519543T::1Always Give BackCADSENDERECHECKBALANCECREDITCARD50 gagan3%40gmail.comPERSONAL25 gagan2%40gmail.comPERSONALhttp://localhost/payp/test.phpdeep.waft@gmail.com
    [XMLResponse] => 2014-07-21T23:44:27.335-07:00Failureb03e23d615c9011853342580022PLATFORMApplicationErrorApplicationInvalid request parameter: email gagan3%40gmail.com is invalidemail gagan3%40gmail.com580022PLATFORMApplicationErrorApplicationInvalid request parameter: email gagan2%40gmail.com is invalidemail gagan2%40gmail.com

    Please help!

  5. Does anybody had this working within an iframe? Let say, Facebook iframe for example?

    The redirect part would break that does it?

    1. I have never specifically tested this with Facebook, so I don’t know. Moreover, the paypal documentation has something about the iframe 🙂

  6. Amico, gran bel tutorial! Ho sotto gli occhi la soluzione ai miei problemi che mi stanno facendo impazzire da giorni!
    L’unico problema è che di javascript e ajax purtroppo capisco ben poco, e difatti non riesco ad assemblare la prima parte del codice che hai postato.
    Non riesco a capire dove si chiudono le parentesi e dove posizionare le varie parti di codice, se l’una all’interno dell’altra o semplicemente in sequenza.
    La guida che hai scritto è davvero una manna dal cielo per chiunque abbia mai avuto la sfortuna di trovarsi davanti le api paypal, peccato però non trovare il codice completo (almeno la parte javascript) scritto in modo lineare da cima a fondo; per uno come me che non conosce ajax è come trovare l’acqua nel deserto e non poterla bere perchè non ci sono bicchieri 🙂 Davvero un peccato.
    Spero che deciderai di fare un collage di tutti i pezzi e magari un paio di file esportabili così da rendere il tuo tutorial davvero eccellente. Daresti un grande aiuto a molta gente. Grazie per l’attenzione e ancora complimenti!

    1. Ciao, scusa la risposa imbarazzentemente tardiva: mi ero ripromesso di rispondere e poi mi sono dimenticato.

      Un minimo di comprensione di javascript è necessaria per costruire un’applicazione del genere. In ogni caso, le parti di codice sono da porre in sequenza se non specificato diversamente, e le parentesi aperte nel primo frammento di JS vengano chiuse nel penultimo frammento di JS.

      Spero di averti aiutato! In caso sono sempre qui 🙂

  7. Thanks mate, works well (except the bug with ReturnURL that needs to be assigned $return_page instead of $current_page, the latter not being defined anywhere).

    To achieve a “unilateral implicit payment”, I had to do some tweaking indeed:
    – removed param “feesPayer” (needs to be the default value, i.e., EACHRECEIVER)
    – added param “senderEmail” (needs to be linked to a valid PayPal business account)

    These kind of payments allows a merchant to transfer funds to receivers who are not required to have an active PayPal account upfront (e.g., if you want to realise a “cash-out” system that allows users to redeem rewards).

    Here’s the link to the API reference: https://developer.paypal.com/webapps/developer/docs/classic/api/adaptive-payments/Pay_API_Operation/

    1. Still have to fully understand what implicit payments are but thanks for sharing, definitely gonna be helpful to me as well, will test them in the following days… The nasty thing is that fees can’t be paid by sender though…

    1. Hi, I would love to download your PHP library for PayPal’s Adaptive Payments API but when I go to your website I just get a database error… “Error establishing database connection” I will continue to google for other places to download it but so far haven’t found any. Thanks

  8. Thanks for this article! it was really helpful :D.
    I’ve only replaced $return_page instead of $current_page in the array $PayRequestFields.

      1. The sentence ‘PreapprovalKey’ => ” needs a comma at the end of the line. 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *