Getting Started With The PayPal API

Advertisement

PayPal is the most popular platform for receiving online payments today. The ease of opening a PayPal account and receiving payments compared to opening a merchant account with a traditional payment gateway is probably the number one reason for its popularity, with a close second being the comprehensive API that PayPal provides for its payment services. In this post, I will break down some of the techniques and approaches to working with the PayPal API, in order to make integration and troubleshooting simpler and easier.

Disclaimer: PayPal’s API is among the worst I’ve ever had to deal with. Inconsistencies, sometimes poor or conflicting documentation, unpredictable failures and account changes, and major differences between the live and sandbox versions all conspire to make the PayPal API quite a pain in the arse to work with. Over the years, I’ve taken my lumps from working quite a bit with the PayPal API, and I’ve published the results of my hard-learned lessons as a commercial PHP PayPal API component on the source-code marketplace Binpress.

PayPal at LeWeb, Copyright Jean-Christophe Capelli, Some Rights Reserved

The Different Payment Options

PayPal offers a variety of payment options, which might be confusing at first:

  • Express Checkout
    The premier PayPal service. Express Checkout allows you to receive payments without having a merchant account and without having to meet special requirements other than verifying your account (either via a bank account or a credit card). Previously, you could receive Express Checkout payments from PayPal users only, but PayPal has since added a credit-card option for non-PayPal users, making this service accessible to practically anyone with a major credit card. Note that the Express Checkout process occurs on PayPal’s platform and thus can never be fully integrated in your website’s experience.
  • Direct Payment
    The Direct Payment method allows you to receive credit-card payments directly through an API call. This enables you to host the payment process on your website in full, which might make for a more complete shopping experience for your customers. The Direct Payment method has several variations that enable you to authorize a payment and complete it at a later date: the appropriately named Authorization and Capture methods. These variations are a part of the Website Payments Pro API, which is available only to US, Canadian and UK accounts.
  • Recurring Payments
    This allows you to set up a recurring transaction (i.e. a subscription payment).
  • Mass Payments
    This allows you to transfer money to multiple accounts at once.
  • Adaptive Payments
    Here is another API for sending funds to multiple recipients, with some differences from the Mass Payments API. (Did I mention that the PayPal API is confusing and a bit redundant?)

This list is not comprehensive, but it covers the main payment options (see the API documentation for more).

Making API Requests

PayPal supports two main formats over HTTP: NVP and SOAP. NVP is short for Name-Value Pair, and SOAP stands for Simple Object Access Protocol. I will cover the NVP approach, which I prefer to SOAP’s relatively verbose and complex syntax.

Each of the API methods has different parameters, but they all share some basic parameters, which are used to identify the API account and sign the transaction. These include:

  • USER
    Your PayPal API user name.
  • PWD
    Your PayPal API password.
  • VERSION
    The version number of the NVP API service, such as 74.0 (the most recent as of this writing).
  • SIGNATURE
    Your PayPal API signature string. This parameter is optional if you use a certificate to authenticate.

The last required parameter is METHOD, which declares which API method we are calling.

Requests are made over HTTPS. We’ll use cURL to build our basic request, and then encapsulate the process in a class:

class Paypal {
   /**
    * Last error message(s)
    * @var array
    */
   protected $_errors = array();

   /**
    * API Credentials
    * Use the correct credentials for the environment in use (Live / Sandbox)
    * @var array
    */
   protected $_credentials = array(
      'USER' => 'seller_1297608781_biz_api1.lionite.com',
      'PWD' => '1297608792',
      'SIGNATURE' => 'A3g66.FS3NAf4mkHn3BDQdpo6JD.ACcPc4wMrInvUEqO3Uapovity47p',
   );

   /**
    * API endpoint
    * Live - https://api-3t.paypal.com/nvp
    * Sandbox - https://api-3t.sandbox.paypal.com/nvp
    * @var string
    */
   protected $_endPoint = 'https://api-3t.sandbox.paypal.com/nvp';

   /**
    * API Version
    * @var string
    */
   protected $_version = '74.0';

   /**
    * Make API request
    *
    * @param string $method string API method to request
    * @param array $params Additional request parameters
    * @return array / boolean Response array / boolean false on failure
    */
   public function request($method,$params = array()) {
      $this -> _errors = array();
      if( empty($method) ) { //Check if API method is not empty
         $this -> _errors = array('API method is missing');
         return false;
      }

      //Our request parameters
      $requestParams = array(
         'METHOD' => $method,
         'VERSION' => $this -> _version
      ) + $this -> _credentials;

      //Building our NVP string
      $request = http_build_query($requestParams + $params);

      //cURL settings
      $curlOptions = array (
         CURLOPT_URL => $this -> _endPoint,
         CURLOPT_VERBOSE => 1,
         CURLOPT_SSL_VERIFYPEER => true,
         CURLOPT_SSL_VERIFYHOST => 2,
         CURLOPT_CAINFO => dirname(__FILE__) . '/cacert.pem', //CA cert file
         CURLOPT_RETURNTRANSFER => 1,
         CURLOPT_POST => 1,
         CURLOPT_POSTFIELDS => $request
      );

      $ch = curl_init();
      curl_setopt_array($ch,$curlOptions);

      //Sending our request - $response will hold the API response
      $response = curl_exec($ch);

      //Checking for cURL errors
      if (curl_errno($ch)) {
         $this -> _errors = curl_error($ch);
         curl_close($ch);
         return false;
         //Handle errors
      } else  {
         curl_close($ch);
         $responseArray = array();
         parse_str($response,$responseArray); // Break the NVP string to an array
         return $responseArray;
      }
   }
}

Note that I use a CA certificate file for SSL certificate validation. You can obtain the file from the cURL website or any trusted source. Update the path to the certificate file according to where you’ve placed it.

The response returned will be in NVP format as well, and I reformat it into an array before returning it. A parameter named ACK signifies the status of the request: Success or SuccessWithWarning when the request succeeds, and Error or Warning when the request fails.

A request could fail for many reasons, and there are different reasons for each API method, which are covered in detail in the manual. We’ll go over some further down in this article and look at ways to handle them. Keep in mind that the parameter values are case-sensitive, so code against them accordingly.

Express Checkout

One of the most popular APIs is the Express Checkout API, which enables you to receive payments without opening a Website Payments Pro account (which is available only to verified US accounts) or hosting the actual transaction yourself (which requires additional security).

The Express Checkout process works as follows:

  1. We request a checkout token from PayPal using the transaction details;
  2. If successful, we redirect the user to the PayPal endpoint using the received token;
  3. The user completes or cancels the payment on the PayPal platform and is redirected back to our website;
  4. We complete the payment either when the user is redirected back or via an Instant Payment Notification (IPN).

Express Checkout flow

1. Getting the Checkout Token: SetExpressCheckout

We initiate the Express Checkout process by passing the order details to the PayPal API, and we receive a token string that identifies it. This token would be used in the next step to redirect to PayPal.

Here are the required parameters:

  • METHOD
    This is the API method that we’re using (i.e. SetExpressCheckout).
  • RETURNURL
    The URL that the user will be redirected to after the payment process is completed.
  • CANCELURL
    The URL that the user will be redirected to after having cancelled the payment process.
  • PAYMENTREQUEST_0_AMT
    The transaction’s total amount. This must have two decimal places, with the decimal separator being a period (.). The optional thousands separator must be a comma (,).
  • PAYMENTREQUEST_0_ITEMAMT
    The total cost of the items in the order, excluding shipping, taxes and other costs. If there are no extra costs, then it should be the same value as PAYMENTREQUEST_0_AMT.

We can pass additional parameters to add more information about the order, some of which have default values:

  • PAYMENTREQUEST_0_CURRENCYCODE
    The payment’s currency, as a three-letter code. The default is USD.
  • PAYMENTREQUEST_0_SHIPPINGAMT
    The total shipping costs for this order.
  • PAYMENTREQUEST_0_TAXAMT
    The total tax amount for this order. This is required if per-item tax is specified (see below).
  • PAYMENTREQUEST_0_DESC
    The order’s description.

We can also add details about individual items in the order:

  • L_PAYMENTREQUEST_0_NAMEm
    The item’s name.
  • L_PAYMENTREQUEST_0_DESCm
    The item’s description.
  • L_PAYMENTREQUEST_0_AMTm
    The item’s cost.
  • L_PAYMENTREQUEST_0_QTYm
    The quantity of an item.

The variable index m identifies the item. (Use the same variable for all details of the same item.)

There are many other optional parameters, which can be found in the API documentation.

We’ll use the function that we wrote above to build the SetExpressCheckout request:

//Our request parameters
$requestParams = array(
   'RETURNURL' => 'http://www.yourdomain.com/payment/success',
   'CANCELURL' => 'http://www.yourdomain.com/payment/cancelled'
);

$orderParams = array(
   'PAYMENTREQUEST_0_AMT' => '500',
   'PAYMENTREQUEST_0_SHIPPINGAMT' => '4',
   'PAYMENTREQUEST_0_CURRENCYCODE' => 'GBP',
   'PAYMENTREQUEST_0_ITEMAMT' => '496'
);

$item = array(
   'L_PAYMENTREQUEST_0_NAME0' => 'iPhone',
   'L_PAYMENTREQUEST_0_DESC0' => 'White iPhone, 16GB',
   'L_PAYMENTREQUEST_0_AMT0' => '496',
   'L_PAYMENTREQUEST_0_QTY0' => '1'
);

$paypal = new Paypal();
$response = $paypal -> request('SetExpressCheckout',$requestParams + $orderParams + $item);

2. Redirecting to PayPal Using the Checkout Express Token

If the request is successful, we’ll receive a checkout token in the TOKEN parameter of the response.

if(is_array($response) && $response['ACK'] == 'Success') { //Request successful
      $token = $response['TOKEN'];
      header( 'Location: https://www.paypal.com/webscr?cmd=_express-checkout&token=' . urlencode($token) );
}

The user now goes through the purchase process on PayPal’s website. When they confirm or cancel it, they will return to one of the URLs that we’ve specified in the request.

3. Completing the Transaction

Assuming the user confirms the transaction, they will be redirected to our website by PayPal. At this point, we should use two relevant API methods: DoExpressCheckoutPayment will complete the transaction, but before that we might want to get additional information on the buyer using GetExpressCheckoutDetails.

PayPal will redirect the user back from the purchase with the checkout token, which we will use to call those methods. The token will be available in the URL query parameters via the token parameter. We will check for its existence in the confirmation URL and then send our API requests if we find it.

The GetExpressCheckoutDetails method requires only the checkout token. DoExpressCheckoutPayment requires a couple of additional parameters:

  • PAYMENTREQUEST_0_PAYMENTACTION
    This is the payment action. It should be set to Sale unless we’ve specified a different action in the SetExpressCheckout method (possible values include Authorization and Capture).
  • PAYERID
    This is the unique identification for the PayPal account. This, too, is returned in the URL query parameters (in the PayerID parameter) and can also be retrieved from the details returned by GetExpressCheckoutDetails.
if( isset($_GET['token']) && !empty($_GET['token']) ) { // Token parameter exists
   // Get checkout details, including buyer information.
   // We can save it for future reference or cross-check with the data we have
   $paypal = new Paypal();
   $checkoutDetails = $paypal -> request('GetExpressCheckoutDetails', array('TOKEN' => $_GET['token']));

   // Complete the checkout transaction
   $requestParams = array(
       'TOKEN' => $_GET['token'],
       'PAYMENTACTION' => 'Sale',
       'PAYERID' => $_GET['PayerID'],
       'PAYMENTREQUEST_0_AMT' => '500', // Same amount as in the original request
       'PAYMENTREQUEST_0_CURRENCYCODE' => 'GBP' // Same currency as the original request
   );

   $response = $paypal -> request('DoExpressCheckoutPayment',$requestParams);
   if( is_array($response) && $response['ACK'] == 'Success') { // Payment successful
       // We'll fetch the transaction ID for internal bookkeeping
       $transactionId = $response['PAYMENTINFO_0_TRANSACTIONID'];
   }
}

Direct Payment

The Direct Payment API allows you to receive payments directly on your website or application, giving you complete control over the checkout process. PayPal tends to push users to register and use a PayPal account, which is understandable, but this conflicts somewhat with our interest to make the payment process as simple and clear as possible for our customers. For this reason, full control over the checkout process is preferred and gives us more options to optimize sales and generate more sales.

Direct Payment flow

The process is a bit simpler than that of Express Checkout, because the entire interaction occurs on our website, and we need to perform just one API call to process a normal payment: DoDirectPayment.

A couple of more API requests are required if you want to perform a transaction that is billed at a later date (for example, when you ship the product or confirm availability). These would be the Authorization & Capture API methods, which I will not cover in this post, but be aware that this option exists.

DirectPayment Parameters

DirectPayment requires different parameters than Express Checkout, as to be expected. While the transaction details parameters are similar (with different key names, to make it more interesting), the method also requires credit-card and address information.

DirectPayment’s basic parameters:

  • METHOD
    This is DoDirectPayment.
  • IPADDRESS
    This is the IP address of the payer. In PHP, we can retrieve it using the superglobal $_SERVER['REMOTE_ADDR']. You’ll have to do a bit more work to get the IP when dealing with set-ups that have a proxy between the PHP process and the outside network (such as nginx).
  • PAYMENTACTION
    This is the type of action that we want to perform. A value of Sale indicates an immediate transaction. A value of Authorization indicates that this transaction will not be performed immediately, but rather will be captured later using the Authorization & Capture API mentioned earlier.

Credit-card details:

  • CREDITCARDTYPE
    The credit-card type (Visa, MasterCard, etc.). See the API documentation for the full list.
  • ACCT
    The credit-card number. (Don’t you love these abbreviated key names?) This must conform to the particular format of the card’s type.
  • EXPDATE
    The expiration date, in MMYYYY format (i.e. a two-digit month and a four-digit year, as one string).
  • CVV2
    The “card verification value,” or security code, as it’s sometimes known.

Payer information and address parameters:

  • FIRSTNAME, LASTNAME
    The payer’s first name and last name, respectively (in separate fields). You can also provide an email address in an EMAIL parameter, but it’s not required.
  • CITY, STATE, COUNTRYCODE, ZIP
    The city, state, country code (as a two-letter code) and zip code parts of the address, all required.
  • STREET, STREET2
    Two lines for the address (only the first is required).

This address will be used in the address verification system (AVS). You’ll receive a specific error code if a transaction has failed due to an address verification failure.

The payment details parameters are the same as the ones for Express Checkout, but with slightly different names (AMT, ITEMAMT, CURRENCYCODE, SHIPPINGAMT, TAXAMT and DESC) and without the PAYMENTREQUEST_0_ prefix. Refer to the previous section or the API documentation for specific details on those.

Similarly, the item details parameters are similar to those of Express Checkout. These include L_NAMEm, L_DESCm, L_AMTm and L_QTYm, giving you granular control of item details in the order summary. The m integer variable is used to account for multiple items (replace with 0, 1 and so on for numbered items in the order). See the API documentation for a comprehensive list of item details.

Performing the Transaction

Sending the request using our function is very similar to GetExpressCheckoutToken. We pass all of the parameters into the request function as before, with the method set to DoDirectPayment.

$requestParams = array(
   'IPADDRESS' => $_SERVER['REMOTE_ADDR'],
   'PAYMENTACTION' => 'Sale'
);

$creditCardDetails = array(
   'CREDITCARDTYPE' => 'Visa',
   'ACCT' => '4929802607281663',
   'EXPDATE' => '062012',
   'CVV2' => '984'
);

$payerDetails = array(
   'FIRSTNAME' => 'John',
   'LASTNAME' => 'Doe',
   'COUNTRYCODE' => 'US',
   'STATE' => 'NY',
   'CITY' => 'New York',
   'STREET' => '14 Argyle Rd.',
   'ZIP' => '10010'
);

$orderParams = array(
   'AMT' => '500',
   'ITEMAMT' => '496',
   'SHIPPINGAMT' => '4',
   'CURRENCYCODE' => 'GBP'
);

$item = array(
   'L_NAME0' => 'iPhone',
   'L_DESC0' => 'White iPhone, 16GB',
   'L_AMT0' => '496',
   'L_QTY0' => '1'
);

$paypal = new Paypal();
$response = $paypal -> request('DoDirectPayment',
   $requestParams + $creditCardDetails + $payerDetails + $orderParams + $item
);

if( is_array($response) && $response['ACK'] == 'Success') { // Payment successful
   // We'll fetch the transaction ID for internal bookkeeping
   $transactionId = $response['TRANSACTIONID'];
}

There are plenty of parameters, but all relatively simple.

Error Handling

In a perfect world, this section would not exist. In reality, you will be referring to it quite a lot. PayPal can fail a transaction for a multitude of reasons, not all of which you can control.

The $response variable we returned from our paypalApiRequest() function could contain a different value than Success for the ACK parameter. That value could be:

  • Success
    Indicates a successful operation.
  • SuccessWithWarning
    Indicates a successful operation, and that messages were returned in the response that you should examine.
  • Failure
    Indicates a failed operation, and that the response contains one or more error messages explaining the failure.
  • FailureWithWarning
    Indicates a failed operation, and that messages were returned in the response that you should examine.

This gives us two success statuses and two failure statuses. The mock code above tests for the Success value only, but we could change it to check for SuccessWithWarning as well; and keep in mind that we need to find out what the warning is. A common scenario is that a Direct Payment charge will have been performed successfully, but the credit-card company responds that the transaction has failed, for whatever reason.

Errors from PayPal are returned in four parameters in the response:

  • L_ERRORCODE0
    A numeric error code, which can referenced against PayPal’s error code list (there are quite a few).
  • L_SHORTMESSAGE0
    A short error message describing the problem.
  • L_LONGMESSAGE0
    A longer error message describing the problem.
  • L_SEVERITYCODE0
    The severity code. (I couldn’t find any useful documentation on this, and it doesn’t really matter, so let’s put it aside.)

The 0 part of these parameters is an incrementing integer for multiple error message (1, 2, etc.).

Here are some common errors you’ll run into:

  • 10002
    Authentication or authorization failed. This usually indicates invalid API credentials, or credentials that do not match the type of environment you are working in (such as a live or sandbox environment).
  • 81***
    Missing parameter. There are quite a few of these, all starting with 81. Each refers to a specific required parameter that is missing from the request.
  • 104**
    Invalid argument. This indicates that one of the supplied parameters has an invalid value. Each argument has specific errors, all starting with 104. A common one is 10413, which means that the total cost of the cart items does not match the order’s amount (i.e. the total amount parameter, AMT, does not equal the items’ total plus shipping, handling, taxes and other charges).

How Do We Handle These Errors in Practice?

PayPal error messages vary and could contain private information that you do not want your users to see (such as an invalid merchant configuration). That being the case, showing PayPal error messages directly to users is not advisable, even though some of them might be useful.

In most cases, I would do the following:

  1. Set up a white-list array of errors that can be shown safely (such as a missing credit-card number and expiration date);
  2. Check the response code against that array;
  3. If the error message is not white-listed, then display a generic message, such as “An error has occurred while processing your payment. Please try again in a few minutes, or contact us if this is a recurring issue.”

If an error falls outside of the white-listed array, I will also log it to a file on the server and send an email to the administrator, with the full details so that someone is up to speed on payment failures. In fact, logging PayPal requests and responses is good practice regardless of errors, so that you can monitor and troubleshoot payment failures (I provide this option in the commercial component that I mentioned at the beginning of this article).

Ready To Get Started With The PayPal API?

In this post, I’ve covered two of the most widely used API methods, as well as error handling with the PayPal API. This should be enough for you to get started using the most popular payment platform online.

The PayPal API has many more methods and processes, more than can be covered in any one post. Once you get up to speed on the basic methods, learning the others should be relatively straightforward (even if somewhat exhausting). I hope this guide has given you a good head start on using the API. If you have questions or comments, I would love to hear from you in the comments!

Disclaimer: PayPal’s API is among the worst I’ve ever had to deal with. Inconsistencies, sometimes poor or conflicting documentation, unpredictable failures and account changes, and major differences between the live and sandbox versions all conspire to make the PayPal API quite a pain in the arse to work with. Over the years, I’ve taken my lumps from working quite a bit with the PayPal API, and I’ve published the results of my hard-learned lessons as a commercial PHP PayPal API component on the source-code marketplace Binpress.

Front cover: Image source

(al)

↑ Back to top

I'm an entrepreneur and web developer. Formerly started Lionite, a web development shop and incubator, now I'm CTO on Binpress, a discovery service and marketplace for source-code.

  1. 1

    Lorenzo Franchini

    September 5, 2011 4:47 am

    Thanks Eran, can’t wait to try. Paypal API is really chaotic, and I’m really curious to see if what I tried in the past was so wrong :)

    0
  2. 2

    My pleasure, Lorenzo :) If you have any questions after reading it, make sure to leave a comment about it!

    0
  3. 3

    Really nice article! It’s a really big shame that the PayPal API is so poor. But your article really helps demonstrate the usage without all that complicated stuff PayPal posts.

    Thanks!!!!!
    André

    0
  4. 4

    Great! This will serve as a great reference for my next project.

    0
  5. 5

    I have used Paypal for years and found it to be one of the easiest ever.

    0
  6. 6

    You were wise to avoid diving into website payment pro’s authorization and capture API calls, because that could merit an entirely separate article. I recently discovered there are processing constraints surrounding separate authorize and capture API calls.

    For example, you only have 3 days after the initial authorization to make a guaranteed capture. This is called the honor period. If you try to capture funds outside of the honor period you are not guaranteed the money.

    There is an option to re-authorize once within 30 days of the initial authorization, but that only gives you another 3 days to make a capture. These constraints mean that paypal is unsuitable for API automation for a multi-shipment business model that could involve many shipments sprinkled over a 30-day window.

    Furthermore, they have no PCI-compliant storage service like Authorize.net’s CIM, meaning you have no automated way to create a new authorization. I’m just putting in my two cents that if you are considering using direct payment for anything but a simultaneous authorization & capture, go with a more advanced gateway like Authorize.net.

    0
    • 7

      @Kevin
      Yes, the authorization and capture APIs and the rules governing their operations are quite complex. Frankly, the title for such an article should be called something like “diving off the deep end with the PayPal API” :)

      0
  7. 8

    great article! we often use paypal for a payment gateway and there are a few snippets I’ll be referencing back to in your article. thanks for sharing!

    0
  8. 9

    You mention in your article that Payments Pro is only available to US, this is untrue, I have a UK account which uses it fine.

    The only instance where it is only available to the US is in the sandbox website/api where you have to choose US as the merchant account in order to test your code.

    0
    • 10

      Yes, you are right – it is also available to Canadian and UK accounts. I’ll make the correction in the article, thanks for letting me know!

      0
  9. 11

    Hell, YES! Thank you for that article. The official PayPal API Documentation is one of the worst payment documentations ever. I searched the site about an hour (!) to find out how to make a mass payment. I’ll try your example tomorrow.

    0
  10. 12

    For a full overview of all available API calls see https://www.x.com/developers/paypal/documentation-tools/api

    Note: Not all will be available on Live accounts, but you can request access to pretty much all of them in Sandbox by filing a ticket with PayPal MTS.

    0
  11. 13

    Great article! I’ve written a PayPal Class that interacts with PayFlow. You can grab it here: http://www.richardcastera.com/projects/paypal-payflow-api-wrapper-class

    Cheers!

    0
  12. 14

    WTF are you people nuts? have you tried to use any OTHER payment gateways before? i can name several that have worse if not non-existant documentation and PayPal has one of the best developer programs in the world for a payment gateway.

    What are you code n00bs?

    0
  13. 16

    Thanks, i’ve been looking for a comprehensive guide on paypal integration! :)

    0
  14. 17

    I was talking about how I need to learn PayPal today and then I find this! Thanks =D

    0
  15. 18

    Could you implement a more secure method of storing the merchant account var and password? Plain text in a configuration file is sketchy

    0
  16. 19

    Despite the popularity of PayPal and the fact that people I know who have used it keep saying “easy”, PayPal documentation seems very hard to understand, to me.

    Your article has definitely made things clearer here. I have bookmarked and will come back with questions should I have any.

    Great thanks :)

    0
  17. 20

    Thank you for this Tutorial / Guide! Gonna read it tonight…

    0
  18. 21

    PayPal simply rocks. Thanks.

    0
  19. 22

    Thanks for this useful tutorial

    I tried using the Express Checkout, but I encountered a problem last request “DoExpressCheckoutPayment”.
    Following the guidance I get the error code 81115 “PaymentAction: Required parameter missing”. If I change the parameters of the request with the $checkoutDetails variable seems to work.
    Is this correct?

    thanks

    0
  20. 25

    Great article to help all people whom want to implement PayPal payment gateway on their website.

    artistechnologies.com

    0
  21. 26

    good article

    0
  22. 27

    I’ve been several payment processing websites (or websites that have a payment processing aspect).

    If you decide to use the IPN method (which is actually kinda cool because your IPN script gets pinged with almost every transaction so its possible to do some cool stuff) when a sale is made, make sure that you verify the purchase against what you intended to send to paypal checkout.

    I’ve seen people inject 0.01 for a value or even changing the currency to Japanese Yen.

    I assume they saved the form and changed it or they used firebug to change the values, whatever the case…. ensure you match your checkout data with your IPN data.

    0
  23. 29

    Disclaimer: lack of research makes for a bad article, you dont even understand the different API types.

    Next time Eran i suggest you research before writing something like this. All you really did was tidy up the PayPal SDK’s and walk though them, anyone could do that. Also i wonder if you have even used any other pay API’s before to base the comment “PayPal’s API is among the worst I’ve ever had to deal with.”.

    0
    • 30

      David, I’m not at Carmack-levels of programming-mastery, yet.
      However, I can tell you that going through all of the API documentation, for everything, that the PayPal documentation is HORRIBLE.
      Not only for the inner-workings of each API, but in how they separate useful sets of information (both in documentation and in APIs in general).

      Worse, they’ll stick incompatible method calls into the same API.
      Quick example:
      Button Manager allows you to create Token-based buttons for Hosted Solutions.
      That’s great, except that as I learned, hours into reading/implementation (because all of the requisite information is stored in four different documents, and you need to read through to figure out what links where, and what’s available to you at which clearance/cost levels), that’s not even an option unless you’re using Web Payment Pro.

      Then why put the call to create a hosted solution button into the button-manager API, which is supposed to be the only API that’s free of charge (except, it’s not, as the Express Checkout works, which is not what I had expected — except that I needed to come here and read this article, and then go back and reread all of the sales pitches on the horribly laid-out site, to figure out that it’s actually a viable alternative with a Premier account, without requiring WPP )?

      If “DRY” is your argument — sure, but there’s a point where “DRY” becomes stupid, and that point is where you can’t actually tell which module you’re using, because you need to ask three other, non-integral modules (that should be self-contained) to borrow methods, and to have users instinctively “know” this, just to avoid implementing similar functionality on the other end (when really, they could call the same method, seamlessly on their end, anyway).

      The point of the matter is that yes, there are some ugly, malformed APIs out there.
      Some are going to be way worse than PayPal. But how prolific is PayPal, and how horrible is their documentation in direct correlation to how important they are, on the web?

      This article was perfect for what I needed (and by that, I mean to get me out of having to go the button-manager route), by pointing me to an option that I didn’t have before, and fast-tracking me through the expected parameters.
      That will cut my implementation time down to nil, comparatively.

      0
  24. 31

    Thanks Eran, even though I’m an ASP.NET developer this tutorial ignited my interest in using the actual PayPal API and not some third party components which I am currently using now.

    You explained it so much better than them, and I agree their whole API documentation and Sandbox can be quite ambiguous and error prone at times.

    0
  25. 32

    I can only second the comment that PayPal API is one of the worst. Bad documentation is the primary problem, but the hoops one has to jump through is also problematic. It maybe worth noting that the Ebay API is also one of the worst I have ever worked with and the PayPal and Ebay API are both now maintained by the same team/company…

    0
  26. 33

    Thanks for this guide. We are putting up an online advertising web site In Sri Lanka and we were trying to get a payment solution integrated into our system. Your article has given us guidance as to how to implement paypal for our needs. :)

    0
  27. 34

    This article is very broad and helful, thanks! I once completed working checkout via PayPal, but when I tried it once again there were plenty of errors. So I need to start from the scratch.

    0
  28. 35

    PayPal? The same paypal that allows donations to KKK but not to Wikileaks? #occupywallstreet

    0
  29. 37

    Does the API allow you to set-up recurring payments?

    0
  30. 39

    Nice post, I was looking for information on credit card transactions and e-commerce. I found this blog about it in general, but it’s definitely nice to find something on paypal specifically.

    http://www.back40design.com/news/m.blog/22/credit-card-transactions-and-e-commerce-what-do-i-need-to-get-started

    0
  31. 40

    Phew,

    after hours of messing around I finally found a good tutorial!

    Thanks!!!!!!!

    0
  32. 41

    Anyone have a working one yet? I would like to see 1. How it came out and 2. A point to start and integrate from there.

    0
  33. 42

    At step 2. the header location should be the sandbox if testing within the sandbox environment!

    Location: https://www.sandbox.paypal.com/webscr?cmd=_express-checkout&token=
    not
    Location: https://www.paypal.com/webscr?cmd=_express-checkout&token=

    The latter is when live.

    0
  34. 43

    Playing around with the sandbox it turned out for me in Australia, that I need to provide a few more entries to the DoExpressCheckoutPayment array:

    ‘TOKEN’ => $_GET['token'],
    ‘PAYMENTACTION’ => ‘Sale’,
    ‘AMT’ => $checkoutDetails['PAYMENTREQUEST_0_AMT'], // or just ‘AMT’
    ‘CURRENCYCODE’ => $checkoutDetails['PAYMENTREQUEST_0_CURRENCYCODE'], // or just ‘CURRENCYCODE’

    and comment out PAYMENTREQUEST_0_PAYMENTACTION

    Why so? Anyone?

    0
  35. 45

    I find their API and documentation to be ok, it is their product offering that I find confusing.

    Is there an equivalent to Website Payments Pro (process credit-card payments through an API call) for those living outside the US, Canada and the UK?

    0
  36. 46

    will you please tell me how it will done??
    i want to show a “0″ value in label when user comes first time on my site and and after payment through paypal when he or she back on my page i want to show a value “1″ in label kindly help me as soon as posible
    thanks

    0
  37. 47
  38. 48

    One question. As I understand from PayPal’s documentation DoExpressCheckoutPayment call must be done when a user explicitly presses some kind of “Pay now button” on my site after he returns from PayPal’s site. I am now testing it in sandbox, and when I act as a buyer there is a message on PayPal site saying “You’re almost done. You will confirm your payment on Seller’s Test Store.” and a button “Continue”. After pressing “Continue” I do get redirected back to my site, and from all these I assume that I must show my customer some kind of button pressing which he confirms the payment, and only after that I execute DoExpressCheckoutPayment API call. If I do DoExpressCheckoutPayment call right after the user is redirected to my site, than the payment gets completed after the user presses “Continue” button on PayPal, and before he gets any chance to really confirm his payment as he was promised on PayPal’s site.

    Any ideas? Your help would be very much appreciated.

    0
  39. 50

    Regarding my previous post, I found out that if you add url parameter “useraction=commit” to redirect url (when you redirect a user to PayPal site) then at PayPal’s site the user is displayed “Pay Now” button instead of “Continue”. In this case it makes sense to execute DoExpressCheckoutPayment command right after the user is redirected back to our site. Note that you still have to execute DoExpressCheckoutPayment command in order to complete payment.

    Thank you all.

    0
  40. 51

    Hi Eran Galperin,

    Good Tutorial… finally i got the good tutorial after reading so many tutorials from the web..
    thanks a lot…. lol… :-)

    Is there any way to integrate the Express checkout in IPN process with Paypal.

    0
  41. 52

    How do you display the error messages from PayPal?

    0
  42. 53

    hi,

    i am using the paypal api for express shot checkout .. i got the message success and token and payerid but i didn’t get the amount in my PayPal account .. i mean in PayPal account i did’nt get the transaction …

    can you please help me to find out where i missed some thing

    thanks

    0
  43. 54

    Not work bro, already tried it. When do $paypal->request(); i got 500 internal server error on paypal website.

    https://www.paypal.com/webscr?cmd=_express-checkout&token=

    0
  44. 56

    @GusDeCooL: because the endpoint is set to sandbox mode, you must specify the sandbox url in header redirection.

    header( ‘Location: https://sandbox.paypal.com/webscr?cmd=_express-checkout&token=‘ . urlencode($token) );

    0
  45. 57

    I followed the tutorial. I’m using Checkout express. Everything looks fine, I get the success page but in my Paypal account I don’t get any money.
    Can you please tell me what I have missed?
    Thanks,

    0
    • 58

      Same problem there, any ideas?

      Still getting TRAN ID and success messag, but no Money in PayPal account..

      0
  46. 59

    Great Post !!! I am able to understand the adpative payment type in paypal but was unable to find where do i split the received money in percentage like 80% to primary receiver and rest to secondary receiver i.e. 20%.

    Could you help me on this.

    0
  47. 60

    Does this allow using third-party API model when I use Accelerated Boarding for my merchants as a shopping cart provider?

    0
  48. 61

    Thanks. Great tutorial, worked first time with express payment method.

    0
  49. 62

    Hi
    I am new in php
    i am facing this error please help me

    error setting certificate verify locations: CAfile: /media/www/html/kalosDemo/cacert.pem CApath: none
    Thanks

    0
  50. 63

    Hi
    I am facing this error please help me i am new in php
    error setting certificate verify locations: CAfile: /media/www/html/kalosDemo/cacert.pem CApath: none

    0
  51. 64

    Hi,
    Thanks for the great researched article.Can you please help me for this case.Is it possible to make parallel payment to multiple seller using do-direct method?My requirement is i have a shopping cart and i need to be able to make payment using credit card to multiple sellers at once.How can this be achieved?Can you provide links to some C# librady for achieving the same if its there.

    Thanks.

    0
  52. 65

    So many random issues with Paypal.
    Conflicting documentation, no real support or official tutorials.
    Basically, you will run into issues when your Gateway is live, and when it happens get ready to email there support team.

    The support team is alright, usually they answer your questions with a link to a pdf whichis impossible to deciper and may in fact be of no help.

    If I could recommend a payment system for clients? Bank based systems…
    Simpler, documented and with real support!

    0
  53. 66

    hey man great article, but i ran into a problem with the DoDirectPayment.

    it doesn’t seem to send the request and it doesn’t seem to throw any errors either?

    $request doesn’t come back as an array or even have a value at all.

    I’m completely at a loss, any ideas as to what i may be missing?

    0
    • 67

      @David Maison

      I’m having the same problem too. However, it worked when it runs on a hosted server such as 1&1 but not on a localhost server. I’m using XAMPP to host my website and the express checkout request array returns empty.

      0
  54. 68

    Hey all,
    I’ve tried this script, but I keep it getting payment not initiated. it seems to all work ok, interms of redirected to paypal and after payment, it seems to redirect to my site. What am I doing wrong, any chance of downloading the complete files so I can see where Im going wrong?

    Cheers
    Abs

    0
  55. 69

    Hey all,
    i am new to paypal api.i am using CheckoutByCreditCard method
    i am passing the false credit card detail.
    but m still getting SUCCESS and TRANSACTION ID as response
    i dont knw y m getting SUCCESS on wrong credit card detail

    Could you help me on this.
    thnx

    0
  56. 70

    Nice one Eran, but i have question, where i can find PaymentDetailesRequestType Class ??

    0
  57. 71

    Liked your article. I think it’s a shame that the API is so complex. Honestly in this day and age API technology should be more accessible for people to ‘plug and play’. Love Facebook connect for this reason… simple and it just works.

    0
  58. 72

    You guys should check out Braintree. It’ll avoid this whole mess and be the best decision you’ve ever made.

    0
  59. 73

    Thanks bro! it helps me alot with one of my project. Its better if you include all express checkout api call examples. Also mass payment example. Once again thanks.

    0
  60. 74

    Great article thanks so much

    0
  61. 75

    Josef van Niekerk

    May 20, 2013 7:10 am

    Awesome article, thanks so much for taking the time to write this.

    I had to struggle with a few errors like 10001 “The transaction could not be loaded”, which was because I was using the wrong credit card number for testing. That got sorted out by creating a test user on developer.paypal.com and using its credit card details with a random CVC number. It would have been more useful if the PayPal API responded with a more appropriate error messages.

    Another issue bugged that me for a while was error 10501, “Invalid Merchant Configuration”. This was solved by deleting the Business account on the sandbox, and simply recreating it from scratch and updating my configuration to the new Sandbox API credentials.

    I struggled for HOURS debugging and troubleshooting these issues. Thanks so much PayPal for the un-intuitive API, thank goodness for blokes like Eran!

    0
  62. 76

    Thanks for this useful article. Just had to change few things (CC and account details) to make it work.

    0
    • 77

      Hi, did u have some troubles?

      Can u provide us your solutuion, because the explained one here didnt work for me. I got Tran Id , evrything was ok, except the money never reached. No Overview in paypal…

      0
  63. 78

    Hi,
    Using the PayPal SOAP API is not very hard nowadays using a WSDL to php converter. I wrote an article about a simple example that can be used as a starting guide to call any PayPal SOAP API operation.
    You can find the article on http://www.wsdltophp.com/Blog/Get-your-PayPal-account-balance-with-the-PayPal-SOAP-API-and-WsdlToPhp,

    0
  64. 79

    Hi eran,
    i really appreciate for your great article.I am a newbie to paypal. I am processing the ipn message which comes from paypal but while processing the ipn message there is a chance that it might get an exception and i am catching that exception also.
    Now i want to know what happens, if the exception occurs while processing the ipn message. Will that subscription cancelled? and how the buyer knows about the failure.

    any help would be great.
    Thanks in advance,
    Msn

    0
  65. 80

    Hello.

    Thank you for your article.

    I’m beginner of Paypal API.

    I’d like to use paypal api in PHP.

    I have tried to connect Paypal API with your code.

    But I have always get the error message as following:

    TIMESTAMP=2013.08%2d23T21%3a04%3a09Z&CORRELATIONID=bb16f99d75316&ACK=Failure&VERSION=106%2e0&BUILD=7333778&L_ERRORCODE0=10002&L_SHORTMESSAGE0=Security%20error&L_LONGMESSAGE0=Security%20header%20is%20not%20valid&L_SEVERITYCODE0=Error

    What is the mean of this Security Header err?

    I hope your advice.

    Best,

    0
  66. 81

    Amazing post.
    You saved me days of frustration.
    I have made a post about your post in my blog
    r3mast.blogspot.com/2013/08/calling-paypal-api.html

    Thanks again man,
    Ramast

    0
  67. 82

    Read my new article on how to call the PayPal SOAP API without writing even one line of code at https://www.wsdltophp.com/Blog/Get-your-PayPal-account-balance-with-the-PayPal-SOAP-API-using-the-Web-interface

    0
  68. 83

    bhoopendra vishwakarma

    October 10, 2013 1:37 am

    TIMESTAMP=2013%2d10%2d10T09%3a34%3a52Z&CORRELATIONID=769628454d243&ACK=Failure&VERSION=51%2e0&BUILD=8077598&L_ERRORCODE0=11585&L_ERRORCODE1=11518&L_ERRORCODE2=11516&L_ERRORCODE3=11519&L_ERRORCODE4=11549&L_SHORTMESSAGE0=Missing%20Token%20or%20payment%20source&L_SHORTMESSAGE1=Invalid%20billing%20period%2e&L_SHORTMESSAGE2=Invalid%20billing%20frequency&L_SHORTMESSAGE3=Invalid%20amount&L_SHORTMESSAGE4=Start%20Date%20is%20required&L_LONGMESSAGE0=Missing%20Token%20or%20buyer%20credit%20card&L_LONGMESSAGE1=Billing%20period%20must%20be%20one%20of%20Day%2c%20Week%2c%20SemiMonth%2c%20or%20Year&L_LONGMESSAGE2=Billing%20frequency%20must%20be%20%3e%200%20and%20be%20less%20than%20or%20equal%20to%20one%20year&L_LONGMESSAGE3=Bill%20amount%20must%20be%20greater%20than%200&L_LONGMESSAGE4=Subscription%20start%20date%20is%20required&L_SEVERITYCODE0=Error&L_SEVERITYCODE1=Error&L_SEVERITYCODE2=Error&L_SEVERITYCODE3=Error&L_SEVERITYCODE4=ErrorArray
    (
    [TIMESTAMP] => 2013%2d10%2d10T09%3a34%3a52Z
    [CORRELATIONID] => 769628454d243
    [ACK] => Failure
    [VERSION] => 51%2e0
    [BUILD] => 8077598
    [L_ERRORCODE0] => 11585
    [L_ERRORCODE1] => 11518
    [L_ERRORCODE2] => 11516
    [L_ERRORCODE3] => 11519
    [L_ERRORCODE4] => 11549
    [L_SHORTMESSAGE0] => Missing%20Token%20or%20payment%20source
    [L_SHORTMESSAGE1] => Invalid%20billing%20period%2e
    [L_SHORTMESSAGE2] => Invalid%20billing%20frequency
    [L_SHORTMESSAGE3] => Invalid%20amount
    [L_SHORTMESSAGE4] => Start%20Date%20is%20required
    [L_LONGMESSAGE0] => Missing%20Token%20or%20buyer%20credit%20card
    [L_LONGMESSAGE1] => Billing%20period%20must%20be%20one%20of%20Day%2c%20Week%2c%20SemiMonth%2c%20or%20Year
    [L_LONGMESSAGE2] => Billing%20frequency%20must%20be%20%3e%200%20and%20be%20less%20than%20or%20equal%20to%20one%20year
    [L_LONGMESSAGE3] => Bill%20amount%20must%20be%20greater%20than%200
    [L_LONGMESSAGE4] => Subscription%20start%20date%20is%20required
    [L_SEVERITYCODE0] => Error
    [L_SEVERITYCODE1] => Error
    [L_SEVERITYCODE2] => Error
    [L_SEVERITYCODE3] => Error
    [L_SEVERITYCODE4] => Error
    )
    There is an error while processing your payment.Please try again with correct credentials

    Please help …………………………

    my code is :

    <?php

    require_once('includes/config.php');
    //function responsible to setup required data for direct payment
    if(isset($_POST["submit"]))
    {

    global $amount;

    /* echo "”;
    print_r($_POST);
    echo “”;
    die; */
    $cardHolderName=$_POST["cardHolderName"];
    $firstName = $_POST["dname"];
    $creditCardType = $_POST["cardType"]; //card type
    $creditCardNumber = $_POST["creditCardNumber"];
    $expDateYear = $_POST["expireDate"];
    $amount=$_POST["damount"];
    $cvv2Number = $_POST["securityCode"];
    $subscribeDate = $_POST["subscribeDate"];
    $arr1 = str_split($amount);
    $arr2 = (array_filter($arr1, “is_numeric”));
    $comma_separated = implode(“”, $arr2);
    $lastamount = (int)$comma_separated;
    $month = $_POST["billingperoid"];
    $saveammount = $amount;
    $address1 = $_POST["prmt_address"];
    //permanent address
    $city = $_POST["cc_city"];
    $state = $_POST["cc_state"]; //address state
    $zip = $_POST["cc_zip"]; //address zip code
    $country = $_POST["cc_country"]; // US or other valid country code
    $currencyID = urlencode(‘USD’); // or other currency (‘GBP’, ‘EUR’, ‘JPY’, ‘CAD’, ‘AUD’)
    global $nvpStr;
    function setupPaymentDetails()
    {

    // Add request-specific fields to the request string.

    $nvpStr = “&PAYMENTACTION=$paymentType&AMT=$lastamount&CREDITCARDTYPE=$creditCardType&ACCT=$creditCardNumber”.
    “&EXPDATE=$expDateYear&CVV2=$cvv2Number&FIRSTNAME=$firstName&LASTNAME=$lastName”.
    “&STREET=$address1&STATE=$state&CITY=$city&ZIP=$zip&COUNTRYCODE=$country&BUYERCREDITCARD=$cardHolderName&AMOUNT=$saveammount&CURRENCYCODE=$currencyID”.
    “&PROFILESTARTDATE=”.date(“Y-m-d”).”T”.date(“H:i:s”).”Z&DESC=Prepentice&BILLINGPERIOD=Month&BILLINGFREQUENCY=”.$month.”&MAXFAILEDPAYMENTS=1″;
    }
    // Execute the API operation; see the PPHttpPost function above.
    $httpParsedResponseAr = PPHttpPost(‘CreateRecurringPaymentsProfile’, $nvpStr);

    if(“SUCCESS” == strtoupper($httpParsedResponseAr["ACK"]) || “SUCCESSWITHWARNING” == strtoupper($httpParsedResponseAr["ACK"])) {

    $sqlQuery=”insert into tbl_payments(CREDITCARDTYPE,ACCT,cardHolderName,DONATORNAME,EXPDATE,AMOUNT,CVV)values(‘$creditCardType’,'$creditCardNumber’,'$cardHolderName’,'$firstName’,'$expireDate’,$amount,$securityCode)”;
    $result=mysql_query($sqlQuery);
    echo “Your payment has been done successfully”;
    } else {
    echo “There is an error while processing your payment.Please try again with correct credentials”;
    }

    }

    //paypal do direct payment for recurring profile
    function PPHttpPost($methodName_,$nvpStr_) {
    $environment = ‘sandbox’; // or ‘beta-sandbox’ or ‘live’
    // Set up your API credentials, PayPal end point, and API version.
    $API_UserName = urlencode(‘vivekpandey_api1.webworldexpertsindia.com’);//my_api_username
    $API_Password = urlencode(’1375868944′); //my_api_password
    $API_Signature = urlencode(‘Ai1PaghZh5FmBLCDCTQpwG8jB264AmPewRjqzn4Xq37XTnvFG-bGjkjY’); //my_api_signature
    $API_Endpoint = “https://api-3t.paypal.com/nvp”;
    if(“sandbox” === $environment || “beta-sandbox” === $environment) {
    $API_Endpoint = “https://api-3t.$environment.paypal.com/nvp”;
    }
    $version = urlencode(’51.0′);

    // Set the curl parameters.
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $API_Endpoint);
    curl_setopt($ch, CURLOPT_VERBOSE, 1);

    // Turn off the server and peer verification (TrustManager Concept).
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_PROXY, “192.168.1.2:3128″);
    //curl_setopt($curl, CURLOPT_PROXY, “192.168.1.2″);
    curl_setopt($ch, CURLOPT_PROXYPORT, 3128);
    // Set the API operation, version, and API signature in the request.
    $nvpreq = “METHOD=$methodName_&VERSION=$version&PWD=$API_Password&USER=$API_UserName&SIGNATURE=$API_Signature$nvpStr_”;
    // Set the request as a POST FIELD for curl.
    curl_setopt($ch, CURLOPT_POSTFIELDS, $nvpreq);

    // Get response from the server.
    $httpResponse = curl_exec($ch);
    echo ”;
    print_r($httpResponse);
    if(!$httpResponse) {
    exit(“$methodName_ failed: “.curl_error($ch).’(‘.curl_errno($ch).’)');
    }

    // Extract the response details.
    $httpResponseAr = explode(“&”, $httpResponse);
    $httpParsedResponseAr = array();
    foreach ($httpResponseAr as $i => $value) {
    $tmpAr = explode(“=”, $value);
    if(sizeof($tmpAr) > 1) {
    $httpParsedResponseAr[$tmpAr[0]] = $tmpAr[1];
    }
    }
    print_r($httpParsedResponseAr);
    if((0 == sizeof($httpParsedResponseAr)) || !array_key_exists(‘ACK’, $httpParsedResponseAr)) {
    exit(“Invalid HTTP Response for POST request($nvpreq) to $API_Endpoint.”);
    }
    return $httpParsedResponseAr;

    }

    ?>

    0
  69. 84

    bhoopendra vishwakarma

    October 10, 2013 1:39 am

    how to embaded phpbb module in codegniter framework..

    please reply me quickly…………..

    0
  70. 85

    May all the gods that exist bless your kind face!!!!

    Was getting so frustrated over the ridiculous API docs and beginning to think I was completely stupid for not getting it until I found this piece of gold.

    0
  71. 86

    Tone Irene Andersen

    January 2, 2014 12:42 pm

    Hi.. Ive been struggling with paypal for quite some time now. Ive been trying to setup my site to handle subscriptions, but there is very little explaination how to handle ipn for these. This article have helped a great deal.

    0
  72. 87

    Thanks.. WoW just Wow.. supert Article… So well Elaborated So briefly.. Really useful…
    thanks

    0
  73. 88

    Hi

    I’ve get a token using above and redirect (in sandbox mode) with it to PayPal.

    Get sent to random Company pages on PayPal, some not in English. Not my shopping cart amounts ie the Iphone above. This normal?

    Great article beats the PayPal one.

    Graham

    0

Leave a Comment

Yay! You've decided to leave a comment. That's fantastic! Please keep in mind that comments are moderated and rel="nofollow" is in use. So, please do not use a spammy keyword or a domain as your name, or else it will be deleted. Let's have a personal and meaningful conversation instead. Thanks for dropping by!

↑ Back to top