Web SDK Integration Guide
This tutorial will provide a guide to developing a basic 'Hosted Session' type integration, using Network International's proprietary Web SDK technology, and is intended to provide a starting point for customers and developers that wish to accept credit and debit card payments on their website.
Before you start
You will need the following items before you begin to integrate the Web SDK for a Hosted Session integration:
- A front-end web-site capable of consuming 3rd-party JavaScript libraries (i.e. the Web SDK)
- A back-end service capable of making JSON-based POST requests to the N-Genius Online payments APIs
- One API key (of type 'Hosted Session') to facilitate SDK authentication and session generation
- A second (back-end) API key, used to complete back-end payment completion requests
Both these keys can be generated from the N-Genius Online portal by navigating to the Settings > Integrations > Service Accounts section and following the on-screen prompts.
You will also require an outlet reference (UUID). You can find this by navigating to Settings > Organization Hierarchy in the N-Genius Online portal and clicking on a relevant Outlet to retrieve the matching reference UUID.
Once you are satisfied that you have everything you need, please find below the steps required to integrate the Web SDK onto your own website for a Hosted Session integration.
1. Include the SDK in your website
We host the JavaScript SDK file for this integration type on your behalf in order to streamline your development process, and to ensure that you are always using the most up-to-date version of the SDK. To embed the SDK into your web-site/app, you will need to link it from your code using a <script>
HTML tag, or similar.
The SDK URL for inclusion in your <script>
tag will be:
- https://paypage.sandbox.ngenius-payments.com/hosted-sessions/sdk.js, if you are integrating to our UAT environment (for initial/ongoing integration testing), or...
- https://PAYPAGEDOMAIN/hosted-sessions/sdk.js, if you are integrating to the Live/Production environment
An example of this link method can be seen below in the <script>
tag:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<!--SDK url with rest of your scripts-->
<script src="https://<<paypageSandboxDomain>>/hosted-sessions/sdk.js"></script>
</head>
<body>
<!--Your website code goes here-->
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<!--SDK url with rest of your scripts-->
<script src="https://paypage-uat.ngenius-payments.com/hosted-sessions/sdk.js"></script>
</head>
<body>
<!--Your website code goes here-->
</body>
</html>
Once you include the SDK script in your code, as above, the NI
object will become available in the document window. If you are familiar with jQuery, the NI
object functions comparably to jQuery's $
syntax.
2. Mount the payment form on your website
Once the SDK has been included successfully in your project, you will need to call the mountCardInput
method under the NI
namespace, providing a DOM ID of the element you wish to mount the payment card fields onto:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<script src="https://<<paypageSandboxDomain>>/hosted-sessions/sdk.js"></script>
</head>
<body>
<!--Your website code goes here-->
<!--below div will have payment form loaded -->
<div id="mount-id"></div>
<!--....-->
</body>
<script>
/* Method call to mount the card input on your website */
window.NI.mountCardInput('mount-id'/* the mount id*/, {
style, // Style configuration you can pass to customize the UI
hostedSessionApiKey, // // Hosted Session Key which is used to generate Session ID
language, // language to be passed either "ar" or "en", default: "en"
outletRef, // outlet reference from the portal
onSuccess, // Success callback if hostedSessionApiKey validation succeeds
onFail, // Fail callback if hostedSessionApiKey validation fails
onChangeValidStatus: ({
isCVVValid,
isExpiryValid,
isNameValid,
isPanValid
}) => {
console.log(isCVVValid, isExpiryValid, isNameValid, isPanValid);
}
});
</script>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<script src="https://paypage-uat.ngenius-payments.com/hosted-sessions/sdk.js"></script>
</head>
<body>
<!--Your website code goes here-->
<!--below div will have payment form loaded -->
<div id="mount-id"></div>
<!--....-->
</body>
<script>
/* Method call to mount the card input on your website */
"use strict";
window.NI.mountCardInput('mount-id'
/* the mount id*/
, {
style: style,
// Style configuration you can pass to customize the UI
apiKey: apiKey,
// API Key for WEB SDK from the portal
outletRef: outletRef,
// outlet reference from the portal
onSuccess: onSuccess,
// Success callback if apiKey validation succeeds
onFail: onFail, // Fail callback if apiKey validation fails
onChangeValidStatus: (function (_ref) {
var isCVVValid = _ref.isCVVValid,
isExpiryValid = _ref.isExpiryValid,
isNameValid = _ref.isNameValid,
isPanValid = _ref.isPanValid;
console.log(isCVVValid, isExpiryValid, isNameValid, isPanValid);
});
});
</script>
</html>
This method requires a number of mandatory inputs:
style
: a set of configurable CSS elements you can use to customize the look and feel of the payment fields when they are displayed to the userhostedSessionApiKey
: a dedicated, limited authority API key used by the SDK to authenticate your request, but which cannot be used to execute payments, login to the N-Genius Online portal, or perform any other API interactions beyond SDK authentication. An API key for this purpose can be generated at any time from the N-Genius Online portal (Settings > Integrations > Service Accounts (Type - Hosted Session Service Account)).outletRef
: aUUID
representing the N-Genius Online outlet against which you wish to process a transactiononSuccess
: a call-back function allowing you to provide bespoke code to be executed if the authentication of the SDK with N-Genius Online is successful. Often, this is used to hide an element that could be used as a placeholder whilst the SDK is being loaded (i.e. a spinner)onFail
: a call-back function allowing you to provide bespoke code to be executed if the authentication of the SDK is unsuccessful.onChangeValidStatus
: a call-back function that is called when a field changes from valid to invalid state or vice versa. This function is called with a single argument which is an object with 4 keys as followsisCVVValid
,isExpiryValid
,isNameValid
,isPanValid
. Each key holds a valuetrue
orfalse
based on the validity of the respective fields. You can use this call back to ascertain if all fields are valid or not before proceeding to generate a session ID.
Note that you may wish to call this method only when the full DOM has been loaded by the user's browser, in order to avoid errors arising from order of execution.
DOM Readiness
Various methods exist for ensuring that, when the JavaScript contained in the
<script>
HTML tag is executed, the full DOM has already been loaded. One such example is the jQuery.ready()
syntax, but how you choose to do this will depend on your desired user experience, and choice of programming language.
If all the above parameters are correct, the SDK will attempt to authenticate itself with the N-Genius Online identity services and, if successful, you should now see the payment form loaded on the DOM mount id
provided.
A basic example of the customization available with the style
element:
Token Expiry
By default, the self-authentication of the N-Genius Online SDK is only valid for five minutes.
It is important to factor this understanding in to your page design, in order to ensure that the payment fields are only displayed when your customer is actually ready to pay, or to provide some mechanism to automatically refresh the session after the five minute period has elapsed.
Once you have been successful in calling the payment fields from the SDK, we must now capture the card information provided by the customer, and generate a unique payment session.
How to Unmount(optional) :
Some merchants design their payment pages similarly to Stepper, where the user enters information in multiple steps. If your payment page is designed in this way, you must mount and unmount the card inputs to account for all possible scenarios and obtain correct behavior for our SDK. Therefore, you must use the unMountCardinputs function from the window.NI object to unmount the SDK
window.NI.unMountCardInputs()
3. Generate Session ID
The Session ID (sessionId
) is a unique reference value valid against the context of the entered card details, which can be used only one time, and is required to make a payment with N-Genius Online.
To generate the sessionId
you need to call an asynchronous JavaScript method called generateSessionId
in the NI
namespace.
Example:
/* This code would only work if its called after the mountCardInput has been called successfully */
<div>
<div id="mount-id"></div>
<button onclick="createSession()" class="checkoutButton">
Check out
</button>
</div>
<script>
let sessionId;
async function createSession() {
try {
const response = await window.NI.generateSessionId();
sessionId = response.session_id;
} catch (err) {
console.error(err);
}
}
</script>
/* This code would only work if its called after the mountCardInput has been called successfully */
<div>
<div id="mount-id"></div>
<button onclick="createSession()" class="checkoutButton">
Check out
</button>
</div>
<script>
"use strict";
var sessionId;
function createSession() {
window.NI.generateSessionId().then(function (response) {
sessionId = response.session_id;
}).catch(function (error) {
return console.error(err);
});
}
</script>
Typically, the generateSessionId
method would be called by the onClick
(or similar) function of a button in your control labelled "Pay" or "Pay Now".
Importantly, you should store the resulting (sessionId
) of successful generateSessionId
calls for use in the later steps.
Auth Timeout
Note that the above
generateSessionId
will fail with an error if the authentication window of the previous step (mountCardInput
) has expired. For testing purposes, you should ensure that you refresh the page or reload the SDK handling component at appropriate intervals in order to avoid such errors.
Once you have successfully generated a valid sessionId
from the generateSessionId
call, we may now move on to performing the final step in completing the requested payment.
4. Make a call to your own server to make the payment
Now that we have the sessionId
generated we can proceed to make the payment, the final step which requires your back-end services to call the N-Genius Online APIs to complete the payment.
The flow diagram below describes the remaining process.
You should pass the sessionId
received in the previous step to your back-end service, perhaps via a POST
request or similar. This will be used to complete the payment process.
Data Integrity
Since the
sessionId
variable is a one-time value, it is safe to pass this information from your front-end to your back-end service.However, it is extremely important that you do not attempt to pass any sensitive, order/payment related data in this way, as it is visible to the consumer's browser and may be compromised.
Instead, sensitive data related to the payer's order (i.e. amount, keys, etc.) should be retrieved and sourced from the back-end service directly, perhaps from a database containing records of customer baskets, or similar.
It is your responsibility to ensure that your site is not passing sensitive data across domains in an insecure manner.
Request an access token
We must first validate ourselves with the identity service and obtain an access token. This token allows us to execute operations on the gateway APIs with authority, and whilst a single token will expire after 5 minutes, we can use our Service Account API key to generate one at any time.
HTTP Request Method: POST
Resource (URI): https://api-gateway.sandbox.ngenius-payments.com/identity/auth/access-token
Headers
Header key | Header value |
---|---|
Content-Type | x-www-form-urlencoded |
Authorization | Basic: api_key |
Body
Payload / body key | Payload / body value |
---|---|
grant_type | client_credentials |
Example request
{
‘grant_type’: ‘client_credentials’
}
Example response
{
“access_token”: “eyJhbGciOiJSUzI1N…0eDloZnVRI”,
“expires_in”: 300,
“refresh_expires_in”: 1800,
“refresh_token”: “eyJhbGciOi…eDloZnVRIn0”,
“token_type”: “bearer”,
“not-before-policy”: 0,
“session_state”: “1f2e7d6e-e1f6-41f8-b763-37be5ef747d2”,
“scope”: “”
}
Retrieve the access_token
value and store it ready for the next step...
Complete the payment
Now we can call the N-Genius Online APIs to request completion of the payment we initiated earlier, using the following key values:
sessionId
: passed from our front-end to our back-end service, at the beginning of step 4 of this integration guideaccess_token
: which we just received from our identification/authentication calloutletRef
: the N-Genius Online outlet reference we used in the SDK authentication call in step 2 of this guideamount
: retrieved from a secure back-end source (not passed from front-end)
In particular, you should ensure that any static values in your code (i.e. outletRef
) are not referenced/embedded directly, but pulled from a secure source. This will improve both the security and the flexibility of your integration.
HTTP Request Method: POST
Resource (URI): https://api-gateway.sandbox.ngenius-payments.com/transactions/outlets/ {outletRef}
/payment/hosted-session/ {sessionId}
Headers
Header key | Header value |
---|---|
Authorization | Bearer access_token |
Content-Type | application/vnd.ni-payment.v2+json |
Accept | application/vnd.ni-payment.v2+json |
Body
Payload / body key | Payload / body value |
---|---|
action | "SALE" (or "AUTH" for authorization only) |
amount { } | N/A |
amount.currencyCode | "AED" (or "USD", "GBP", per availability) |
amount.value | 100 (in minor units, i.e. "100" = 1.00 AED) |
payment { } | N/A (For MCP transactions only) |
payment.currency | Payer chosen currency, i.e. "USD" (For MCP Transactions only) |
Example request
{
"action": "SALE",
"amount": { "currencyCode": "AED", "value":100 }
}
Code examples
// NodeJS example (using express.js framework)
async function getAuthToken() {
const {
data: { access_token: accessToken }
} = await axios.post(
IDENTITY_API_URL,
querystring.stringify({ grant_type: 'client_credentials' }),
{
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
Authorization: `Basic ${API_KEY}` /* This is the Service Account API key to make the payment */
}
}
);
return accessToken;
}
app.post('/api/hosted-sessions/payment', async (req, res) => {
try {
const { sessionId, order, outletRef } = req.body;
const accessToken = await getAuthToken();
const { data } = await axios.post(
`${TRANSACTIONS_SERVICE_URL}outlets/${outletRef}/payment/hosted-session/${sessionId}`,
{
...order
},
{
headers: {
Authorization: `Bearer ${accessToken}`, // Note the access_token received in the previous step is passed here
'Content-Type': 'application/vnd.ni-payment.v2+json',
Accept: 'application/vnd.ni-payment.v2+json'
}
}
);
res.status(200).send(data);
} catch (e) {
res.send(500).send(e.message);
}
});
<?php
// get these from secure back-end sources
$outlet = {outletRef};
$apikey = {apiKey};
$amount = {amount};
if (isset($_POST['sessionId'])) {
$session = $_POST['sessionId'];
try {
$idData = identify($apikey);
if (isset($idData->access_token)) {
$token = $idData->access_token;
$payData = pay($session, $token, $outlet);
echo(json_encode($payData));
}
} catch (Exception $e) {
echo($e->getMessage());
}
}
/////////////////////
function identify($apikey) {
$idUrl = "https://identity-uat.ngenius-payments.com/auth/realms/ni/protocol/openid-connect/token";
$idHead = array("Authorization: Basic ".$apikey, "Content-Type: application/x-www-form-urlencoded");
$idPost = http_build_query(array('grant_type' => 'client_credentials'));
$idOutput = invokeCurlRequest("POST", $idUrl, $idHead, $idPost);
return $idOutput;
}
function pay($session, $token, $outlet) {
// construct order object JSON
$ord = new stdClass;
$ord->action = "SALE";
$ord->amount = new stdClass;
$ord->amount->currencyCode = "AED";
$ord->amount->value = "100";
$payUrl = "https://api-gateway-uat.ngenius-payments.com/transactions/outlets/".$outlet."/payment/hosted-session/".$session;
$payHead = array("Authorization: Bearer ".$token, "Content-Type: application/vnd.ni-payment.v2+json", "Accept: application/vnd.ni-payment.v2+json");
$payPost = json_encode($ord);
$payOutput = invokeCurlRequest("POST", $payUrl, $payHead, $payPost, true);
return $payOutput;
}
function invokeCurlRequest($type, $url, $headers, $post, $json) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
if ($type == "POST" || $type == "PUT") {
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
if ($type == "PUT") {
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
}
}
$server_output = curl_exec ($ch);
return json_decode($server_output);
}
?>
This is just a sample snippet of handling the payment call from your server and it can be implemented in any language of your choice.
5. Handle Payment Response (Without 3DS)
Most customers will be processing payments enabled for 3-D Secure payer authentication. However, in some instances the 3DS step is either suppressed, switched off or not relevant.
Once you have received the response from the previous call, you will need to call the handlePaymentResponse
method in the NI
namespace, as follows:
/* paymentResponse is the response from the previous call */
const {status, error} = await window.NI.handlePaymentResponse(paymentResponse);
"use strict";
/* paymentResponse is the response from the previous call */
window.NI.handlePaymentResponse(paymentResponse).then(function (response) {
console.log(response.status, response.error);
});
In order to understand the status of the payment you will need evaluate the status
parameter.
For a non-3DS payment (one where 3-D Secure payer authentication process has been skipped, or is not relevant) the status can take one of 3 distinct states, found in the paymentStates
object under the NI
namespace:
- For successful authorization, status will be:
window.NI.paymentStates.AUTHORISED
- For a successful sale, status will be:
window.NI.paymentStates.CAPTURED
- For a successful card verification, status will be:
window.NI.paymentStates.VERIFIED
- For a failed transaction, status will be
window.NI.paymentStates.FAILED
Based on the result of the above status check, you may then provide an appropriate outcome message to your customer.
const {status, error} = await window.NI.handlePaymentResponse(paymentResponse);
if (
status === window.NI.paymentStates.AUTHORISED ||
status === window.NI.paymentStates.CAPTURED
) {
// Same as before this signals successful payment
} else if (
status === window.NI.paymentStates.FAILED ||
// A new state to look out for is 3DS Challenge failure
status === window.NI.paymentStates.THREE_DS_FAILURE
) {
// payment failure signal
} else {
// FAILED authentications scenarios
}
"use strict";
window.NI.handlePaymentResponse(paymentResponse)
.then(function (response) {
if (response.status === window.NI.paymentStates.AUTHORISED ||
response.status === window.NI.paymentStates.CAPTURED) {
// do something to show status on UI
} else if (response.status === window.NI.paymentStates.FAILED) {
// do something for failed case
}
});
6. Handle Payment Response with 3DS Enabled
This will be pretty similar to the previous step the only distinction being we need a way mountId
again to show the 3DS challenge form in your website. So the function call changes a little bit to look something like this:
const { status, error } = await window.NI.handlePaymentResponse(
paymentResponse,
{
mountId: '3ds_iframe',
style: { width: 500, height: 500 }
}
);
"use strict";
window.NI.handlePaymentResponse(paymentResponse, {
mountId: '3ds_iframe',
style: {
width: 500,
height: 500
}
}).then(function (response) {
console.log(response.status, response.error);
});
The only difference being the additional object with mountId
and style
config to load 3DS challenge iframe.
To get the status of 3DS challenge is same as before with few other paymentStates
:
const {status, error} = await window.NI.handlePaymentResponse(paymentResponse);
if (
status === window.NI.paymentStates.AUTHORISED ||
status === window.NI.paymentStates.CAPTURED
) {
// Same as before this signals successful payment
} else if (
status === window.NI.paymentStates.FAILED ||
// A new state to look out for is 3DS Challenge failure
status === window.NI.paymentStates.THREE_DS_FAILURE
) {
// payment failure signal
} else {
// FAILED authentications scenarios
}
"use strict";
window.NI.handlePaymentResponse(paymentResponse, {
mountId: '3ds_iframe',
style: {
width: 500,
height: 500
}
}).then(function (response) {
var status = response.status;
if (status === window.NI.paymentStates.AUTHORISED
|| status === window.NI.paymentStates.CAPTURED) {
// Same as before this signals successful payment
} else if (status === window.NI.paymentStates.FAILED || // A new state to look out for is 3DS Challenge failure
status === window.NI.paymentStates.THREE_DS_FAILURE) {
// payment failure signal
}
});
So the new status the payment can be in is: NI.paymentStates.THREE_DS_FAILURE
.
Updated 4 months ago