Introduction
PayPal provides SDK’s for all of their API’s in various programming languages. These SDK’s work just fine, however, they are fairly basic and I consider them good samples or starting-points, but not a complete, easy-to-use solution. As such, I put together my own PHP class for PayPal API’s that makes it very simple to work with all of PayPal’s web services.
My focus upon developing this class was to make it simple for novice and intermediate PHP developers to work with PayPal. Therefore, you might notice I don’t follow the typical structure of creating multiple Set and Get methods within this class. Instead, I’ve constructed everything to work off basic PHP array data. You simply gather all of your request data into a PHP array and pass that into the class methods (one for each PayPal API call). The class handles generating the requests for PayPal, sending it off to the correct end-point depending on whether or not you’re using the sandbox for testing, and parsing the results accordingly. The methods return a simple PHP array of all response data including any errors or warnings returned, fraud filters, etc. This eliminates the need to learn about SOAP, building NVP strings, POST requests with CURL, and all of the other details involved in working with web service API’s.
Usage Overview
The class was designed to follow the same data grouping patterns that PayPal does in their NVP Documentation, and I even included commented notes about all of the potential request fields you can use with each API call. It is still recommended that you keep a copy of PayPal’s documentation handy while working, though, for quick reference if necessary.
I’m going to discuss some of the general rules for using this class and then I will provide some usage samples that should give you a good idea of how to work with this class. I think you’ll find it’s very simple once you understand the way it was designed.
As previously mentioned, the class is intended to be used along-side the NVP documentation that PayPal provides. There is a function/method for each call in the documentation. Each function in the class has a commented template of the arrays you can use for that particular request, so all you need to do is copy and paste the blank array-set template into a new file and populate the data placeholders. We’ll go over that in more depth in a bit.
The first thing you’ll need to do is update the /class/includes/config.php file with your API credentials. Then, when you first setup the PayPal object within a script you will pass in an array consisting of the following values:
- Sandbox – Boolean option (true or false) for whether or not you’d like to use the test servers or not.
- APIVersion – The version of the API you’d like to use. The class defaults to the current version of the time of this writing (64.0).
- APIUsername – API username of the PayPal account you’re making the call with.
- APIPassword – API password of the PayPal account you’re making the call with.
- APISignature – API signature of the PayPal account you’re making the call with.
The functions within this class are built to generate request strings using data from the arrays that you pass into them. The names of the fields you pass in are used in the string generated so you simply need to make sure the names you provide match the names that PayPal shows in their documentation. Again, the array templates set this all up for you to make it easy. The METHOD parameter has been hard-coded into each function within the class so you don’t need to worry about passing it.
The array templates are split up the same way PayPal splits data in their documentation. For example, there are separate arrays to store PayerInfo, ShippingInfo, BillingInfo, etc. Once all of these arrays are setup you need to nest them all in a single, “master” array which will be passed into the class method call.
There are just a couple of other things I’d like to discuss before we dive into the usage samples. I’ve provided a few options in this class that PayPal doesn’t actually have in their system to make things a little bit easier for the developer.
For example, when using PayPal Express Checkout you can specify whether you want to use PayPal’s checkout flow as your final review or whether you’d like to use your own review pages after redirecting back to your site. This changes the button on PayPal from Continue to Pay and allows you to move on without calling GetExpressCheckoutDetails if you want to. The SetExpressCheckout() method in this class includes 1 extra field that I called SKIPDETAILS. This field is a boolean option (true/false) that you can use to specify how you want the checkout flow to work. If SKIPDETAILS is set to true, the PayPal review page will have a Pay button and the PayerID will be returned as a parameter in the ReturnURL you specified. If it’s set to false the button on PayPal will say Continue and you will need to call GetExpressCheckoutDetails to retrieve the PayerID. The details of that are beyond the scope of this article, but I wanted to explain what that SKIPDETAILS parameter is for.
On that same note, the SetExpressCheckout() method handles generating the redirect URL for you and returns it in the response array as REDIRECTURL. It will automatically setup your useraction parameter based on what you specified for SKIPDETAILS. If the last couple of paragraphs have confused you I’d highly recommend you study the Express Checkout documentation PayPal provides.
Finally, all the responses returned from the class methods will include all of the actual PayPal response fields themselves as well as an ERRORS array, which will contain any errors/warnings that might have occurred, a REQUESTDATA array which provides an easy look at the exact request data that was sent for that API call, and an ORDERITEMS array (where applicable) that consists of the order items included with that API call. This makes it very easy to loop through such items for updating databases, generating email receipts, etc. There will also be a RAWREQUEST and RAWRESPONSE field returned with all result arrays so you can easily see exactly what was sent to PayPal and exactly what came back for troubleshooting purposes.
Ok, with all of that out of the way let’s dive into some usage samples!
Usage Samples
GetBalance Request
// Included required files. require_once('includes/config.php'); require_once('includes/paypal.nvp.class.php'); // Setup PayPal object $PayPalConfig = array( 'Sandbox' => $sandbox, 'APIUsername' => $api_username, 'APIPassword' => $api_password, 'APISignature' => $api_signature ); $PayPal = new PayPal($PayPalConfig); // Populate data arrays with order data. $GBFields = array( 'returnallcurrencies' => '1' // Whether or not to return all currencies. 0 or 1. ); // Wrap all data arrays into a single, “master” array which will be passed into the class function. $PayPalRequestData = array( 'GBFields' => $GBFields ); // Pass the master array into the PayPal class function $PayPalResult = $PayPal->GetBalance($PayPalRequestData); // Display results echo '<pre/>'; print_r($PayPalResult);
GetBalance Output Result
Array ( [L_AMT0] => 882861.53 [L_CURRENCYCODE0] => USD [TIMESTAMP] => 2010-09-16T21:26:09Z [CORRELATIONID] => c518a53de1742 [ACK] => Success [VERSION] => 64.0 [BUILD] => 1492716 [ERRORS] => Array ( ) [BALANCERESULTS] => Array ( [0] => Array ( [L_AMT] => 882861.53 [L_CURRENCYCODE] => USD ) ) [REQUESTDATA] => Array ( [USER] => sandbo------------------.com [PWD] => 12-----------74 [VERSION] => 64.0 [BUTTONSOURCE] => AngellEYE_PHPClass [SIGNATURE] => AiK----------------------------W18v [METHOD] => GetBalance [RETURNALLCURRENCIES] => 1 ) [RAWREQUEST] => USER=san--------ye.com&PWD=12---74&VERSION=64.0&BUTTONSOURCE=AngellEYE_PHPClass&SIGNATURE=AiKZh----18v&METHOD=GetBalance&RETURNALLCURRENCIES=1 [RAWRESPONSE] => L_AMT0=882861%2e53&L_CURRENCYCODE0=USD&TIMESTAMP=2010%2d09%2d16T21%3a26%3a09Z&CORRELATIONID=c518a53de1742&ACK=Success&VERSION=64%2e0&BUILD=1492716 )
As you can see, the request is very simple using this class. We simply include the the config file and the PayPal class file, and then setup the object by passing the credentials in to the new class instance. Then, we specify whether or not we want multiple currencies to be returned or not. That’s all this particular call provides for request options so we wrap that into a parent array and pass it into the GetBalance() method of the class. The result displayed above is very similar to what you’ll see with any API call, however, in this case we have an additional array for BALANCERESULTS. This array only has a single balance in because my sandbox account isn’t tracking multiple currency balances. If you had more than one currency balance in your account, though, each would be returned in that array which makes it simple to loop through and handle accordingly.
DoDirectPayment Request
// Included required files. require_once('includes/config.php'); require_once('includes/paypal.nvp.class.php'); // Setup PayPal object $PayPalConfig = array( 'Sandbox' => $sandbox, 'APIUsername' => $api_username, 'APIPassword' => $api_password, 'APISignature' => $api_signature ); $PayPal = new PayPal($PayPalConfig); // Populate data arrays with order data. $DPFields = array( 'paymentaction' => 'Sale', // How you want to obtain payment. Authorization indidicates the payment is a basic auth subject to settlement with Auth & Capture. Sale indicates that this is a final sale for which you are requesting payment. Default is Sale. 'ipaddress' => $_SERVER['REMOTE_ADDR'], // Required. IP address of the payer's browser. 'returnfmfdetails' => '1' // Flag to determine whether you want the results returned by FMF. 1 or 0. Default is 0. ); $CCDetails = array( 'creditcardtype' => 'MasterCard', // Required. Type of credit card. Visa, MasterCard, Discover, Amex, Maestro, Solo. If Maestro or Solo, the currency code must be GBP. In addition, either start date or issue number must be specified. 'acct' => '5522340006063638', // Required. Credit card number. No spaces or punctuation. 'expdate' => '022017', // Required. Credit card expiration date. Format is MMYYYY 'cvv2' => '516', // Requirements determined by your PayPal account settings. Security digits for credit card. 'startdate' => '', // Month and year that Maestro or Solo card was issued. MMYYYY 'issuenumber' => '' // Issue number of Maestro or Solo card. Two numeric digits max. ); $PayerInfo = array( 'email' => 'tester@testerson.com', // Email address of payer. 'payerid' => '', // Unique PayPal customer ID for payer. 'payerstatus' => '', // Status of payer. Values are verified or unverified 'business' => 'Testers, LLC' // Payer's business name. ); $PayerName = array( 'salutation' => 'Mr.', // Payer's salutation. 20 char max. 'firstname' => 'Tester', // Payer's first name. 25 char max. 'middlename' => 'T.', // Payer's middle name. 25 char max. 'lastname' => 'Testerson', // Payer's last name. 25 char max. 'suffix' => 'Jr.' // Payer's suffix. 12 char max. ); $BillingAddress = array( 'street' => '123 Test Ave.', // Required. First street address. 'street2' => '', // Second street address. 'city' => 'Kansas City', // Required. Name of City. 'state' => 'MO', // Required. Name of State or Province. 'countrycode' => 'US', // Required. Country code. 'zip' => '64111', // Required. Postal code of payer. 'phonenum' => '555-555-5555' // Phone Number of payer. 20 char max. ); $ShippingAddress = array( 'shiptoname' => 'Tester Testerson', // Required if shipping is included. Person's name associated with this address. 32 char max. 'shiptostreet' => '123 Test Ave.', // Required if shipping is included. First street address. 100 char max. 'shiptostreet2' => '', // Second street address. 100 char max. 'shiptocity' => 'Kansas City', // Required if shipping is included. Name of city. 40 char max. 'shiptostate' => 'MO', // Required if shipping is included. Name of state or province. 40 char max. 'shiptozip' => '64030', // Required if shipping is included. Postal code of shipping address. 20 char max. 'shiptocountrycode' => 'US', // Required if shipping is included. Country code of shipping address. 2 char max. 'shiptophonenum' => '555-555-5555' // Phone number for shipping address. 20 char max. ); $PaymentDetails = array( 'amt' => '100.00', // Required. Total amount of order, including shipping, handling, and tax. 'currencycode' => 'USD', // Required. Three-letter currency code. Default is USD. 'itemamt' => '85.00', // Required if you include itemized cart details. (L_AMTn, etc.) Subtotal of items not including S&H, or tax. 'shippingamt' => '5.00', // Total shipping costs for the order. If you specify shippingamt, you must also specify itemamt. 'handlingamt' => '5.00', // Total handling costs for the order. If you specify handlingamt, you must also specify itemamt. 'taxamt' => '5.00', // Required if you specify itemized cart tax details. Sum of tax for all items on the order. Total sales tax. 'desc' => 'Testing Payments Pro', // Description of the order the customer is purchasing. 127 char max. 'custom' => '', // Free-form field for your own use. 256 char max. 'invnum' => '', // Your own invoice or tracking number 'notifyurl' => '' // URL for receiving Instant Payment Notifications. This overrides what your profile is set to use. ); $OrderItems = array(); $Item = array( 'l_name' => 'Widget 123', // Item Name. 127 char max. 'l_desc' => 'Test widget 123.', // Item description. 127 char max. 'l_amt' => '50.00', // Cost of individual item. 'l_number' => 'ABC123', // Item Number. 127 char max. 'l_qty' => '1', // Item quantity. Must be any positive integer. 'l_taxamt' => '', // Item's sales tax amount. 'l_ebayitemnumber' => '', // eBay auction number of item. 'l_ebayitemauctiontxnid' => '', // eBay transaction ID of purchased item. 'l_ebayitemorderid' => '' // eBay order ID for the item. ); array_push($OrderItems, $Item); $Item = array( 'l_name' => 'Widget 456', // Item Name. 127 char max. 'l_desc' => 'Test widget 456.', // Item description. 127 char max. 'l_amt' => '35.00', // Cost of individual item. 'l_number' => 'CBA456', // Item Number. 127 char max. 'l_qty' => '1', // Item quantity. Must be any positive integer. 'l_taxamt' => '', // Item's sales tax amount. 'l_ebayitemnumber' => '', // eBay auction number of item. 'l_ebayitemauctiontxnid' => '', // eBay transaction ID of purchased item. 'l_ebayitemorderid' => '' // eBay order ID for the item. ); array_push($OrderItems, $Item); // Wrap all data arrays into a single, “master'' array which will be passed into the class function. $PayPalRequestData = array( 'DPFields' => $DPFields, 'CCDetails' => $CCDetails, 'PayerName' => $PayerName, 'BillingAddress' => $BillingAddress, 'PaymentDetails' => $PaymentDetails, 'OrderItems' => $OrderItems ); // Pass the master array into the PayPal class function $PayPalResult = $PayPal->DoDirectPayment($PayPalRequestData); // Display results echo '<pre />'; print_r($PayPalResult);
DoDirectPayment Output Result
Array ( [TIMESTAMP] => 2010-09-16T22:07:23Z [CORRELATIONID] => 57a8c3d7e8ae [ACK] => Success [VERSION] => 64.0 [BUILD] => 1505414 [AMT] => 100.00 [CURRENCYCODE] => USD [AVSCODE] => X [CVV2MATCH] => M [TRANSACTIONID] => 87129234BF266101P [ERRORS] => Array ( ) [REQUESTDATA] => Array ( [USER] => sandb----------ye.com [PWD] => 12-----74 [VERSION] => 64.0 [BUTTONSOURCE] => AngellEYE_PHPClass [SIGNATURE] => AiKZh-------------96W18v [METHOD] => DoDirectPayment [PAYMENTACTION] => Sale [IPADDRESS] => 173.197.0.115 [RETURNFMFDETAILS] => 1 [CREDITCARDTYPE] => MasterCard [ACCT] => 5522------3638 [EXPDATE] => 022013 [CVV2] => 516 [STARTDATE] => [ISSUENUMBER] => [SALUTATION] => Mr. [FIRSTNAME] => Tester [MIDDLENAME] => T. [LASTNAME] => Testerson [SUFFIX] => Jr. [STREET] => 123 Test Ave. [STREET2] => [CITY] => Kansas City [STATE] => MO [COUNTRYCODE] => US [ZIP] => 64111 [PHONENUM] => 555-555-5555 [AMT] => 100.00 [CURRENCYCODE] => USD [ITEMAMT] => 85.00 [SHIPPINGAMT] => 5.00 [HANDLINGAMT] => 5.00 [TAXAMT] => 5.00 [DESC] => Testing Payments Pro [CUSTOM] => [INVNUM] => [NOTIFYURL] => [L_NAME0] => Widget 123 [L_DESC0] => Test widget 123. [L_AMT0] => 50.00 [L_NUMBER0] => ABC123 [L_QTY0] => 1 [L_TAXAMT0] => [L_EBAYITEMNUMBER0] => [L_EBAYITEMAUCTIONTXNID0] => [L_EBAYITEMORDERID0] => [L_NAME1] => Widget 456 [L_DESC1] => Test widget 456. [L_AMT1] => 35.00 [L_NUMBER1] => CBA456 [L_QTY1] => 1 [L_TAXAMT1] => [L_EBAYITEMNUMBER1] => [L_EBAYITEMAUCTIONTXNID1] => [L_EBAYITEMORDERID1] => ) [RAWREQUEST] => USER=sandbo_1----e.com&PWD=12---4&VERSION=64.0&BUTTONSOURCE=AngellEYE_PHPClass&SIGNATURE=AiKZhE-------W18v&METHOD=DoDirectPayment&PAYMENTACTION=Sale&IPADDRESS=173.197.0.115&RETURNFMFDETAILS=1&CREDITCARDTYPE=MasterCard&ACCT=552---638&EXPDATE=022013&CVV2=516&STARTDATE=&ISSUENUMBER=&SALUTATION=Mr.&FIRSTNAME=Tester&MIDDLENAME=T.&LASTNAME=Testerson&SUFFIX=Jr.&STREET=123+Test+Ave.&STREET2=&CITY=Kansas+City&STATE=MO&COUNTRYCODE=US&ZIP=64111&PHONENUM=555-555-5555&AMT=100.00&CURRENCYCODE=USD&ITEMAMT=85.00&SHIPPINGAMT=5.00&HANDLINGAMT=5.00&TAXAMT=5.00&DESC=Testing+Payments+Pro&CUSTOM=&INVNUM=&NOTIFYURL=&L_NAME0=Widget+123&L_DESC0=Test+widget+123.&L_AMT0=50.00&L_NUMBER0=ABC123&L_QTY0=1&L_TAXAMT0=&L_EBAYITEMNUMBER0=&L_EBAYITEMAUCTIONTXNID0=&L_EBAYITEMORDERID0=&L_NAME1=Widget+456&L_DESC1=Test+widget+456.&L_AMT1=35.00&L_NUMBER1=CBA456&L_QTY1=1&L_TAXAMT1=&L_EBAYITEMNUMBER1=&L_EBAYITEMAUCTIONTXNID1=&L_EBAYITEMORDERID1= [RAWRESPONSE] => TIMESTAMP=2010%2d09%2d16T22%3a07%3a23Z&CORRELATIONID=57a8c3d7e8ae&ACK=Success&VERSION=64%2e0&BUILD=1505414&AMT=100%2e00&CURRENCYCODE=USD&AVSCODE=X&CVV2MATCH=M&TRANSACTIONID=87129234BF266101P )
With the DoDirectPayment call you can see there is a lot more information available with the request and the response. You can see the request arrays are split up the same way PayPal does in their documentation: DPFields, CCDetails, PayerInfo, PayerName, BillingAddress, ShippingAddress, PaymentDetails, and OrderItems. These are all then nested into a parent array called $PayPalRequestData which is then passed into the DoDirectPayment() method of the class.
The result consists of an array of all the response field PayPal returned along with an empty Errors array (because no errors occurred), a RequestData array, which contains all of the request fields nicely formatted, and then RAWREQUEST/RESPONSE fields that contain exactly what was sent back and forth to and from PayPal.
Conclusion
Use of this PHP class for PayPal Payments Pro will make working with PayPal API’s much easier and you’ll be able to accomplish some serious tasks with PayPal very quickly. The class includes every single call PayPal provides in their API system, and a separate class file includes all of the calls for Adaptive Payments as well. The Adaptive Payments class is used in exactly the same way as the NVP class, however, it actually uses XML instead of NVP within it. Usage is exactly the same, though.
Obtaining the Class
You may download the class and stay up-to-date with it at my blog: Angell EYE Officially Releases PayPal Payments Pro PHP Class. I will be updating this class as PayPal updates their web services and I will also provide more usage samples and some video screen-casts to help learn to use this class.
Good luck, and happy coding!