PayPal Express Checkout with PHP

Paypal is the most popular and convenient way to get paid. If you are selling some products in your website, you should definitely use Paypal payment gateway, why? because it’s free and there are over 350 million Paypal users all over the world who would happily purchase your products.

In this tutorial let us find-out how we can use Paypal Express Checkout in websites to sell some products instantly.


To test your PayPal store in a local server, you need to signup for PayPal Developer account and use their sandbox. See creating PayPal Sandbox account. To sell your products in real world, you need to signup for real Paypal account and obtain sellers information needed for the configuration file.

As you can see we have four PHP files in this tutorial index.php, config.php, process.php and paypal.class.php, but if you observe mainly two files index.php and process.php, you should be pretty clear how everything works.

Configuration

config.php PHP file is used to store seller’s Paypal API information. Use your sandbox or live PayPal API details to replace variables in config.php file.

1
2
3
4
5
6
7
8
9
<?php
$PayPalMode         = 'sandbox'; // sandbox or live
$PayPalApiUsername  = 'selleremail@somesite.com'; //PayPal API Username
$PayPalApiPassword  = '123456'; //Paypal API password
$PayPalApiSignature     = 'ZWxwchnCsdQg5PxAUjcH6OPuZK3sPcPH'; //Paypal API Signature
$PayPalCurrencyCode     = 'USD'; //Paypal Currency Code
$PayPalReturnURL    = 'http://yoursite.com/paypal/process.php'; //Point to process.php page
$PayPalCancelURL    = 'http://yoursite.com/paypal/cancel_url.php'; //Cancel URL if user clicks cancel
?>

Product Page

index.php is initial page where your buyers get to see your products, it doesn’t matter how you are planning to present your products, it could be complex ajax driven page, single product or just list of few products, you just need to list your products similar to example below.

Each product item contains a form, and each form contains hidden input variables item name, item number, item quantity and price. A buyer is able to see product details and select quantity before buying the product. When buyer decides to buy, the selected product data gets posted to process.php.

Please Note: Do not include price in hidden field as shown in example below, as the value can be easily replaced using any developer tool. In practical world, you should check existence of product and fetch actual price from database using product ID in process page, so that people can not manipulate the price.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
include_once("config.php");
?>
<h2 align="center">Test Products</h2>
<table class="procut_item" border="0" cellpadding="4">
  <tr>
    <td width="70%"><h4>Product 1</h4>(product description)</td>
    <td width="30%">
    <form method="post" action="process.php">
    <input type="hidden" name="itemname" value="Product 1" />
    <input type="hidden" name="itemnumber" value="10000" />
    <input type="hidden" name="itemdesc" value="product description." />
    <input type="hidden" name="itemprice" value="225.00" />
    Quantity : <select name="itemQty"><option value="1">1</option><option value="2">2</option><option value="3">3</option></select>
    <input class="dw_button" type="submit" name="submitbutt" value="Buy (225.00 <?php echo $PayPalCurrencyCode; ?>)" />
    </form>
    </td>
  </tr>
</table>

PHP Class

The downloadbale sample files also include a PHP class called paypal.class.php to interact with PayPal. paypal.class.php is nothing but collection of functions, PPHttpPost() PHP function is used to carry out API operations in progress.php file, such as sending HTTP POST Request or getting response from the server. You can add your own additional functions (if needed) in this class file and execute like this $paypal->functionname().

Processing PayPal Payment

The most important segment of our PayPal Express Checkout system is the process.php file. Here the buyer’s product data is received and processed further for the payment.

We will execute mainly three Paypal methods here SetExpressCheckout, DoExpressCheckout & GetExpressCheckoutDetails. But before we proceed further, we need to collect product details such as product id, its name and price for process page.

As explained earlier, you should only fetch product price from database rather than hidden input fields for security reasons, once we have the price, we can calculate and include tax details, shipping cost and discounts, which we need to set as parameters for SetExpressCheckout and DoExpressCheckout.

There are other various parameters you can pass to SetExpressCheckout and DoExpressCheckout to control the outcome. I advice you to read official PayPal documentation to know more about these parameters.

SetExpressCheckOut

When buyer sends product details by clicking buy button, process.php needs to obtain PayPal token with SetExpressCheckOut method using Seller’s PayPal API credentials.

Once we successfully receive PayPal token, we need to set some session variable (itemprice, totalamount, itemName, itemNo, itemQTY) for later use. And then we redirect buyer to PayPal order summary page, where buyer pays in secure PayPal environment, but remember PayPal doesn’t transfer money yet.

DoExpressCheckoutPayment

After payment, buyer is redirected back to process.php page with Paypal token and PayerID values. We again need to send these values back to PayPal using DoExpressCheckoutPayment method, where PayPal verifies these values, only then the money is transferred to Seller’s account.

GetExpressCheckoutDetails

Obtains information about a specific order using SetExpressCheckOut token, on successful payment you might want to save buyer details such as address, payment Information etc. in database, please see Mysqli basic usage.

Each comment line in PHP code below explains how process.php deals with data received from buyer and PayPal.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
<?php
session_start();
include_once("config.php");
include_once("paypal.class.php");

$paypalmode = ($PayPalMode=='sandbox') ? '.sandbox' : '';

if($_POST) //Post Data received from product list page.
{
    //Mainly we need 4 variables from product page Item Name, Item Price, Item Number and Item Quantity.
   
    //Please Note : People can manipulate hidden field amounts in form,
    //In practical world you must fetch actual price from database using item id. Eg:
    //$ItemPrice = $mysqli->query("SELECT item_price FROM products WHERE id = Product_Number");

    $ItemName       = $_POST["itemname"]; //Item Name
    $ItemPrice      = $_POST["itemprice"]; //Item Price
    $ItemNumber     = $_POST["itemnumber"]; //Item Number
    $ItemDesc       = $_POST["itemdesc"]; //Item description
    $ItemQty        = $_POST["itemQty"]; // Item Quantity
    $ItemTotalPrice = ($ItemPrice*$ItemQty); //(Item Price x Quantity = Total) Get total amount of product;
   
    //Other important variables like tax, shipping cost
    $TotalTaxAmount     = 2.58;  //Sum of tax for all items in this order.
    $HandalingCost      = 2.00;  //Handling cost for this order.
    $InsuranceCost      = 1.00;  //shipping insurance cost for this order.
    $ShippinDiscount    = -3.00; //Shipping discount for this order. Specify this as negative number.
    $ShippinCost        = 3.00; //Although you may change the value later, try to pass in a shipping amount that is reasonably accurate.
   
    //Grand total including all tax, insurance, shipping cost and discount
    $GrandTotal = ($ItemTotalPrice + $TotalTaxAmount + $HandalingCost + $InsuranceCost + $ShippinCost + $ShippinDiscount);
   
    //Parameters for SetExpressCheckout, which will be sent to PayPal
    $padata =   '&METHOD=SetExpressCheckout'.
                '&RETURNURL='.urlencode($PayPalReturnURL ).
                '&CANCELURL='.urlencode($PayPalCancelURL).
                '&PAYMENTREQUEST_0_PAYMENTACTION='.urlencode("SALE").
               
                '&L_PAYMENTREQUEST_0_NAME0='.urlencode($ItemName).
                '&L_PAYMENTREQUEST_0_NUMBER0='.urlencode($ItemNumber).
                '&L_PAYMENTREQUEST_0_DESC0='.urlencode($ItemDesc).
                '&L_PAYMENTREQUEST_0_AMT0='.urlencode($ItemPrice).
                '&L_PAYMENTREQUEST_0_QTY0='. urlencode($ItemQty).
               
                /*
                //Additional products (L_PAYMENTREQUEST_0_NAME0 becomes L_PAYMENTREQUEST_0_NAME1 and so on)
                '&L_PAYMENTREQUEST_0_NAME1='.urlencode($ItemName2).
                '&L_PAYMENTREQUEST_0_NUMBER1='.urlencode($ItemNumber2).
                '&L_PAYMENTREQUEST_0_DESC1='.urlencode($ItemDesc2).
                '&L_PAYMENTREQUEST_0_AMT1='.urlencode($ItemPrice2).
                '&L_PAYMENTREQUEST_0_QTY1='. urlencode($ItemQty2).
                */

               
                /*
                //Override the buyer's shipping address stored on PayPal, The buyer cannot edit the overridden address.
                '&ADDROVERRIDE=1'.
                '&PAYMENTREQUEST_0_SHIPTONAME=J Smith'.
                '&PAYMENTREQUEST_0_SHIPTOSTREET=1 Main St'.
                '&PAYMENTREQUEST_0_SHIPTOCITY=San Jose'.
                '&PAYMENTREQUEST_0_SHIPTOSTATE=CA'.
                '&PAYMENTREQUEST_0_SHIPTOCOUNTRYCODE=US'.
                '&PAYMENTREQUEST_0_SHIPTOZIP=95131'.
                '&PAYMENTREQUEST_0_SHIPTOPHONENUM=408-967-4444'.
                */

               
                '&NOSHIPPING=0'. //set 1 to hide buyer's shipping address, in-case products that do not require shipping
               
                '&PAYMENTREQUEST_0_ITEMAMT='.urlencode($ItemTotalPrice).
                '&PAYMENTREQUEST_0_TAXAMT='.urlencode($TotalTaxAmount).
                '&PAYMENTREQUEST_0_SHIPPINGAMT='.urlencode($ShippinCost).
                '&PAYMENTREQUEST_0_HANDLINGAMT='.urlencode($HandalingCost).
                '&PAYMENTREQUEST_0_SHIPDISCAMT='.urlencode($ShippinDiscount).
                '&PAYMENTREQUEST_0_INSURANCEAMT='.urlencode($InsuranceCost).
                '&PAYMENTREQUEST_0_AMT='.urlencode($GrandTotal).
                '&PAYMENTREQUEST_0_CURRENCYCODE='.urlencode($PayPalCurrencyCode).
                '&LOCALECODE=GB'. //PayPal pages to match the language on your website.
                '&LOGOIMG=https://www.sanwebe.com/wp-content/themes/sanwebe/img/logo.png'. //site logo
                '&CARTBORDERCOLOR=FFFFFF'. //border color of cart
                '&ALLOWNOTE=1';
               
                ############# set session variable we need later for "DoExpressCheckoutPayment" #######
                $_SESSION['ItemName']           =  $ItemName; //Item Name
                $_SESSION['ItemPrice']          =  $ItemPrice; //Item Price
                $_SESSION['ItemNumber']         =  $ItemNumber; //Item Number
                $_SESSION['ItemDesc']           =  $ItemDesc; //Item description
                $_SESSION['ItemQty']            =  $ItemQty; // Item Quantity
                $_SESSION['ItemTotalPrice']     =  $ItemTotalPrice; //total amount of product;
                $_SESSION['TotalTaxAmount']     =  $TotalTaxAmount;  //Sum of tax for all items in this order.
                $_SESSION['HandalingCost']      =  $HandalingCost;  //Handling cost for this order.
                $_SESSION['InsuranceCost']      =  $InsuranceCost;  //shipping insurance cost for this order.
                $_SESSION['ShippinDiscount']    =  $ShippinDiscount; //Shipping discount for this order. Specify this as negative number.
                $_SESSION['ShippinCost']        =   $ShippinCost; //Although you may change the value later, try to pass in a shipping amount that is reasonably accurate.
                $_SESSION['GrandTotal']         =  $GrandTotal;


        //We need to execute the "SetExpressCheckOut" method to obtain paypal token
        $paypal= new MyPayPal();
        $httpParsedResponseAr = $paypal->PPHttpPost('SetExpressCheckout', $padata, $PayPalApiUsername, $PayPalApiPassword, $PayPalApiSignature, $PayPalMode);
       
        //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'.$paypalmode.'.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token='.$httpParsedResponseAr["TOKEN"].'';
                header('Location: '.$paypalurl);
             
        }else{
            //Show error message
            echo '<div style="color:red"><b>Error : </b>'.urldecode($httpParsedResponseAr["L_LONGMESSAGE0"]).'</div>';
            echo '<pre>';
            print_r($httpParsedResponseAr);
            echo '</pre>';
        }

}

//Paypal redirects back to this page using ReturnURL, We should receive TOKEN and Payer ID
if(isset($_GET["token"]) && isset($_GET["PayerID"]))
{
    //we will be using these two variables to execute the "DoExpressCheckoutPayment"
    //Note: we haven't received any payment yet.
   
    $token = $_GET["token"];
    $payer_id = $_GET["PayerID"];
   
    //get session variables
    $ItemName           = $_SESSION['ItemName']; //Item Name
    $ItemPrice          = $_SESSION['ItemPrice'] ; //Item Price
    $ItemNumber         = $_SESSION['ItemNumber']; //Item Number
    $ItemDesc           = $_SESSION['ItemDesc']; //Item Number
    $ItemQty            = $_SESSION['ItemQty']; // Item Quantity
    $ItemTotalPrice     = $_SESSION['ItemTotalPrice']; //total amount of product;
    $TotalTaxAmount     = $_SESSION['TotalTaxAmount'] ;  //Sum of tax for all items in this order.
    $HandalingCost      = $_SESSION['HandalingCost'];  //Handling cost for this order.
    $InsuranceCost      = $_SESSION['InsuranceCost'];  //shipping insurance cost for this order.
    $ShippinDiscount    = $_SESSION['ShippinDiscount']; //Shipping discount for this order. Specify this as negative number.
    $ShippinCost        = $_SESSION['ShippinCost']; //Although you may change the value later, try to pass in a shipping amount that is reasonably accurate.
    $GrandTotal         = $_SESSION['GrandTotal'];

    $padata =   '&TOKEN='.urlencode($token).
                '&PAYERID='.urlencode($payer_id).
                '&PAYMENTREQUEST_0_PAYMENTACTION='.urlencode("SALE").
               
                //set item info here, otherwise we won't see product details later 
                '&L_PAYMENTREQUEST_0_NAME0='.urlencode($ItemName).
                '&L_PAYMENTREQUEST_0_NUMBER0='.urlencode($ItemNumber).
                '&L_PAYMENTREQUEST_0_DESC0='.urlencode($ItemDesc).
                '&L_PAYMENTREQUEST_0_AMT0='.urlencode($ItemPrice).
                '&L_PAYMENTREQUEST_0_QTY0='. urlencode($ItemQty).

                /*
                //Additional products (L_PAYMENTREQUEST_0_NAME0 becomes L_PAYMENTREQUEST_0_NAME1 and so on)
                '&L_PAYMENTREQUEST_0_NAME1='.urlencode($ItemName2).
                '&L_PAYMENTREQUEST_0_NUMBER1='.urlencode($ItemNumber2).
                '&L_PAYMENTREQUEST_0_DESC1=Description text'.
                '&L_PAYMENTREQUEST_0_AMT1='.urlencode($ItemPrice2).
                '&L_PAYMENTREQUEST_0_QTY1='. urlencode($ItemQty2).
                */


                '&PAYMENTREQUEST_0_ITEMAMT='.urlencode($ItemTotalPrice).
                '&PAYMENTREQUEST_0_TAXAMT='.urlencode($TotalTaxAmount).
                '&PAYMENTREQUEST_0_SHIPPINGAMT='.urlencode($ShippinCost).
                '&PAYMENTREQUEST_0_HANDLINGAMT='.urlencode($HandalingCost).
                '&PAYMENTREQUEST_0_SHIPDISCAMT='.urlencode($ShippinDiscount).
                '&PAYMENTREQUEST_0_INSURANCEAMT='.urlencode($InsuranceCost).
                '&PAYMENTREQUEST_0_AMT='.urlencode($GrandTotal).
                '&PAYMENTREQUEST_0_CURRENCYCODE='.urlencode($PayPalCurrencyCode);
   
    //We need to execute the "DoExpressCheckoutPayment" at this point to Receive payment from user.
    $paypal= new MyPayPal();
    $httpParsedResponseAr = $paypal->PPHttpPost('DoExpressCheckoutPayment', $padata, $PayPalApiUsername, $PayPalApiPassword, $PayPalApiSignature, $PayPalMode);
   
    //Check if everything went ok..
    if("SUCCESS" == strtoupper($httpParsedResponseAr["ACK"]) || "SUCCESSWITHWARNING" == strtoupper($httpParsedResponseAr["ACK"]))
    {

            echo '<h2>Success</h2>';
            echo 'Your Transaction ID : '.urldecode($httpParsedResponseAr["PAYMENTINFO_0_TRANSACTIONID"]);
           
                /*
                //Sometimes Payment are kept pending even when transaction is complete.
                //hence we need to notify user about it and ask him manually approve the transiction
                */

               
                if('Completed' == $httpParsedResponseAr["PAYMENTINFO_0_PAYMENTSTATUS"])
                {
                    echo '<div style="color:green">Payment Received! Your product will be sent to you very soon!</div>';
                }
                elseif('Pending' == $httpParsedResponseAr["PAYMENTINFO_0_PAYMENTSTATUS"])
                {
                    echo '<div style="color:red">Transaction Complete, but payment is still pending! '.
                    'You need to manually authorize this payment in your <a target="_new" href="http://www.paypal.com">Paypal Account</a></div>';
                }

                // we can retrive transection details using either GetTransactionDetails or GetExpressCheckoutDetails
                // GetTransactionDetails requires a Transaction ID, and GetExpressCheckoutDetails requires Token returned by SetExpressCheckOut
                $padata =   '&TOKEN='.urlencode($token);
                $paypal= new MyPayPal();
                $httpParsedResponseAr = $paypal->PPHttpPost('GetExpressCheckoutDetails', $padata, $PayPalApiUsername, $PayPalApiPassword, $PayPalApiSignature, $PayPalMode);

                if("SUCCESS" == strtoupper($httpParsedResponseAr["ACK"]) || "SUCCESSWITHWARNING" == strtoupper($httpParsedResponseAr["ACK"]))
                {
                   
                    echo '<br /><b>Stuff to store in database :</b><br /><pre>';
                    /*
                    #### SAVE BUYER INFORMATION IN DATABASE ###
                    //see (https://www.sanwebe.com/2013/03/basic-php-mysqli-usage) for mysqli usage
                   
                    $buyerName = $httpParsedResponseAr["FIRSTNAME"].' '.$httpParsedResponseAr["LASTNAME"];
                    $buyerEmail = $httpParsedResponseAr["EMAIL"];
                   
                    //Open a new connection to the MySQL server
                    $mysqli = new mysqli('host','username','password','database_name');
                   
                    //Output any connection error
                    if ($mysqli->connect_error) {
                        die('Error : ('. $mysqli->connect_errno .') '. $mysqli->connect_error);
                    }      
                   
                    $insert_row = $mysqli->query("INSERT INTO BuyerTable
                    (BuyerName,BuyerEmail,TransactionID,ItemName,ItemNumber, ItemAmount,ItemQTY)
                    VALUES ('$buyerName','$buyerEmail','$transactionID','$ItemName',$ItemNumber, $ItemTotalPrice,$ItemQTY)");
                   
                    if($insert_row){
                        print 'Success! ID of last inserted record is : ' .$mysqli->insert_id .'<br />';
                    }else{
                        die('Error : ('. $mysqli->errno .') '. $mysqli->error);
                    }
                   
                    */

                   
                    echo '<pre>';
                    print_r($httpParsedResponseAr);
                    echo '</pre>';
                } else  {
                    echo '<div style="color:red"><b>GetTransactionDetails failed:</b>'.urldecode($httpParsedResponseAr["L_LONGMESSAGE0"]).'</div>';
                    echo '<pre>';
                    print_r($httpParsedResponseAr);
                    echo '</pre>';

                }
   
    }else{
            echo '<div style="color:red"><b>Error : </b>'.urldecode($httpParsedResponseAr["L_LONGMESSAGE0"]).'</div>';
            echo '<pre>';
            print_r($httpParsedResponseAr);
            echo '</pre>';
    }
}
?>

Conclusion

I hope this tutorial will help you sell your products easily using PayPal. If you are facing issue of Paypal holding fund for 21 days, please read their policy here, and if you sell huge amount of products everyday, you might want to automate things by setting up PayPal IPN listener script. Good luck!

You might also be interested in reading Creating Simple Shopping Cart with PHP. and Sending Multiple Items to PayPal using Shopping cart.

Download Demo

  1. Reymart “Canu” Canuel

    My code is now working. Though when I’m trying to login to pay.. it PayPal says “Please check your email address and password and try again”

     Reply
  2. Reymart “Canu” Canuel

    Hello, I’m having this error:

    Error : Timeout processing request
    Array
    (
    [TIMESTAMP] => 2014%2d07%2d20T07%3a48%3a29Z
    [CORRELATIONID] => 67dcddadd2fcd
    [ACK] => Failure
    [L_ERRORCODE0] => 10001
    [L_SHORTMESSAGE0] => Internal%20Error
    [L_LONGMESSAGE0] => Timeout%20processing%20request
    )

     Reply
  3. i get that error from 2 reasons
    1: on chrome only!
    2. because i didn’t put @session_start(); in paypal.class.php

     Reply
  4. there is a huge security issue, after you get the redirect url with token you can use it up to 5 times, so basically making 5 charges on the website but paying only once, can anyone help in this regard?

     Reply
    • after 10 tries you get this message “You have exceeded the maximum number of payment attempts for this token”

      I can’t find anywhere in the script the number of attempts to reduce it to 1.

    • I think it’s an internal setting of PayPal library, not depending on its usage. I’ve looked for some callback in PayPal API to change this setting but I haven’t found it: I think it cannot be modified. If PayPal doesn’t allow to change it, I imagine it doesn’t represent a bad security issue anyway.

    • it does in my case, every time the page gets refreshed the same item gets stored in the database over and over again, now i have to code a protection check as well, damn this paypal.

    • Ok I see your point now. So, why don’t you store in database the transaction ID too? If it’s not present, you save items, otherwise discard them. I think it may not be too complicated.

  5. Error : Security header is not valid
    Array
    (
    [TIMESTAMP] => 2014%2d07%2d12T06%3a05%3a00Z
    [CORRELATIONID] => f156037030ce7
    [ACK] => Failure
    [VERSION] => 109%2e0
    [BUILD] => 11843215
    [L_ERRORCODE0] => 10002
    [L_SHORTMESSAGE0] => Security%20error
    [L_LONGMESSAGE0] => Security%20header%20is%20not%20valid
    [L_SEVERITYCODE0] => Error
    )
    I got the above error when running this, how to solve this error?

     Reply
  6. Error : Security header is not valid

    Array
    (
    [TIMESTAMP] => 2014%2d07%2d10T14%3a53%3a12Z
    [CORRELATIONID] => 7e0cb9fb78ae1
    [ACK] => Failure
    [VERSION] => 109%2e0
    [BUILD] => 11811513
    [L_ERRORCODE0] => 10002
    [L_SHORTMESSAGE0] => Security%20error
    [L_LONGMESSAGE0] => Security%20header%20is%20not%20valid
    [L_SEVERITYCODE0] => Error
    )

     Reply
    • Hi there!

      I get the same error on my first try. Then, I realize I had use the Saran signature.

      I put my own data on config.php about:
      $PayPalApiUsername
      $PayPalApiPassword
      $PayPalApiSignature

      All of them get from my sandbox account, on profile section… notice that the PayPalApiPassword is not your real password, I get this on the same section.

      I hope to be helpful.

      Best regards… and very thank you Saran!

    • Hi Tiago, see my reply to Waqas. Hope it helps!

  7. Hi! How can I get success or failed status?

    Ty

     Reply
    • according to the code row 175. According to doc of PayPal it returns you paremetrs. One them is ACK. This one holds the status of respose of the payment

  8. Hello,
    I would like to use this express Paypal checkout to accept payment for some web services (no digital download or shipping) on a WordPress site. I want to be able to record the purchase into the wpdb and have the service details post from the service page (wp post) to the checkout or Paypal transaction page. Can anyone put me on the right path? or directly assist or contact me at my email selectiveform([at])gmail>.com

     Reply
  9. Hi Saran. Thank you. This saved my day. PayPal documentation is still awful and I spent a whole day on this.

     Reply
  10. This tutorial saved me from ripping my hair out. Thank you!

     Reply
  11. helpful tutorial thanks

     Reply
  12. Hi,

    Thank a lt for this tutoriel.
    Is it possible to have an example of sending mail with information about the purchased product to the buyer and the seller once the transaction is passed to ‘COMPLETED’ please?

     Reply
  13. Very nice. I was planning to up my game a little bit and adapt an e-commerce website, this could be very useful. Just one question, is it possible to disable the customer note when they are checking out? We sell online tutoring session, but it bugged me a lot when customer cannot accurately describe their services and I’ hate to see it becomes a trouble to us.

    Thank you.

    Yawn

     Reply
  14. there is security problecm i guess
    u cud change value of price with inspect
    and will send this value as you change it
    so any one no how to secure this issue?!!!

     Reply
    • I would send to another form wich would be on document ready submit and will hold all posisitions from this form and secured fields. And as I said it will be submitted right where it needs to go.

    • what about using curl by checking the price from DB and then send data on background
      cuz idont trust javascript in security
      Q: is sending data with curl lib cud be visible by livehttprequset or bruitsuit or any other program?!!
      thanks amazing blog

    • Don’t know nothing about curl visibility with progs and I never had problems with security by signing data with curl, but anyway you have to check all outgoing data in back. Sorry for not such clear answer. The thing is that you are comparing everything on back before submitting form such as I prefer to do it on js. PayPal is working with security token mostly so data is pretty safe. We have to take care about amount, price and id of product, so user couldn’t by something much chipper by changing data. This surly you can compare on back. I would defiantly do so.

  15. Hello,

    I would like to know how i can get the “DoExpressCheckoutPayment” if i use the multiple itens?
    I need to put itens in a foreach?

    thanks

     Reply
  16. Hi thanks a lot for your effort with this.. it really came in handy for me. Keep up the good work!

     Reply
  17. Hey your code is just awesome abd working fine, but recently i got the problem here
    Its working fine in sandbox mode but getting error like : “Merchant country not supported” in live mode.
    So how to fix that? please help me as I need to fix it in urgent basis.
    Thanks in advance.

     Reply
  18. First of all I want to thank you for this brillant tutorial, I’ve spent days trying to build something which was never right, especially with the official PayPal wizard…
    For me it’s almost perfect I say almost because at the very end of the process, when I hit the last PayPal button I have the following error message :

    1
    2
    3
    4
    5
    6
    7
    8
    9
    [TIMESTAMP] =&gt; 2014%2d05%2d22T17%3a02%3a17Z
        [CORRELATIONID] =&gt; 46911d540d48
        [ACK] =&gt; Failure
        [VERSION] =&gt; 109%2e0
        [BUILD] =&gt; 11110362
        [L_ERRORCODE0] =&gt; 10525
        [L_SHORTMESSAGE0] =&gt; Invalid%20Data
        [L_LONGMESSAGE0] =&gt; This%20transaction%20cannot%20be%20processed%2e%20The%20amount%20to%20be%20charged%20is%20zero%2e
        [L_SEVERITYCODE0] =&gt; Error

    I don’t understand what could cause that as the amounts displayed on PayPal transactions screens are OK.. I looked to previous comments but apparently nobody encountered this problem….
    If you have time to find an idea…
    Thanks anyway !
    Best regards

     Reply
    • Check if you set the value of “PAYMENTREQUEST_0_AMT” variable correctly. It must be greater than zero.

    • according to the code of your error the user did not enter the amount he wanna pay for:
      10525 Invalid Data This transaction cannot be processed. The amount to be charged is zero. The merchant entered an amount of zero.

  19. Hi, I integrated this code in my CI project. But when i’m trying to login in buy page of paypal, i get the follow error message:
    We are unable to validate your information. Please try again.

    Why? Is a sandbox problem?

     Reply
  20. First, thanks for your web and your examples.
    Second, I have the same problem as Jaya and Rana Rananjay Singh, I check all my code and all the variables, but didnt found any error.

    ¿Any idea to check it and found the problem?

    Thanks

     Reply
  21. SetExpressCheckout failed: SSL read: error:00000000:lib(0):func(0):reason(0), errno 104(56)

     Reply
  22. Hello,
    If i want to use this class to send a payment to an e-mail other than mine as i am having a platform that people sell their stuff on.
    How do i specify the receiver, i am asking about adaptive payments.

     Reply
  23. U know this error?

    Error : This Express Checkout session has expired. Token value is no longer valid.

     Reply
  24. Great … Working fine thanks :)

     Reply
  25. Thanks for this tutorial. I am trouble sorting this out! can you guide me
    Error : Security header is not valid

    Array
    (
    [TIMESTAMP] => 2014%2d05%2d06T04%3a34%3a37Z
    [CORRELATIONID] => 379021548c439
    [ACK] => Failure
    [VERSION] => 109%2e0
    [BUILD] => 10850615
    [L_ERRORCODE0] => 10002
    [L_SHORTMESSAGE0] => Security%20error
    [L_LONGMESSAGE0] => Security%20header%20is%20not%20valid
    [L_SEVERITYCODE0] => Error
    )

     Reply
    • Hi Waquas, this is because you may have used your live API credentials instead of sandbox API credentials. If you are using the “sandbox” version of the script, you must use sandbox API credentials.
      You can find sandbox API credentials here https://developer.paypal.com/webapps/developer/applications/accounts. If you don’t have one, create a sandbox business account, select it in the accounts list, select “Profile” and then look at the “API credentials” tab. Here you may find credentials data. Hope it helps.

  26. Hii Saran ,
    I have done a mass payment on localhost by using sandbox account, and there is two recievers whose having individual mail address, unique id. after execution It showing success message, but those receivers didn’t get any mail for payment link .

    Thanks in advance

     Reply
  27. thank you for the great example.
    I’ve a problem with the cancel-url. How can I retrieve the paypal message, if the user clicks by paypal on “Cancel and back to the shop”?
    if(isset($_GET[“token”]) && isset($_GET[“PayerID”])) << is ignored, because the payer_id Param is missing

     Reply
  28. kudos for this script, I’ve been hitting with my head around this for a while, thanks!

     Reply
  29. Great work. Thank for your tutorial

     Reply
  30. Hello Saran!
    Need your advice.

    How can i resolve this problem

    *Error : *Order total is missing.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    Array (
        [TIMESTAMP] => 2013%2d07%2d25T06%3a35%3a40Z
        [CORRELATIONID] => 7135c1b55ab96
        [ACK] => Failure
        [VERSION] => 76%2e0
        [BUILD] => 6941909
        [L_ERRORCODE0] => 10400
        [L_SHORTMESSAGE0] => Transaction%20refused%20because%20of%20an%20invalid%20argument%2e%20See%20additional%20error%20messages%20for%20details%2e
        [L_LONGMESSAGE0] => Order%20total%20is%20missing%2e
        [L_SEVERITYCODE0] => Error
    )
     Reply
    • Obviously the order total is missing, please check script is retrieving session variable correctly.

    • how i check that ?

    • if *Error : *Order total is missing. error comes that means you have not started session on that page.

      kindly put session_start() on the top of the page. and it will work. Thnx

    • I did, same problem, i needed session start to connect to the database to get other info as well, why does it only work in Chrome?

    • FIXED IT !!!! you need to put session_start(); in INDEX.PHP file, you didn’t specify this Vishal, and please update the code, many of us have problems, so now it works in every browser !!! even Firefox and IE.

    • Error : *Order total is missing
      I also put session_start() on the top of the page. but it still give that error.
      I checked about the problem at apache_error.log side it gives all session variable’s name error like below.
      Undefined index: ItemPrice
      Undefined index: ItemNumber
      But I have defined like
      $_SESSION[‘ItemName’] = $ItemName;
      $_SESSION[‘ItemPrice’] = $ItemPrice;
      Please suggest me

    • Have you checked the $_POST[“ItemName”] variable when you compute the order total? You should get this variable from the form in the previous page (index.php). Echo the value of this variable: if it’s not set, you will not be able to proceed in order processing.

Message Type : Question Comment ?
  • Question : Can include code, jsFiddle, codePen etc using Markdown Syntax.
  • Comment : Short comments and questions.