Integrating PIN Payments Using PHP
Recently I had to integrate PIN Payments with a website we have built. With PIN being a bit of a new kid on the block as far as payment options go, it wasn't too much of a surprise to find that there was very little documentation on how to integrate it.
The API exists but the PHP code samples simply give you a PHP library from Omnipay and call it quits. The library is built to handle multiple payment methods so for me it was a bit of overkill, not to mention having to install it via Composer.
So I set about writing my own basic php script. If you're looking to use PHP to integrate PIN Payments, this is how you do it...
First you need the private keys for both the test and live PIN end points. When you register for PIN they are available when you log in.
Next you need a form. Just a simple HTML form will do. You actually need a lot of information for the payment to be processed so here is a run down of the fields you need:
Field Name | Description |
amount | This is the amount to be charged, in cents |
currency | The default currency is AUD but it can be changed here if required |
description | The description of what is being bought / paid for |
The user's email address | |
ip_address | IP Address of the user |
card[number] | Spaces do get removed but just validate for numbers only |
card[expiry_month] | Month in MM format |
card[expiry_year] |
Year in YYYY format |
card[cvc] | Card CVC number |
card[name] | Name on the card - must be two words or more to work |
card[address_line1] | Street address of user |
card[address_line2] | This is the only optional field |
card[address_city] | Address City |
card[address_postcode] | Address Postcode |
card[state] | Address State |
card[country] | Address Country |
There is no point actually writing a form here as every form will vary a bit but as long as you have that data being posted to the processing script, you'll be all good.
Now that you have your form sorted, it's time to do some processing.
First we need to set some Authentication variables and determine if we are testing the system or not.
//Authentication
$test = true;
$auth['u'] = (($test === true) ? 'xxxxTestPrivateKeyxxx' : 'xxxxLivePrivateKeyxxxx'); //Private Key from PIN
$auth['p'] = ''; //API calls use empty password
Next we set the charge URL. If $test is set to true above, we need to add test- into the URL
//Set URL
$url = 'https://' . (($test === true) ? 'test-' : '') . 'api.pin.net.au/1/charges';
Time to set which data we are sending through to PIN. Obviously you will want to make sure all values are safe before sending through, this example is just giving you the basics. Because I was using CakePHP, the data in this example has been posted through as $this->data['Payment']['form_field_name'] but you need to replace that with whatever field you are posting through.
However you do it, the goal is to get an array containing the fields and field names that PIN requires.
//Fields to Post
$post = array();
$post['amount'] = ($this->data['Payment']['amount'] * 100);
$post['currency'] = "AUD";
$post['description'] = urlencode("Payment for ...");
$post['email'] = $this->data['Payment']['email'];
$post['ip_address'] = $_SERVER['REMOTE_ADDR'];
$post['card[number]'] = $this->data['Payment']['cc_number'];
$post['card[expiry_month]'] = $this->data['Payment']['cc_expiry']['month'];
$post['card[expiry_year]'] = $this->data['Payment']['cc_expiry']['year'];
$post['card[cvc]'] = $this->data['Payment']['cc_cvc'];
$post['card[name]'] = $this->data['Payment']['cc_name'];
$post['card[address_line1]'] = $this->data['Payment']['street'];
$post['card[address_line2]'] = $this->data['Payment']['street2'];
$post['card[address_city]'] = $this->data['Payment']['town'];
$post['card[address_postcode]'] = $this->data['Payment']['postcode'];
$post['card[address_state]'] = $this->data['Payment']['state'];
$post['card[address_country]'] = $this->data['Payment']['country'];
Let's post the information through to PIN now using cURL and get a response happening:
// Create a curl handle
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_USERPWD, $auth['u'] . ":" . $auth['p']); //authenticate
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); //make sure it returns a response
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // allow https verification if true
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); // allow https verification if true
curl_setopt($ch, CURLOPT_POST, 1); //tell it we are posting
curl_setopt($ch, CURLOPT_POSTFIELDS, $post); //tell it what to post
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Accept: application/json')); //response comes back as json
// Execute
$response = curl_exec($ch);
// Check if any error occurred
if(!curl_errno($ch)){$info = curl_getinfo($ch);}
// Close handle
curl_close($ch);
That's essentially it. At this point $response holds the information as to whether or not the transaction was successful and if not why not. It's returned as json so we need to decode that before we can work with it.
//Decode JSON
$response = json_decode($response, true);
Finally, are we continuing or not?
//Success?
if(!empty($response['response']['success']) && $response['response']['success'] == 1)
{
.... Successful, place any further code such as a success message here ...
}
else
{
.... Not successful, let the user know. The error message is held in
$response['error_description']
so you can output that to show invalid card, declined, expired, etc.
}
PIN does provide some sample credit cards as well which will return different results, so you can test how your system handles those.
The list of these cards is found here (Link opens in a new window).
Has this worked for you? Do you have any suggestions on how it can be improved?
UPDATE: As pointed out by PIN, you can also request a token to use for processing the payment:
@templemantwells Hey Patrick! Thanks for the blog post. Note you can use tokens instead of card details: https://t.co/ApCKifHFek
— Pin Payments (@pin_payments) March 4, 2014