Integrating PIN Payments Using PHP

Looking for a quick and easy guide to integrating PIN Payments with your website? This is it...

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
email 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


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.

$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-' : '') . '';

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

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?

if(!empty($response['response']['success']) && $response['response']['success'] == 1)
    .... Successful, place any further code such as a success message here ...
    .... Not successful, let the user know. The error message is held in
    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: