Skip to main content

Sample Code & Examples

Transaction Types

SALE

The following example PHP code shows how to send a SALE transaction (amount £21,01) with support for 3-D Secure using the Gateway library.

For more detail about the 3DS process, do not forget to visit our 3DS Example.

info

An expiry month of 12 (December) will simulate the non frictionless flow and a challenge will appear to the cardholder.


<?PHP

require('gateway.php');
use \P3\SDK\Gateway;

// Merchant signature key
Gateway::$merchantSecret = '3obzOxdqw6e1u';

// Handpoint Gateway URL
Gateway::$directUrl = 'https://commerce-api.handpoint.com/direct/';

// Setup PHP session as use it to store data between 3DS steps
if (isset($_GET['sid'])) {
session_id($_GET['sid']);
}

session_start();
// Compose current page URL (removing any sid and acs parameters)
$pageUrl = ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https://' : 'http://'). $_SERVER['SERVER_NAME']. ($_SERVER['SERVER_PORT'] != '80' ? ':' . $_SERVER['SERVER_PORT'] : ''). preg_replace('/(sid=[^&]+&?)|(acs=1&?)/', '', $_SERVER['REQUEST_URI']);

// Add back the correct sid parameter (used as session cookie may not be passed when the page is redirected from an IFRAME)
$pageUrl .= (strpos($pageUrl, '?') === false ? '?' : '&') . 'sid=' . urlencode(session_id());

// If ACS response into the IFRAME then redirect back to parent window
if (!empty($_GET['acs'])) {
echo silentPost($pageUrl, array('threeDSResponse' => $_POST), '_parent');
exit();
}

if (!isset($_POST['threeDSResponse'])) {
// Initial request

// Gather browser info - can be done at any time prior to the checkout
if (!isset($_POST['browserInfo'])) {
echo Gateway::collectBrowserInfo();
exit();
}

// Direct Request
$req = array(
'merchantID' => 155928,
'action' => 'SALE',
'type' => 1,
'currencyCode' => 826,
'countryCode' => 826,
'amount' => 2101,
'cardNumber' => '5573471234567898',
//An expiry month of 12 (December) will simulate the non frictionless flow and a challenge will appear to the cardholder.
'cardExpiryMonth' => 12,
'cardExpiryYear' => 25,
'cardCVV' => '159',
'customerName' => 'Test Customer',
'customerEmail' => 'example@example.com',
'customerAddress' => 'Merevale Avenue Leicester',
'customerPostCode' => 'LE10 2BU',
'orderRef' => 'Test purchase',

// The following fields are mandatory for 3DS v2
'remoteAddress' => $_SERVER['REMOTE_ADDR'],
'threeDSRedirectURL' => $pageUrl . '&acs=1',

// The following field allows options to be passed for 3DS v2
// and the values here are for demonstration purposes only
'threeDSOptions' => array(
'paymentAccountAge' => '20220601', //Date that the payment account was enrolled in the cardholder's account with the 3DS Requestor.
//Accepted date format is YYYYMMDD.

'paymentAccountAgeIndicator' => '05', //Indicates the length of time that the payment account was enrolled in the cardholder's account
//with the 3DS Requestor. Possible values are:
//01 – No account (guest check-out)
//02 – Created during this transaction
//03 – Less than 30 days
//04 – 30-60 days
//05 – More than 60 days
),
);

// Add the browser info as it is mandatory for 3DS v2
$req += $_POST['browserInfo'];

} else {

// 3DS continuation request
$req = array (
// The following field are only required for tbe benefit of the SDK
'merchantID' => '155928',
'action' => 'SALE',

// The following field must be passed to continue the 3DS request
'threeDSRef' => $_SESSION['threeDSRef'],
'threeDSResponse' => $_POST['threeDSResponse'],
);

}

try {
$res = Gateway::directRequest($req);
} catch (\Exception $e) {

// You should exit gracefully
die('Sorry, the request could not be sent: ' . $e);
}

print $res['responseCode'];
// Check the response code
if ($res['responseCode'] === Gateway::RC_3DS_AUTHENTICATION_REQUIRED) {
// Send request to the ACS server displaying response in an IFRAME

// Render an IFRAME to show the ACS challenge (hidden for fingerprint method)
$style = (isset($res['threeDSRequest']['threeDSMethodData']) ? 'display: none;' : '');
echo "<iframe name=\"threeds_acs\" style=\"height:420px; width:420px; {$style}\"></iframe>\n";

// Silently POST the 3DS request to the ACS in the IFRAME
echo silentPost($res['threeDSURL'], $res['threeDSRequest'], 'threeds_acs');

// Remember the threeDSRef as need it when the ACS responds
$_SESSION['threeDSRef'] = $res['threeDSRef'];

} else if ($res['responseCode'] === Gateway::RC_SUCCESS) {

echo "<p>Thank you for your payment.</p>";
} else {
echo "<p>Failed to take payment: " . htmlentities($res['responseMessage']) . "</p>";
}


// Render HTML to silently POST data to URL in target brower window
function silentPost($url = '?', array $post = null, $target = '_self') {
$url = htmlentities($url);
$target = htmlentities($target);
$fields = '';


if ($post) {
foreach ($post as $name => $value) {
$fields .= Gateway::fieldToHtml($name, $value);
}
}

$ret = "<form id=\"silentPost\" action=\"{$url}\" method=\"post\" target=\"{$target}\">
{$fields}
<noscript><input type=\"submit\" value=\"Continue\"></noscript
</form>

<script>
window.setTimeout('document.forms.silentPost.submit()', 0);
</script>
";

return $ret;
}

?>

VERIFY

The following example PHP code shows how to send a VERIFY (amount £0,00) transaction with support for 3-D Secure using the Gateway library:

info

An expiry month of 12 (December) will simulate the non frictionless flow and a challenge will appear to the cardholder.

<?PHP

require('gateway.php');
use \P3\SDK\Gateway;

// Merchant signature key
Gateway::$merchantSecret = '3obzOxdqw6e1u';

// Handpoint Gateway URL
Gateway::$directUrl = 'https://commerce-api.handpoint.com/direct/';

// Setup PHP session as use it to store data between 3DS steps
if (isset($_GET['sid'])) {
session_id($_GET['sid']);
}

session_start();
// Compose current page URL (removing any sid and acs parameters)
$pageUrl = ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https://' : 'http://'). $_SERVER['SERVER_NAME']. ($_SERVER['SERVER_PORT'] != '80' ? ':' . $_SERVER['SERVER_PORT'] : ''). preg_replace('/(sid=[^&]+&?)|(acs=1&?)/', '', $_SERVER['REQUEST_URI']);

// Add back the correct sid parameter (used as session cookie may not be passed when the page is redirected from an IFRAME)
$pageUrl .= (strpos($pageUrl, '?') === false ? '?' : '&') . 'sid=' . urlencode(session_id());

// If ACS response into the IFRAME then redirect back to parent window
if (!empty($_GET['acs'])) {
echo silentPost($pageUrl, array('threeDSResponse' => $_POST), '_parent');
exit();
}

if (!isset($_POST['threeDSResponse'])) {
// Initial request

// Gather browser info - can be done at any time prior to the checkout
if (!isset($_POST['browserInfo'])) {
echo Gateway::collectBrowserInfo();
exit();
}

// Direct Request
$req = array(
'merchantID' => 155928,
'action' => 'VERIFY',
'type' => 1,
'currencyCode' => 826,
'countryCode' => 826,
'amount' => 0,
'cardNumber' => '5573471234567898',
//An expiry month of 12 (December) will simulate the non frictionless flow and a challenge will appear to the cardholder.
'cardExpiryMonth' => 12,
'cardExpiryYear' => 25,
'cardCVV' => '159',
'customerName' => 'Test Customer',
'customerEmail' => 'example@example.com',
'customerAddress' => 'Merevale Avenue Leicester',
'customerPostCode' => 'LE10 2BU',
'orderRef' => 'Test purchase',

// The following fields are mandatory for 3DS v2
'remoteAddress' => $_SERVER['REMOTE_ADDR'],
'threeDSRedirectURL' => $pageUrl . '&acs=1',

// The following field allows options to be passed for 3DS v2
// and the values here are for demonstration purposes only
'threeDSOptions' => array(
'paymentAccountAge' => '20220601',
'paymentAccountAgeIndicator' => '05',
),
);

// Add the browser info as it is mandatory for 3DS v2
$req += $_POST['browserInfo'];

} else {

$req = array (
// The following field are only required for tbe benefit of the SDK
'merchantID' => '155928',
'action' => 'VERIFY',
'threeDSRef' => $_SESSION['threeDSRef'],
'threeDSResponse' => $_POST['threeDSResponse'],
);

}

try {
$res = Gateway::directRequest($req);
} catch (\Exception $e) {

// You should exit gracefully
die('Sorry, the request could not be sent: ' . $e);
}

print $res['responseCode'];
// Check the response code
if ($res['responseCode'] === Gateway::RC_3DS_AUTHENTICATION_REQUIRED) {
// Send request to the ACS server displaying response in an IFRAME

// Render an IFRAME to show the ACS challenge (hidden for fingerprint method)
$style = (isset($res['threeDSRequest']['threeDSMethodData']) ? 'display: none;' : '');
echo "<iframe name=\"threeds_acs\" style=\"height:420px; width:420px; {$style}\"></iframe>\n";

// Silently POST the 3DS request to the ACS in the IFRAME
echo silentPost($res['threeDSURL'], $res['threeDSRequest'], 'threeds_acs');



// Remember the threeDSRef as need it when the ACS responds
$_SESSION['threeDSRef'] = $res['threeDSRef'];

} else if ($res['responseCode'] === Gateway::RC_SUCCESS) {

echo "<p>Verify done succesfully.</p>";
}
else {
echo "<p>Failed to Verify: " . htmlentities($res['responseMessage']) . "</p>";
}

// Render HTML to silently POST data to URL in target brower window
function silentPost($url = '?', array $post = null, $target = '_self') {
$url = htmlentities($url);
$target = htmlentities($target);
$fields = '';


if ($post) {
foreach ($post as $name => $value) {
$fields .= Gateway::fieldToHtml($name, $value);
}
}

$ret = "
<form id=\"silentPost\" action=\"{$url}\" method=\"post\" target=\"{$target}\">
{$fields}
<noscript><input type=\"submit\" value=\"Continue\"></noscript
</form>
<script>
window.setTimeout('document.forms.silentPost.submit()', 0);
</script>
";

return $ret;
}

?>

PREAUTH

The following example PHP code shows how to do a PREAUTH (amount £1,00) transaction with support for 3-D Secure using the Gateway library:

info

An expiry month of 12 (December) will simulate the non frictionless flow and a challenge will appear to the cardholder.

<?PHP

require('gateway.php');
use \P3\SDK\Gateway;

// Merchant signature key
Gateway::$merchantSecret = '3obzOxdqw6e1u';

// Handpoint Gateway URL
Gateway::$directUrl = 'https://commerce-api.handpoint.com/direct/';

// Setup PHP session as use it to store data between 3DS steps
if (isset($_GET['sid'])) {
session_id($_GET['sid']);
}

session_start();
// Compose current page URL (removing any sid and acs parameters)
$pageUrl = ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https://' : 'http://'). $_SERVER['SERVER_NAME']. ($_SERVER['SERVER_PORT'] != '80' ? ':' . $_SERVER['SERVER_PORT'] : ''). preg_replace('/(sid=[^&]+&?)|(acs=1&?)/', '', $_SERVER['REQUEST_URI']);

// Add back the correct sid parameter (used as session cookie may not be passed when the page is redirected from an IFRAME)
$pageUrl .= (strpos($pageUrl, '?') === false ? '?' : '&') . 'sid=' . urlencode(session_id());

// If ACS response into the IFRAME then redirect back to parent window
if (!empty($_GET['acs'])) {
echo silentPost($pageUrl, array('threeDSResponse' => $_POST), '_parent');
exit();
}

if (!isset($_POST['threeDSResponse'])) {
// Initial request

// Gather browser info - can be done at any time prior to the checkout
if (!isset($_POST['browserInfo'])) {
echo Gateway::collectBrowserInfo();
exit();
}

// Direct Request
$req = array(
'merchantID' => 155928,
'action' => 'PREAUTH',
'type' => 1,
'currencyCode' => 826,
'countryCode' => 826,
'amount' => 100,
'cardNumber' => '5573471234567898',
//An expiry month of 12 (December) will simulate the non frictionless flow and a challenge will appear to the cardholder.
'cardExpiryMonth' => 12,
'cardExpiryYear' => 24,
'cardCVV' => '159',
'customerName' => 'Test Customer',
'customerEmail' => 'example@example.com',
'customerAddress' => 'Merevale Avenue Leicester',
'customerPostCode' => 'LE10 2BU',
'orderRef' => 'Test purchase',

// The following fields are mandatory for 3DS v2
'remoteAddress' => $_SERVER['REMOTE_ADDR'],
'threeDSRedirectURL' => $pageUrl . '&acs=1',

// The following field allows options to be passed for 3DS v2
// and the values here are for demonstration purposes only
'threeDSOptions' => array(
'paymentAccountAge' => '20220601',
'paymentAccountAgeIndicator' => '05',
),
);

// Add the browser info as it is mandatory for 3DS v2
$req += $_POST['browserInfo'];

} else {

$req = array (
// The following field are only required for tbe benefit of the SDK
'merchantID' => '155928',
'action' => 'PREAUTH',

// The following field must be passed to continue the 3DS request
'threeDSRef' => $_SESSION['threeDSRef'],
'threeDSResponse' => $_POST['threeDSResponse'],
);

}

try {
$res = Gateway::directRequest($req);
} catch (\Exception $e) {

// You should exit gracefully
die('Sorry, the request could not be sent: ' . $e);
}

print $res['responseCode'];
// Check the response code
if ($res['responseCode'] === Gateway::RC_3DS_AUTHENTICATION_REQUIRED) {
// Send request to the ACS server displaying response in an IFRAME

// Render an IFRAME to show the ACS challenge (hidden for fingerprint method)
$style = (isset($res['threeDSRequest']['threeDSMethodData']) ? 'display: none;' : '');
echo "<iframe name=\"threeds_acs\" style=\"height:420px; width:420px; {$style}\"></iframe>\n";

// Silently POST the 3DS request to the ACS in the IFRAME
echo silentPost($res['threeDSURL'], $res['threeDSRequest'], 'threeds_acs');



// Remember the threeDSRef as need it when the ACS responds
$_SESSION['threeDSRef'] = $res['threeDSRef'];

} else if ($res['responseCode'] === Gateway::RC_SUCCESS) {

echo "<p>Thank you for your Preauth.</p>";
}
else {
echo "<p>Failed to take Preauth: " . htmlentities($res['responseMessage']) . "</p>";
}

// Render HTML to silently POST data to URL in target brower window
function silentPost($url = '?', array $post = null, $target = '_self') {
$url = htmlentities($url);
$target = htmlentities($target);
$fields = '';


if ($post) {
foreach ($post as $name => $value) {
$fields .= Gateway::fieldToHtml($name, $value);
}
}

$ret = "
<form id=\"silentPost\" action=\"{$url}\" method=\"post\" target=\"{$target}\">
{$fields}
<noscript><input type=\"submit\" value=\"Continue\"></noscript
</form>
<script>
window.setTimeout('document.forms.silentPost.submit()', 0);
</script>
";

return $ret;
}

?>

REFUND_SALE

The following example PHP code shows how to do a REFUND_SALE transaction, the previous SALE transaction should be specified using the xref field, using the Gateway library.

Partial refunds are allowed by specifying the amount to refund. Any amount must not be greater than the original received amount minus any already refunded amount. Multiple partial refunds may be made while there is still a portion of the originally received amount un-refunded.

It can only be performed on transactions that have been successfully settled

<?PHP

require('gateway.php');
use \P3\SDK\Gateway;

// Merchant signature key
Gateway::$merchantSecret = '3obzOxdqw6e1u';

// Handpoint Gateway URL
Gateway::$directUrl = 'https://commerce-api.handpoint.com/direct/';


session_start();
// Compose current page URL (removing any sid and acs parameters)
$pageUrl = ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https://' : 'http://') . $_SERVER['SERVER_NAME'] . ($_SERVER['SERVER_PORT'] != '80' ? ':' . $_SERVER['SERVER_PORT'] : '') . preg_replace('/(sid=[^&]+&?)|(acs=1&?)/', '', $_SERVER['REQUEST_URI']);

// Add back the correct sid parameter (used as session cookie may not be passed when the page is redirected from an IFRAME)
$pageUrl .= (strpos($pageUrl, '?') === false ? '?' : '&') . 'sid=' . urlencode(session_id());

// Direct Request
$req = array(
'merchantID' => 155928,
'action' => 'REFUND_SALE',
'type' => 1,
'currencyCode' => 826,
'countryCode' => 826,
'customerName' => 'Test Customer',
'orderRef' => 'Test Refund',

//XREF from previously transaction (Sale)
'xref' => '11223344556677889911223',
);

try {
//echo var_dump ($req);
$res = Gateway::directRequest($req);
} catch (\Exception $e) {

// You should exit gracefully
die('Sorry, the request could not be sent: ' . $e);
}

print $res['responseCode'];
// Check the response code
if ($res['responseCode'] === Gateway::RC_SUCCESS) {

echo "<p>Refund done successfully.</p>";

} else {
echo "<p>Failed to take refund: " . htmlentities($res['responseMessage']) . "</p>";
}

?>

REFUND

The following example PHP code shows how to do a REFUND (amount £22,00) transaction using the Gateway library:

This is an independent refund and need not be related to any previous SALE. The amount is therefore not limited by any original received amount.

<?PHP

require('gateway.php');
use \P3\SDK\Gateway;

// Merchant signature key
Gateway::$merchantSecret = '3obzOxdqw6e1u';

// Handpoint Gateway URL
Gateway::$directUrl = 'https://commerce-api.handpoint.com/direct/';


session_start();
// Compose current page URL (removing any sid and acs parameters)
$pageUrl = ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https://' : 'http://') . $_SERVER['SERVER_NAME'] . ($_SERVER['SERVER_PORT'] != '80' ? ':' . $_SERVER['SERVER_PORT'] : '') . preg_replace('/(sid=[^&]+&?)|(acs=1&?)/', '', $_SERVER['REQUEST_URI']);

// Add back the correct sid parameter (used as session cookie may not be passed when the page is redirected from an IFRAME)
$pageUrl .= (strpos($pageUrl, '?') === false ? '?' : '&') . 'sid=' . urlencode(session_id());

// Direct Request
$req = array(
'merchantID' => 155928,
'action' => 'REFUND',
'type' => 1,
'currencyCode' => 826,
'countryCode' => 826,
'amount' => '2200',
'cardNumber' => '5573471234567898',
'cardExpiryMonth' => 12,
'cardExpiryYear' => 25,
'cardCVV' => '159',
'customerName' => 'Test Customer',
'orderRef' => 'Test Refund',
'customerAddress' => 'Merevale Avenue Leicester',
'customerPostCode' => 'LE10 2BU',
);

try {
//echo var_dump ($req);
$res = Gateway::directRequest($req);
} catch (\Exception $e) {

// You should exit gracefully
die('Sorry, the request could not be sent: ' . $e);
}

print $res['responseCode'];
// Check the response code
if ($res['responseCode'] === Gateway::RC_SUCCESS) {

echo "<p>Refund done successfully.</p>";

} else {
echo "<p>Failed to take refund: " . htmlentities($res['responseMessage']) . "</p>";
}

?>

CAPTURE

The following example PHP code shows how to do a CAPTURE using the Gateway library.

This will capture an existing transaction, identified using the xref request field, making it available for settlement at the next available opportunity. It can only be performed on transactions that have been authorised but not yet captured. An amount to capture may be specified but must not exceed the original amount authorised.

NOTE: The original transaction must have been submitted with a captureDelay value that prevented immediate capture and settlement leaving the transaction in an authorised but un-captured state.

<?PHP

require('gateway.php');
use \P3\SDK\Gateway;

// Merchant signature key
Gateway::$merchantSecret = '3obzOxdqw6e1u';

// Handpoint Gateway URL
Gateway::$directUrl = 'https://commerce-api.handpoint.com/direct/';

session_start();
// Compose current page URL (removing any sid and acs parameters)
$pageUrl = ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https://' : 'http://') . $_SERVER['SERVER_NAME'] . ($_SERVER['SERVER_PORT'] != '80' ? ':' . $_SERVER['SERVER_PORT'] : '') . preg_replace('/(sid=[^&]+&?)|(acs=1&?)/', '', $_SERVER['REQUEST_URI']);

// Add back the correct sid parameter (used as session cookie may not be passed when the page is redirected from an IFRAME)
$pageUrl .= (strpos($pageUrl, '?') === false ? '?' : '&') . 'sid=' . urlencode(session_id());

// Direct Request
$req = array(
'merchantID' => 155928,
'action' => 'CAPTURE',
'xref' => '11223344556677889911223',
);

try {
//echo var_dump ($req);
$res = Gateway::directRequest($req);
} catch (\Exception $e) {

// You should exit gracefully
die('Sorry, the request could not be sent: ' . $e);
}

print $res['responseCode'];
// Check the response code
if ($res['responseCode'] === Gateway::RC_SUCCESS) {

echo "<p>Capture done successfully.</p>";

} else {
echo "<p>Failed to Capture: " . htmlentities($res['responseMessage']) . "</p>";
}

?>

CANCEL

The following example PHP code shows how to do a CANCEL using the Gateway library.

This will cancel an existing transaction, identified using the xref request field, preventing it from being settled. It can only be performed on transactions, which have been authorised but not yet settled, and it is not reversible

<?PHP

require('gateway.php');
use \P3\SDK\Gateway;

// Merchant signature key
Gateway::$merchantSecret = '3obzOxdqw6e1u';

// Handpoint Gateway URL
Gateway::$directUrl = 'https://commerce-api.handpoint.com/direct/';


session_start();
// Compose current page URL (removing any sid and acs parameters)
$pageUrl = ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https://' : 'http://') . $_SERVER['SERVER_NAME'] . ($_SERVER['SERVER_PORT'] != '80' ? ':' . $_SERVER['SERVER_PORT'] : '') . preg_replace('/(sid=[^&]+&?)|(acs=1&?)/', '', $_SERVER['REQUEST_URI']);

// Add back the correct sid parameter (used as session cookie may not be passed when the page is redirected from an IFRAME)
$pageUrl .= (strpos($pageUrl, '?') === false ? '?' : '&') . 'sid=' . urlencode(session_id());

// Direct Request
$req = array(
'merchantID' => 155928,
'action' => 'CANCEL',
'xref' => '11223344556677889911223',
);

try {
//echo var_dump ($req);
$res = Gateway::directRequest($req);
} catch (\Exception $e) {

// You should exit gracefully
die('Sorry, the request could not be sent: ' . $e);
}

print $res['responseCode'];
// Check the response code
if ($res['responseCode'] === Gateway::RC_SUCCESS) {

echo "<p>Cancel done successfully.</p>";

} else {
echo "<p>Failed to Cancel: " . htmlentities($res['responseMessage']) . "</p>";
}

?>

QUERY

The following example PHP code shows how to do a QUERY using the Gateway library.

This will query an existing transaction, identified using the xref request field, returning the original response. This is a simple transaction lookup action.

<?PHP

require('gateway.php');
use \P3\SDK\Gateway;

// Merchant signature key
Gateway::$merchantSecret = '3obzOxdqw6e1u';

// Handpoint Gateway URL
Gateway::$directUrl = 'https://commerce-api.handpoint.com/direct/';

session_start();
// Compose current page URL (removing any sid and acs parameters)
$pageUrl = ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https://' : 'http://'). $_SERVER['SERVER_NAME']. ($_SERVER['SERVER_PORT'] != '80' ? ':' . $_SERVER['SERVER_PORT'] : ''). preg_replace('/(sid=[^&]+&?)|(acs=1&?)/', '', $_SERVER['REQUEST_URI']);

// Add back the correct sid parameter (used as session cookie may not be passed when the page is redirected from an IFRAME)
$pageUrl .= (strpos($pageUrl, '?') === false ? '?' : '&') . 'sid=' . urlencode(session_id());


// Direct Request
$req = array (
// The following field are only required for tbe benefit of the SDK
'merchantID' => '155928',
'action' => 'QUERY',
'xref' => '11223344556677889911223', //That field is mandatory for QUERY transaction.
);

try {
$res = Gateway::directRequest($req);
} catch (\Exception $e) {

// You should exit gracefully
die('Sorry, the request could not be sent: ' . $e);
}

// Check the response code
if ($res['responseCode'] === Gateway::RC_SUCCESS) {

echo "QUERY transaction:";
echo "<br>";
echo "ResponseStatus:"." ".$res['responseStatus'];
echo "<br>";
echo "ResponseMessage:"." ".$res['responseMessage'];
echo "<br>";
echo "Action:"." ".$res['action'];
echo "<br>";
echo "Amount:"." ".$res['amount'] ;
echo "<br>";
echo "XREF:"." ". $res['xref'];
echo "<br>";
echo "TransactionID:"." ".$res['transactionID'];
echo "<br>";
echo "State:"." ".$res['state'];
echo "<br>";
echo "Timestamp:"." ".$res['timestamp'];
echo "<br>";
echo "CardNumberMask:"." ".$res['cardNumberMask'];
echo "<br>";
echo "CardTypeCode:"." ".$res['cardTypeCode'];
echo "<br>";
echo "CardType:"." ".$res['cardType'];
echo "<br>";
echo "CardSchemeCode:"." ".$res['cardSchemeCode'];
echo "<br>";
echo "CardScheme:"." ".$res['cardScheme'];
echo "<br>";
echo "CardIssuer:"." ".$res['cardIssuer'];

} else {
echo "<p>Failed to take payment: " . htmlentities($res['responseMessage']) . "</p>";
}

?>

3DS Example (PHP Code)

The following example shows the complete 3D Secure process. When executing this code, the different phases of the 3DS process are displayed on the screen.

It allows you to choose between 3 different cards (Visa, Mastercard and AMEX) and allows you to select the expiration month of the selected card.

Each month represents a different authentication status returned by the Directory Server (for frictionless flow simulation). Here you can check the meaning of each month.

<?php

const MERCHANT_SECRET_KEY = '3obzOxdqw6e1u';
const MERCHANT_ID = '155928';
const GATEWAY_URL = 'https://commerce-api.handpoint.com/direct/';

// Route
if (isset($_GET['menu'])) {
menu();
} elseif (isset($_GET['run'])) {
run();
} elseif (isset($_GET['3dscallback'])) {
threeDSCallback();
} else {
menu();
}


// Select test card menu.
function menu()
{

$testCards = [
[
'card_name' => 'Visa Credit',
'address' => 'Flat 6 Primrose Rise 347 Lavender Road Northampton',
'post_code' => 'NN17 8YG',
'card_number' => '4929421234600821',
'card_cvv' => '356',
],
[
'card_name' => 'Mastercard Credit',
'address' => '25 The Larches Narborough Leicester',
'post_code' => 'LE10 2RT',
'card_number' => '5301250070000191',
'card_cvv' => '419',
], [
'card_name' => 'American Express (Amex)',
'address' => 'The Hunts Way Southampton',
'post_code' => 'SO18 1GW',
'card_number' => '374245455400001',
'card_cvv' => '4887',
],
];

$html = '<p>Select test card:</p><table class="table"><thead>';

foreach ($testCards as $testCard) {

$html .= <<<HTML
<tr>
<td>{$testCard['card_name']}</td>
<td>{$testCard['card_number']}</td>
<td>{$testCard['address']}</td>
<td>{$testCard['post_code']}</td>
<td> <form action="?run" method="post">
Expiry month
<select class="form-select" aria-label="Default select example" name="cardExpiryMonth">
<option selected="selected" value="12">12</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
<option value="7">7</option>
<option value="8">8</option>
<option value="9">9</option>
<option value="10">10</option>
<option value="11">11</option>
<option value="12">12</option>
</select>
<input type="hidden" name="cardNumber" value="{$testCard['card_number']}">
<input type="hidden" name="cardCVV" value="{$testCard['card_cvv']}">
<input type="hidden" name="cardAddress" value="{$testCard['address']}">
<input type="hidden" name="cardPostCode" value="{$testCard['post_code']}">

<td><button type="submit" class="btn btn-primary btn-small">Submit</button></td>
</form></td>
</tr>
HTML;
}

$html .= <<<HTML
</tbody>
</table>
HTML;

echo renderPage('3DSv2 Demo', $html, 'Handpoint');
}

function run()
{

$threeDSRedirectURL = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https://" : "http://") . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];

$request = array(
'action' => 'SALE',
'amount' => '150',
'cardCVV' => (isset($_POST['cardCVV']) ? $_POST['cardCVV'] : '083'),
'cardExpiryYear' => (isset($_POST['cardExpiryYear']) ? $_POST['cardExpiryYear'] : '23'),
'cardExpiryMonth' => (isset($_POST['cardExpiryMonth']) ? $_POST['cardExpiryMonth'] : '12'),
'cardNumber' => (isset($_POST['cardNumber']) ? $_POST['cardNumber'] : '4929421234600821'),
'countryCode' => '826',
'currencyCode' => '826',
'customerAddress' => (isset($_POST['cardAddress']) ? $_POST['cardAddress'] : '16'),
'customerEmail' => 'email@exampledomainnamehere.com',
'customerName' => 'MrMrs Tester',
'customerPostCode' => (isset($_POST['cardPostCode']) ? $_POST['cardPostCode'] : '55'),
'merchantID' => MERCHANT_ID,
'type' => '1',
'orderRef' => 'Test',
'remoteAddress' => $_SERVER['REMOTE_ADDR'],
'threeDSRedirectURL' => "{$threeDSRedirectURL}?3dscallback",
'deviceChannel' => 'browser',
'deviceIdentity' => (isset($_SERVER['HTTP_USER_AGENT']) ? htmlentities($_SERVER['HTTP_USER_AGENT']) : null),
'deviceTimeZone' => '0',
'deviceScreenResolution' => '1x1x1',
'deviceAcceptContent' => (isset($_SERVER['HTTP_ACCEPT']) ? htmlentities($_SERVER['HTTP_ACCEPT']) : '*/*'),
'deviceAcceptEncoding' => (isset($_SERVER['HTTP_ACCEPT_ENCODING']) ? htmlentities($_SERVER['HTTP_ACCEPT_ENCODING']) : '*'),
'deviceAcceptLanguage' => (isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) ? htmlentities($_SERVER['HTTP_ACCEPT_LANGUAGE']) : 'en-gb;q=0.001'),
'deviceAcceptCharset' => (isset($_SERVER['HTTP_ACCEPT_CHARSET']) ? htmlentities($_SERVER['HTTP_ACCEPT_CHARSET']) : null),

);

$request['signature'] = createSignature($request, MERCHANT_SECRET_KEY);

$response = sendRequest($request, GATEWAY_URL);

$html = <<<HTML
<div class="card">
<div class="card-header">
<h5> Request to gateway</h5>
</div>
<div class="card-body">
HTML;


$html .= '<pre>' . print_r($request, true) . '</pre>';

$ret = http_build_query($request, '', '&');
// Normalise all line endings (CRNL|NLCR|NL|CR) to just NL (%0A)
$ret = str_replace(array('%0D%0A', '%0A%0D', '%0D'), '%0A', $ret);

$html .= '<h5>URL Encoded</h5>';
$html .= '</p>' . $ret . '</p>';
$html .= '</div></div>';
$html .= <<<HTML
<div class="card-header" style="margin-top: 20px;">
<h5>Response from gateway</h5>
</div>
<div class="card-body">
HTML;


$html .= '<pre>' . print_r($response, true) . '</pre>';

if ($response['responseCode'] == 65802) {

$html .= "<p>Your transaction requires 3D Secure Authentication</p>";

// Store the threeDSRef in a cookie for reuse. (this is just one way of storeing it)
setcookie('threeDSRef', $response['threeDSRef'], time() + 1500);

$ref = $response['threeDSRef'];

$html .= "<p>The threeDSRef now needs to stored be on the merchant side. In this example it's being stored to a cookie so it can be retreived after 3DS has called back</p>";

$html .= "<p>ThreeDS Ref being stored : {$ref}</p>";

$threeDSUrl = $response['threeDSURL'];

$html .= "<p>Next a POST request needs to be sent to the 3DS URL provided in the threeDSURL field in the response which is {$threeDSUrl} this post request
needs to contain the fields provided in the gateways response threeDSRequest field. These fields are ";

// For each of the fields in threeDSRequest output a hidden input field with it's key/value
foreach ($response['threeDSRequest'] as $key => $value) {
$html .= "<p>Name : {$key} with a value of {$value} </p>";
}

$html .= "<p>Along with these fields the threeDSRef from the response is also sent. </p></p>";

// Start of HTML form with URL
$html .= "<form action=\"" . htmlentities($response['threeDSURL']) . "\"method=\"post\">";

// Add threeDSRef from the gateway response
$html .= '<input type="hidden" name="threeDSRef" value="' . $response['threeDSRef'] . '">';

// For each of the fields in threeDSRequest output a hidden input field with it's key/value
foreach ($response['threeDSRequest'] as $key => $value) {
$html .= '<input type="hidden" name="' . $key . '" value="' . $value . '">';
}

$html .= '<pre><code>&lt;form action="https://acs.3ds-pit.com/?method" method="post"&gt;
&lt;input type="hidden" name="threeDSRef" value="UDNLRVk6dHJhbnNhY3Rpb25JRD0xNTAyNzk0MjgmbWVyY2hhbnRJRD0xMDA4NTYmX19saWZlX189MTY0MzI5Nzk5Mg=="&gt;
&lt;input type="hidden" name="threeDSMethodData" value="eyJ0aHJlZURTTWV0aG9kTm90aWZpY2F0aW9uVVJMIjoiaHR0cDovLzEyNy4wLjAuMTo4MDgwLzNkc3YyLWV4YW1wbGUucGhwPzNkc2NhbGxiYWNrPSZ0aHJlZURTQWNzUmVzcG9uc2U9bWV0aG9kIiwidGhyZWVEU1NlcnZlclRyYW5zSUQiOiIxNGE2YTYyZS0yZjRjLTQxNjYtYWYwYi1jNTJmN2M0ZGFjMjUifQ"&gt;&lt;pre&gt;&lt;code&gt;&lt;input type="hidden" name="threeDSRef" value="UDNLRVk6dHJhbnNhY3Rpb25JRD0xNTAyNzkzNzkmbWVyY2hhbnRJRD0xMDA4NTYmX19saWZlX189MTY0MzI5Nzk2MA=="&gt;&lt;input type="hidden" name="threeDSMethodData" value="eyJ0aHJlZURTTWV0aG9kTm90aWZpY2F0aW9uVVJMIjoiaHR0cDovLzEyNy4wLjAuMTo4MDgwLzNkc3YyLWV4YW1wbGUucGhwPzNkc2NhbGxiYWNrPSZ0aHJlZURTQWNzUmVzcG9uc2U9bWV0aG9kIiwidGhyZWVEU1NlcnZlclRyYW5zSUQiOiJhMzczOTkxMy1kMzdlLTQyZjMtYmFhNC04NjNmOTgwMzMyYzEifQ"&gt;&lt;pre&gt;&lt;code&gt;%3Cform+action%3D%22https%3A%2F%2Facs.3ds-pit.com%2F%3Fmethod%22+method%3D%22post%22%3E%0D%0A%3Cinput+type%3D%22hidden%22+name%3D%22threeDSRef%22+value%3D%22UDNLRVk6dHJhbnNhY3Rpb25JRD0xNTAyNzkwOTEmbWVyY2hhbnRJRD0xMDA4NTYmX19saWZlX189MTY0MzI5Nzc5MQ%3D%3D%22%3E%3Cinput+type%3D%22hidden%22+name%3D%22threeDSMethodData%22+value%3D%22eyJ0aHJlZURTTWV0aG9kTm90aWZpY2F0aW9uVVJMIjoiaHR0cDovLzEyNy4wLjAuMTo4MDgwLzNkc3YyLWV4YW1wbGUucGhwPzNkc2NhbGxiYWNrPSZ0aHJlZURTQWNzUmVzcG9uc2U9bWV0aG9kIiwidGhyZWVEU1NlcnZlclRyYW5zSUQiOiI2MWUzNDJmNC1hZDg2LTQ2YzYtYmMxYy1iYzFiZjIwYWU1NzQifQ%22%3E%0D%0A%3Cinput+type%3D%22submit%22+value%3D%22Continue%22%3E%0D%0A%3C%2Fform%3E&lt;/code&gt;&lt;/pre&gt;&lt;input type="submit" value="Continue"&gt;
&lt;/form&gt;</pre></code>';
// End of html form with submit button.

$html .= "<input type=\"submit\" value=\"Continue\">
</form>";
}


$html .= '</div></div>';

echo renderPage('3DSv2 Test', $html, 'Initial request to gateway');
}

function threeDSCallback()
{

//ACS Response
$html = <<< HTML
<div class="card">
<div class="card-header">
<h5>Response from ACS</h5>
</div>
<div class="card-body">
HTML;

$html .= '<pre>' . print_r($_POST, true) . '</pre>';

$threeDSRequest = array(
'threeDSRef' => $_COOKIE['threeDSRef'], // This is the threeDSref store in the cookie from the previous gateway response.
'threeDSResponse' => $_POST, // <-- Note here no fields are hard coded. Whatever is POSTED from 3DS is returned.
);

// Send the 3DS response back to the gateway and get the response.
$gatewayResponse = sendRequest($threeDSRequest, GATEWAY_URL);

// Store the new threeDSRef in the cookie again because it may change.
setcookie('threeDSRef', $gatewayResponse['threeDSRef'], time() + 1500);

$html .= '</div></div>';


$html .= <<< HTML
<div class="card" style="margin-top: 10px">
<div class="card-header">
<h5>Request to gateway</h5>
</div>
<div class="card-body">
HTML;


$html .= '<pre>' . print_r($threeDSRequest, true) . '</pre>';

$html .= '<h5>Url encoded</h5>';
$ret = http_build_query($threeDSRequest, '', '&');
// Normalise all line endings (CRNL|NLCR|NL|CR) to just NL (%0A)
$ret = str_replace(array('%0D%0A', '%0A%0D', '%0D'), '%0A', $ret);
$html .= $ret;

$html .= '</div></div>';


$html .= <<< HTML
<div class="card" style="margin-top: 10px; margin-bottom: 100px">
<div class="card-header">
<h5>Response from gateway</h5>
</div>
<div class="card-body">
HTML;

$html .= '<pre>' . print_r($gatewayResponse, true) . '</pre>';


if ($gatewayResponse['responseCode'] == 65802) {

$html .= "<p>Your transaction requires 3D Secure Authentication</p>";

// Store the threeDSRef in a cookie for reuse. (this is just one way of storeing it)
setcookie('threeDSRef', $gatewayResponse['threeDSRef'], time() + 500);

$ref = $gatewayResponse['threeDSRef'];

$html .= "<p>The threeDSRef now needs to be stored again on the merchant side.</p>";

$html .= "<label>Three DS Ref being stored : {$ref}</label>";

$threeDSUrl = $gatewayResponse['threeDSURL'];

$html .= "<p>Next a POST request needs to be sent to the 3DS URL provided in the threeDSURL field in the response which is {$threeDSUrl} this post request
needs to contain the fields provided in the gateways response threeDSRequest field. These fields are ";

// For each of the fields in threeDSRequest output a hidden input field with it's key/value
foreach ($gatewayResponse['threeDSRequest'] as $key => $value) {
$html .= "<p>Name : {$key} with a value of {$value}</p>";
}

// Start of HTML form with URL
$html .= "<form action=\"" . htmlentities($gatewayResponse['threeDSURL']) . "\"method=\"post\">";

// Add threeDSRef from the gateway response
$html .= '<input type="hidden" name="threeDSRef" value="' . $gatewayResponse['threeDSRef'] . '">';

// For each of the fields in threeDSRequest output a hidden input field with it's key/value
foreach ($gatewayResponse['threeDSRequest'] as $key => $value) {
$html .= '<input type="hidden" name="' . $key . '" value="' . $value . '">';
}

// End of html form with submit button.
$html .= "<input type=\"submit\" value=\"Continue\">
</form>";
} else {

$html .= 'Transaction Complete';
$html .= '<a href="?menu" class="btn btn-primary" role="button">Return to menu</a>';
}

$html .= '</div></div>';

echo renderPage('3DS Callback', $html, '3DS Callback');
}



function renderPage($title, $body, $jumotronText = null)
{
$html = <<< HTML
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<link rel="icon" href="/docs/4.0/assets/img/favicons/favicon.ico">

<title>{$title}</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css">
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js"></script>
</head>

<body>
<div class="jumbotron text-center">
<h1>{$jumotronText}</h1>
</div>

<main role="main" class="container">
{$body}
</main>
</body>
</html>
HTML;

return $html;
}



/**
* Send request
*
* @param Array $request
* @param String $gatewayURL
*
* @return Array $responseponse
*/
function sendRequest($request, $gatewayURL)
{
// Send request to the gateway

// Initiate and set curl options to post to the gateway
$ch = curl_init($gatewayURL);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($request));
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

// Send the request and parse the response
parse_str(curl_exec($ch), $response);

// Close the connection to the gateway
curl_close($ch);

return $response;
}



/**
* Sign request
*
* @param Array $data
* @param String $key
*
* @return String Hash
*/
function createSignature(array $data, $key)
{
// Sort by field name
ksort($data);

// Create the URL encoded signature string
$ret = http_build_query($data, '', '&');

// Normalise all line endings (CRNL|NLCR|NL|CR) to just NL (%0A)
$ret = str_replace(array('%0D%0A', '%0A%0D', '%0D'), '%0A', $ret);

// Hash the signature string and the key together
return hash('SHA512', $ret . $key);
}

Video showing the above code sample highlighting some of the most important things:

Note: In the case of the video a paymentToken is used. For a Direct integration, card details (Card Number, CVV, Expiry Date) are needed.

Gateway Wallet

Direct Integration creating a new Gateway Wallet

Provide card details IF no walletID is provided, if walletID is provided, then no card details can be present.

walletID value will be returned in the response.

<?PHP

require('gateway.php');

use \P3\SDK\Gateway;

// Merchant signature key
Gateway::$merchantSecret = '3obzOxdqw6e1u';

// Handpoint Gateway URL
Gateway::$directUrl = 'https://commerce-api.handpoint.com/direct/';

// Setup PHP session as use it to store data between 3DS steps
if (isset($_GET['sid'])) {
session_id($_GET['sid']);
}

session_start();
// Compose current page URL (removing any sid and acs parameters)
$pageUrl = ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https://' : 'http://'). $_SERVER['SERVER_NAME']. ($_SERVER['SERVER_PORT'] != '80' ? ':' . $_SERVER['SERVER_PORT'] : ''). preg_replace('/(sid=[^&]+&?)|(acs=1&?)/', '', $_SERVER['REQUEST_URI']);

// Add back the correct sid parameter (used as session cookie may not be passed when the page is redirected from an IFRAME)
$pageUrl .= (strpos($pageUrl, '?') === false ? '?' : '&') . 'sid=' . urlencode(session_id());

// If ACS response into the IFRAME then redirect back to parent window
if (!empty($_GET['acs'])) {
echo silentPost($pageUrl, array('threeDSResponse' => $_POST), '_parent');
exit();
}

if (!isset($_POST['threeDSResponse'])) {
// Initial request

// Gather browser info - can be done at any time prior to the checkout
if (!isset($_POST['browserInfo'])) {
echo Gateway::collectBrowserInfo();
exit();
}

// Direct Request

$req = array(
'merchantID' => 155928,
'action' => 'SALE',
'type' => 1,
'currencyCode' => 826,
'countryCode' => 826,
'amount' => 1999,
//Provide card details IF no walletID is provided, if walletID is provided, then no card details can be present.
'cardNumber' => '5573471234567898',
//An expiry month of 12 (December) will simulate the non frictionless flow and a challenge will appear to the cardholder.
'cardExpiryMonth' => 12,
'cardExpiryYear' => 24,
//CVV needs to be provided even for wallet.
'cardCVV' => '159',
'customerName' => 'Handpoint Test Customer',
'customerAddress' => 'Merevale Avenue Leicester',
'customerPostCode' => 'LE10 2BU',
'orderRef' => 'Test purchase',
'rtAgreementType' => 'cardonfile',
//enables wallet system
'walletEnabled' => 'Y',

//stores card in a wallet automatically if a transaction went through, wallet id is returned in callback.
'walletStore' => 'Y',

//Insert walletid below from previous transaction and remove card details (CVV needs to stay).
//Leave blank if no wallet exists yet. walletID value will be returned in the response.
'walletID' => '1437476',

// The following fields are mandatory for 3DS v2
'remoteAddress' => $_SERVER['REMOTE_ADDR'],
'threeDSRedirectURL' => $pageUrl . '&acs=1',

// The following field allows options to be passed for 3DS v2
// and the values here are for demonstration purposes only
'threeDSOptions' => array(
'paymentAccountAge' => '20220601',
'paymentAccountAgeIndicator' => '05',
),
);

// Add the browser info as it is mandatory for 3DS v2
$req += $_POST['browserInfo'];

} else {

$req = array (
// The following field are only required for tbe benefit of the SDK
'merchantID' => '155928',
'action' => 'SALE',
'threeDSRef' => $_SESSION['threeDSRef'],
'threeDSResponse' => $_POST['threeDSResponse'],
);

}

try {
$res = Gateway::directRequest($req);
} catch (\Exception $e) {

// You should exit gracefully
die('Sorry, the request could not be sent: ' . $e);
}

print $res['responseCode'];
// Check the response code
if ($res['responseCode'] === Gateway::RC_3DS_AUTHENTICATION_REQUIRED) {
// Send request to the ACS server displaying response in an IFRAME

// Render an IFRAME to show the ACS challenge (hidden for fingerprint method)
$style = (isset($res['threeDSRequest']['threeDSMethodData']) ? 'display: none;' : '');
echo "<iframe name=\"threeds_acs\" style=\"height:420px; width:420px; {$style}\"></iframe>\n";

// Silently POST the 3DS request to the ACS in the IFRAME
echo silentPost($res['threeDSURL'], $res['threeDSRequest'], 'threeds_acs');

// Remember the threeDSRef as need it when the ACS responds
$_SESSION['threeDSRef'] = $res['threeDSRef'];

} else if ($res['responseCode'] === Gateway::RC_SUCCESS) {
echo "<p>Thank you for your payment.</p>";
echo 'This is your walletID'.' '.'=>'.' '.$res['walletID'];
} else {
echo "<p>Failed to take payment: " . htmlentities($res['responseMessage']) . "</p>";
}

// Render HTML to silently POST data to URL in target brower window
function silentPost($url = '?', array $post = null, $target = '_self') {
$url = htmlentities($url);
$target = htmlentities($target);
$fields = '';


if ($post) {
foreach ($post as $name => $value) {
$fields .= Gateway::fieldToHtml($name, $value);
}
}

$ret = "
<form id=\"silentPost\" action=\"{$url}\" method=\"post\" target=\"{$target}\">
{$fields}
<noscript><input type=\"submit\" value=\"Continue\"></noscript
</form>
<script>
window.setTimeout('document.forms.silentPost.submit()', 0);
</script>
";

return $ret;
}

?>

Direct Integration using Gateway Wallet

Providing a walletIDwill allow you to use a previously used card. A walletID needs to be provided in the request.

The cardCVV of the stored card is 159.

<?PHP

require('gateway.php');

use \P3\SDK\Gateway;

// Merchant signature key
Gateway::$merchantSecret = '3obzOxdqw6e1u';

// Handpoint Gateway URL
Gateway::$directUrl = 'https://commerce-api.handpoint.com/direct/';

// Setup PHP session as use it to store data between 3DS steps
if (isset($_GET['sid'])) {
session_id($_GET['sid']);
}

session_start();
// Compose current page URL (removing any sid and acs parameters)
$pageUrl = ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https://' : 'http://'). $_SERVER['SERVER_NAME']. ($_SERVER['SERVER_PORT'] != '80' ? ':' . $_SERVER['SERVER_PORT'] : ''). preg_replace('/(sid=[^&]+&?)|(acs=1&?)/', '', $_SERVER['REQUEST_URI']);

// Add back the correct sid parameter (used as session cookie may not be passed when the page is redirected from an IFRAME)
$pageUrl .= (strpos($pageUrl, '?') === false ? '?' : '&') . 'sid=' . urlencode(session_id());

// If ACS response into the IFRAME then redirect back to parent window
if (!empty($_GET['acs'])) {
echo silentPost($pageUrl, array('threeDSResponse' => $_POST), '_parent');
exit();
}

if (!isset($_POST['threeDSResponse'])) {
// Initial request

// Gather browser info - can be done at any time prior to the checkout
if (!isset($_POST['browserInfo'])) {
echo Gateway::collectBrowserInfo();
exit();
}

// Direct Request

$req = array(
'merchantID' => 155928,
'action' => 'SALE',
'type' => 1,
'currencyCode' => 826,
'countryCode' => 826,
'amount' => 1999,

//CVV needs to be provided even for wallet.
'cardCVV' => '159',
'customerName' => 'Handpoint Test Customer',
'customerAddress' => 'Merevale Avenue Leicester',
'customerPostCode' => 'LE10 2BU',
'orderRef' => 'Test purchase',
'rtAgreementType' => 'cardonfile',
//enables wallet system
'walletEnabled' => 'Y',

//stores card in a wallet automatically if a transaction went through, wallet id is returned in callback.
'walletStore' => 'Y',

//Insert walletid below from previous transaction and remove card details (CVV needs to stay).
//Leave blank if no wallet exists yet. walletID value will be returned in the response.
'walletID' => '1437476',

// The following fields are mandatory for 3DS v2
'remoteAddress' => $_SERVER['REMOTE_ADDR'],
'threeDSRedirectURL' => $pageUrl . '&acs=1',

// The following field allows options to be passed for 3DS v2
// and the values here are for demonstration purposes only
'threeDSOptions' => array(
'paymentAccountAge' => '20220601',
'paymentAccountAgeIndicator' => '05',
),
);

// Add the browser info as it is mandatory for 3DS v2
$req += $_POST['browserInfo'];

} else {
$req = array (
// The following field are only required for tbe benefit of the SDK
'merchantID' => '155928',
'action' => 'SALE',
'threeDSRef' => $_SESSION['threeDSRef'],
'threeDSResponse' => $_POST['threeDSResponse'],
);
}

try {
$res = Gateway::directRequest($req);
} catch (\Exception $e) {

// You should exit gracefully
die('Sorry, the request could not be sent: ' . $e);
}

print $res['responseCode'];
// Check the response code
if ($res['responseCode'] === Gateway::RC_3DS_AUTHENTICATION_REQUIRED) {
// Send request to the ACS server displaying response in an IFRAME

// Render an IFRAME to show the ACS challenge (hidden for fingerprint method)
$style = (isset($res['threeDSRequest']['threeDSMethodData']) ? 'display: none;' : '');
echo "<iframe name=\"threeds_acs\" style=\"height:420px; width:420px; {$style}\"></iframe>\n";

// Silently POST the 3DS request to the ACS in the IFRAME
echo silentPost($res['threeDSURL'], $res['threeDSRequest'], 'threeds_acs');

// Remember the threeDSRef as need it when the ACS responds
$_SESSION['threeDSRef'] = $res['threeDSRef'];

} else if ($res['responseCode'] === Gateway::RC_SUCCESS) {
echo "<p>Thank you for your payment.</p>";
echo 'This is your walletID'.' '.'=>'.' '.$res['walletID'];
} else {
echo "<p>Failed to take payment: " . htmlentities($res['responseMessage']) . "</p>";
}

// Render HTML to silently POST data to URL in target brower window
function silentPost($url = '?', array $post = null, $target = '_self') {
$url = htmlentities($url);
$target = htmlentities($target);
$fields = '';


if ($post) {
foreach ($post as $name => $value) {
$fields .= Gateway::fieldToHtml($name, $value);
}
}

$ret = "
<form id=\"silentPost\" action=\"{$url}\" method=\"post\" target=\"{$target}\">
{$fields}
<noscript><input type=\"submit\" value=\"Continue\"></noscript
</form>
<script>
window.setTimeout('document.forms.silentPost.submit()', 0);
</script>
";

return $ret;
}

?>

Credentials on File (COF)

(CIT) - Cardholder opts to store their card details on Merchant's website.

<?PHP

require('gateway.php');

use \P3\SDK\Gateway;

// Merchant signature key
Gateway::$merchantSecret = '3obzOxdqw6e1u';

// Handpoint Gateway URL
Gateway::$directUrl = 'https://commerce-api.handpoint.com/direct/';

// Setup PHP session as use it to store data between 3DS steps
if (isset($_GET['sid'])) {
session_id($_GET['sid']);
}

session_start();
// Compose current page URL (removing any sid and acs parameters)
$pageUrl = ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https://' : 'http://'). $_SERVER['SERVER_NAME']. ($_SERVER['SERVER_PORT'] != '80' ? ':' . $_SERVER['SERVER_PORT'] : ''). preg_replace('/(sid=[^&]+&?)|(acs=1&?)/', '', $_SERVER['REQUEST_URI']);

// Add back the correct sid parameter (used as session cookie may not be passed when the page is redirected from an IFRAME)
$pageUrl .= (strpos($pageUrl, '?') === false ? '?' : '&') . 'sid=' . urlencode(session_id());

// If ACS response into the IFRAME then redirect back to parent window
if (!empty($_GET['acs'])) {
echo silentPost($pageUrl, array('threeDSResponse' => $_POST), '_parent');
exit();
}

if (!isset($_POST['threeDSResponse'])) {
// Initial request

// Gather browser info - can be done at any time prior to the checkout
if (!isset($_POST['browserInfo'])) {
echo Gateway::collectBrowserInfo();
exit();
}

// Direct Request

$req = array(
'merchantID' => 155928,
'action' => 'SALE',
'type' => 1,
'currencyCode' => 826,
'countryCode' => 826,
'amount' => 1999,
'cardNumber' => '5573471234567898',
//An expiry month of 12 (December) will simulate the non frictionless flow and a challenge will appear to the cardholder.
'cardExpiryMonth' => 12,
'cardExpiryYear' => 24,
'cardCVV' => '159',
'customerName' => 'Handpoint Test Customer',
'customerAddress' => 'Merevale Avenue Leicester',
'customerPostCode' => 'LE10 2BU',
'orderRef' => 'Test purchase',
'rtAgreementType' => 'cardonfile',


// The following fields are mandatory for 3DS v2
'remoteAddress' => $_SERVER['REMOTE_ADDR'],
'threeDSRedirectURL' => $pageUrl . '&acs=1',

// The following field allows options to be passed for 3DS v2
// and the values here are for demonstration purposes only
'threeDSOptions' => array(
'paymentAccountAge' => '20220601',
'paymentAccountAgeIndicator' => '05',
),
);

// Add the browser info as it is mandatory for 3DS v2
$req += $_POST['browserInfo'];

} else {
$req = array (
// The following field are only required for tbe benefit of the SDK
'merchantID' => '155928',
'action' => 'SALE',
'threeDSRef' => $_SESSION['threeDSRef'],
'threeDSResponse' => $_POST['threeDSResponse'],
);
}

try {
$res = Gateway::directRequest($req);
} catch (\Exception $e) {

// You should exit gracefully
die('Sorry, the request could not be sent: ' . $e);
}

print $res['responseCode'];
// Check the response code
if ($res['responseCode'] === Gateway::RC_3DS_AUTHENTICATION_REQUIRED) {
// Send request to the ACS server displaying response in an IFRAME

// Render an IFRAME to show the ACS challenge (hidden for fingerprint method)
$style = (isset($res['threeDSRequest']['threeDSMethodData']) ? 'display: none;' : '');
echo "<iframe name=\"threeds_acs\" style=\"height:420px; width:420px; {$style}\"></iframe>\n";

// Silently POST the 3DS request to the ACS in the IFRAME
echo silentPost($res['threeDSURL'], $res['threeDSRequest'], 'threeds_acs');

// Remember the threeDSRef as need it when the ACS responds
$_SESSION['threeDSRef'] = $res['threeDSRef'];

} else if ($res['responseCode'] === Gateway::RC_SUCCESS) {
echo "<p>Thank you for your payment.</p>";
} else {
echo "<p>Failed to take payment: " . htmlentities($res['responseMessage']) . "</p>";
}

// Render HTML to silently POST data to URL in target brower window
function silentPost($url = '?', array $post = null, $target = '_self') {
$url = htmlentities($url);
$target = htmlentities($target);
$fields = '';


if ($post) {
foreach ($post as $name => $value) {
$fields .= Gateway::fieldToHtml($name, $value);
}
}

$ret = "
<form id=\"silentPost\" action=\"{$url}\" method=\"post\" target=\"{$target}\">
{$fields}
<noscript><input type=\"submit\" value=\"Continue\"></noscript
</form>
<script>
window.setTimeout('document.forms.silentPost.submit()', 0);
</script>
";

return $ret;
}

?>

(CIT) - Cardholder opts to store their card details provided to Merchant via mail or telephone.

<?PHP

require('gateway.php');

use \P3\SDK\Gateway;

// Merchant signature key
Gateway::$merchantSecret = '3obzOxdqw6e1u';

// Handpoint Gateway URL
Gateway::$directUrl = 'https://commerce-api.handpoint.com/direct/';

session_start();
// Compose current page URL (removing any sid and acs parameters)
$pageUrl = ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https://' : 'http://'). $_SERVER['SERVER_NAME']. ($_SERVER['SERVER_PORT'] != '80' ? ':' . $_SERVER['SERVER_PORT'] : ''). preg_replace('/(sid=[^&]+&?)|(acs=1&?)/', '', $_SERVER['REQUEST_URI']);

// Add back the correct sid parameter (used as session cookie may not be passed when the page is redirected from an IFRAME)
$pageUrl .= (strpos($pageUrl, '?') === false ? '?' : '&') . 'sid=' . urlencode(session_id());

if (!isset($_POST['threeDSResponse'])) {
// Direct Request

$req = array(
'merchantID' => 155928,
'action' => 'SALE',
'type' => 2,
'currencyCode' => 826,
'countryCode' => 826,
'amount' => 1999,
'cardNumber' => '5573471234567898',
'cardExpiryMonth' => 12,
'cardExpiryYear' => 24,
'cardCVV' => '159',
'customerName' => 'Handpoint Test Customer',
'customerAddress' => 'Merevale Avenue Leicester',
'customerPostCode' => 'LE10 2BU',
'orderRef' => 'Test purchase',
'rtAgreementType' => 'cardonfile',
);

} else {
$req = array (
// The following field are only required for tbe benefit of the SDK
'merchantID' => '155928',
'action' => 'SALE',
);
}

try {
$res = Gateway::directRequest($req);
} catch (\Exception $e) {

// You should exit gracefully
die('Sorry, the request could not be sent: ' . $e);
}

print $res['responseCode'];

// Check the response code
if ($res['responseCode'] === Gateway::RC_SUCCESS) {
echo "<p>Thank you for your payment.</p>";
} else {
echo "<p>Failed to take payment: " . htmlentities($res['responseMessage']) . "</p>";
}

?>

(CIT) - Cardholder pays using a card they previously stored on the Merchant's website.


<?PHP

require('gateway.php');

use \P3\SDK\Gateway;

// Merchant signature key
Gateway::$merchantSecret = '3obzOxdqw6e1u';

// Handpoint Gateway URL
Gateway::$directUrl = 'https://commerce-api.handpoint.com/direct/';

// Setup PHP session as use it to store data between 3DS steps
if (isset($_GET['sid'])) {
session_id($_GET['sid']);
}

session_start();
// Compose current page URL (removing any sid and acs parameters)
$pageUrl = ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https://' : 'http://'). $_SERVER['SERVER_NAME']. ($_SERVER['SERVER_PORT'] != '80' ? ':' . $_SERVER['SERVER_PORT'] : ''). preg_replace('/(sid=[^&]+&?)|(acs=1&?)/', '', $_SERVER['REQUEST_URI']);

// Add back the correct sid parameter (used as session cookie may not be passed when the page is redirected from an IFRAME)
$pageUrl .= (strpos($pageUrl, '?') === false ? '?' : '&') . 'sid=' . urlencode(session_id());

// If ACS response into the IFRAME then redirect back to parent window
if (!empty($_GET['acs'])) {
echo silentPost($pageUrl, array('threeDSResponse' => $_POST), '_parent');
exit();
}

if (!isset($_POST['threeDSResponse'])) {
// Initial request

// Gather browser info - can be done at any time prior to the checkout
if (!isset($_POST['browserInfo'])) {
echo Gateway::collectBrowserInfo();
exit();
}

// Direct Request

$req = array(
'merchantID' => 155928,
'action' => 'SALE',
'type' => 1,
'currencyCode' => 826,
'countryCode' => 826,
'amount' => 1999,
'cardCVV' => '159',
'customerName' => 'Handpoint Test Customer',
'customerAddress' => 'Merevale Avenue Leicester',
'customerPostCode' => 'LE10 2BU',
'orderRef' => 'Test purchase',
'rtAgreementType' => 'cardonfile',

//XREF from previously transaction (transaction that initially stored the card)
'xref' => '22080513FY16RN16LM97FXX',


// The following fields are mandatory for 3DS v2