Tokenization and 3D Secure Support [Deprecated]
Overview
Note: The integration described on this page is deprecated. For new integrations, please see the new version at Tokenization and 3D Secure Support (Version 2).
Radial's foundational JavaScript library can be used to quickly integrate with the Radial Payments Framework in order to take advantage of Tokenization and 3D Secure (3DS) Support. This can be done by loading Radial's radial_payments.js and invoking the appropriate methods as needed.
Note: A similar process can be used to encrypt payment card numbers entered in mobile apps. For more information, see Encryption Support for Mobile Apps.
The radial_payments.js can be used for a wide variety of scenarios:
- Tokenization Only: This call is typically invoked when credit card information is captured without making a purchase. The webstore must use radial_payments.js and call to get token.
- Tokenization and 3DS Authentication: This call is typically invoked when the customer enters a credit card on the payment screen and places an order. In this case, the webstore is expected to call tokenAndAuthenticate js method provided by Radial.
- 3DS Authentication with Saved Token: This call is typically invoked when the customer uses a saved card to place an order. In this case, the webstore is expected to invoke the authenticate call provided by Radial passing in the account_token as an input parameter.
One of the following responses will be returned by Radial at the completion of the Authentication call: SUCCESS, FAILURE, ERROR, NOACTION.
If the response is SUCCESS or NOACTION (not enrolled), the account_token, which is the tokenized account number, is generally returned in the json data object of the callback method invoked by Radial.
Including radial_payments.js
When using radial_payments.js, you begin by including the library. Add this script tag to your page:
- Test Environment
<script src=http://tst.payments.radial.com/hosted-payments/radial_payments.js></script>
- Production Environment
<script src=https://hostedpayments.radial.com/hosted-payments/radial_payments.js></script>
Use Case #1: Tokenization
There are three main steps involved in the Tokenization call. The following sequence diagram shows the tokenization flow.
Step #1: Nonce Generation
Nonce generation is a server-to-server call. For security purpose, Radial must authenticate the webstore prior to exchange any data. To facilitate authentication, Radial exposes a HTTPS REST endpoint where a webstore can submit its credentials in the request body.
During Radial Integration, each webstore will be provided with authentication credentials. Thewebstore must submit these credentials in the body of the nonce generation request.
Use these environment-specific URLs to generate a nonce:
- Test Environment
https://tst.payments.radial.com/hosted-payments/auth/nonce
- Production Environment
https://hostedpayments.radial.com/hosted-payments/auth/nonce
The following is an example of a nonce generation request body.
{
"username" : "username",
"password" : "password",
}
The nonce generation call provides a response similar to the following.
{
"nonce": "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJUTVNVUyIsImF1ZCI6IndlYiIsImV4cCI6MTU4MjE5MDkyOSwiaWF0IjoxNTgyMTkwNjI5fQ.wPiSkUJX8trQcFrVIlG4jRJ8EhdSbddThKWGZ-_ROr-HTkn2RHU97qqhQHoOZvIxfojmJUI_lwwFr2Sl0qbNAw" ,
"expires_in_seconds": 300,
}
Note: The nonce obtained has an expiration period associated with it. Currently, the expiration duration is set as 300 seconds. But this expiration period can vary from time to time based on security requirements. If the nonce times out, you will receive an InvalidLoginError(50002) as a response for subsequent calls. If that occurs, the webstore can make a new server to server authentication call to get a new nonce.
The webstore must capture the response and send the information to the browser. The nonce returned in the response is needed in the JavaScript library method calls.
In case of error, the payload below is returned:
{
"error_code" : "50002",
"error_message" : "InvalidLoginError",
}
Below are the possible errors that can be returned,
Error Code | Error Message | Description |
---|---|---|
50002 | InvalidLoginError | The nonce used to connect to Radial is invalid or timed out. Renew the nonce and try again. |
50003 | RadialInternalError | There was an internal error in Radial's system. |
The following code snippet generates the nonce
public class RestCallClient {
public static void main(String[] args) {
try {
URL url = new URL("http://tst.payments.radial.com/hosted-payments/auth/nonce");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json");
String input = "{\n" +
"\t\"username\": \"username\",\n" +
"\t\"password\" : \"password\",\n" +
"}";
OutputStream os = conn.getOutputStream();
os.write(input.getBytes());
os.flush();
System.out.println(conn.getResponseCode());
BufferedReader br = new BufferedReader(new InputStreamReader(
(conn.getInputStream())));
StringBuilder builder = new StringBuilder();
String output;
System.out.println("Output from Server .... \n");
while ((output = br.readLine()) != null) {
System.out.println(output);
builder.append(output);
}
System.out.println(builder);
JSONObject jsonObject = new JSONObject(builder.toString());
System.out.println(jsonObject.getString("nonce"));
conn.disconnect();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Step #2: Download radial_payments.js and Initialize JavaScript
Note: The JavaScript integration makes a cross-site call from the browser to Radial's server instead of the originating webstore server. This is a CORS request. The webstore should give Radial the IP address or domain names of servers for Javascript integration, so that Radial can whitelist the servers to enable the cross-site call.
Radial hosts a JavaScript file, radial_payments.js, which provides the tokenization functionality. The nonce received in Step #1 is necessary for subsequent JavaScript calls from the browser. The webstore should download the radial_payments.js file using the script tag when the customer navigates to the checkout page. After downloading the radial_payments.js file, the webstore should invoke the Radial.setup() method by passing the nonce as illustrated in the following example. In other words, Radial.setup() should be invoked in the checkout page onload event.
<head>
<script src="http://tst.payments.radial.com/hosted-payments/radial_payments.js"></script>
<script language="JavaScript">
function loadNonce() {
Radial.setup('<%=request.getAttribute("nonce")%>');
}
</script>
</head>
<body onload="loadNonce()">
Step #3: Accept Card Data and Handle Tokenization Response
After capturing card data, the webstore code should immediately call Radial's javascript method Radial.tokenize(), passing the card data.
onclick="Radial.tokenize('accountNumber', tokenizeCallBackHandler);"
The webstore must implement a tokenizationCallbackHandler() JavaScript method that will be called when the Radial.tokenize() receives a response. The webstore can handle the response as in the following example.
<script language=" javascript">
tokenizationCallbackHandler(data) {
switch(data.ActionCode){
case "SUCCESS":
alert(data.account_token);
break;
case "FAILURE":
alert(data.failure_code);
alert(data.failure_message);
break;
case "ERROR":
alert(data.error_code);
alert(data.error_message);
break;
}
</script>
In case of success, the webstore can collect the account_token from the json object.
There are several possible failure responses for this call. Failure can occur with an invalid credit card number or a card number that failed a luhn check. The webstore can prompt the user to correct the error and retry the request.
Below is a list of possible failures that can be returned:
Error Code | Error Message | Description |
---|---|---|
40001 | NonNumericDataException | The account number passed in was not numeric |
40002 | PanTooShortException | The account number passed in was too short. |
40003 | PanDoesNotPassLuhnCheckException | The account number passed in did not pass luhn check. |
40004 | PanTooLongException | The account number passed in was too long. |
40006 | TokenNotFoundException | When the token passed in does not exist in Radial System. |
Some errors can be caused by an issue on the network or with one of Radial's internal services. If one of these errors is returned, the webstore can implicitly retry the request without user intervention. The following errors fall into this category.
Error Code | Error Message | Description |
---|---|---|
50001 | TimeoutError | There was a time out attempting to contact Radial's payment service |
50002 | NonceTimedoutError | The nonce used to connect to Radial is invalid or timed out. Renew the nonce and try again. |
50003 | RadialInternalError | There was an internal error in Radial's system. |
It is suggested that the client can bypass 3DS and proceed with order checkout in all 5000* error cases except during InvalidLoginError and NonceTimeoutError (50002) scenarios.
Use Case #2: Tokenization and 3DS Authorization
Step #1: Nonce Generation
Nonce generation is a server-to-server call. For security purpose, Radial must authenticate the webstore prior to exchange any data. To facilitate authentication, Radial exposes a HTTPS REST endpoint where a webstore can submit its credentials in the request body.
During Radial Integration, each webstore will be provided with authentication credentials. Thewebstore must submit these credentials in the body of the nonce generation request.
Use these environment-specific URLs to generate a nonce:
- Test Environment
https://tst.payments.radial.com/hosted-payments/auth/nonce
- Production Environment
https://hostedpayments.radial.com/hosted-payments/auth/nonce
The following is an example of a nonce generation request body.
{
"username" : "username",
"password" : "password",
}
The nonce generation call provides a response similar to the following.
{
"nonce": "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJUUlVTMiIsImF1ZCI6IndlYiIsImV4cCI6MTU4MjE5NzcxOCwiaWF0IjoxNTgyMTk3NDE4fQ.aaXjnv9SPcKKoOt4k1jzM_tTisgNSZ6OoaNy43SRTI9LPo9APHV-BT1zej7vSCl694qzhJDuqvWyoqYC9ggOow" ,
"expires_in_seconds": 300,
"jwt": "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJjMzQ4MTg3Yy0zNTMzLTRkYjUtYWEwZS1kZjZmZjc5MDI1ZWUiLCJpYXQiOjE1ODIxOTc0MTgsImlzcyI6IjU4NWFkOTY0ZGE1MjkzNjIyMDg5OTY5YSIsIk9yZ1VuaXRJZCI6IjU3OTA4YjhlMzNmYWRkNTQ4ODRiNjcxZCIsIlJlZmVyZW5jZUlkIjoiMmJkMzYzZGQyNjQyNDU0OTlmNjZjN2Q1YWY3ODdkZTkiLCJleHAiOjE1ODIyMDQ2MTh9.gzjxFuAFj6WUYdjlxm_qppaiwqkbAiakvimprTi5tgw”
}
Note: The nonce obtained has an expiration period associated with it. Currently, the expiration duration is set as 300 seconds. But this expiration period can vary from time to time based on security requirements. If the nonce times out, you will receive an InvalidLoginError(50002) as a response for subsequent calls. If that occurs, the webstore can make a new server to server authentication call to get a new nonce.
The webstore must capture the response and send the information to the browser. Two pieces of information in the nonce generation response are required for the JavaScript library: the nonce and the jwt. The webstore must ensure these two elements are available in the browser.
In case of error, the payload below is returned:
{
"error_code" : "50002",
"error_message" : "InvalidLoginError",
}
Below is a list of possible errors that can be returned.
Error Code | Error Message | Description |
---|---|---|
50002 | InvalidLoginError | The nonce used to connect to Radial is invalid or timed out. Renew the nonce and try again. |
50003 | RadialInternalError | There was an internal error in Radial's system. |
The following code snippet generates the nonce.
public class RestCallClient {
public static void main(String[] args) {
try {
URL url = new URL("https://tst.payments.radial.com/hosted-payments/auth/nonce");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json");
String input = "{\n" +
"\t\"username\": \"username\",\n" +
"\t\"password\" : \"password\",\n" +
"}";
OutputStream os = conn.getOutputStream();
os.write(input.getBytes());
os.flush();
System.out.println(conn.getResponseCode());
BufferedReader br = new BufferedReader(new InputStreamReader(
(conn.getInputStream())));
StringBuilder builder = new StringBuilder();
String output;
System.out.println("Output from Server .... \n");
while ((output = br.readLine()) != null) {
System.out.println(output);
builder.append(output);
}
System.out.println(builder);
JSONObject jsonObject = new JSONObject(builder.toString());
System.out.println(jsonObject.getString("nonce"));
conn.disconnect();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Step #2: Download radial_payments.js and Initialize JavaScript
Note: The JavaScript integration makes a cross-site call from the browser to Radial's server instead of the originating webstore server. This is a CORS request. The webstore should give Radial the IP address or domain names of servers for Javascript integration, so that Radial can whitelist the servers to enable the cross-site call.
Radial hosts a JavaScript file, radial_payments.js, which provides the tokenization functionality. The nonce received in Step #1 is necessary for subsequent JavaScript calls from the browser. The webstore should download the radial_payments.js file using the script tag when the customer navigates to the checkout page. After downloading the radial_payments.js file, the webstore should invoke the Radial.setup() method by passing the nonce as illustrated in the following example. In other words, Radial.setup() should be invoked in the checkout page onload event.
<head>
<script src="http://tst.payments.radial.com/hosted-payments/radial_payments.js"></script>
<script language="JavaScript">
function loadNonce() {
Radial.setup('<%=request.getAttribute("nonce")%>', '<%=request.getAttribute("jwt")%>');
}
</script>
</head>
<body onload="loadNonce()">
Integration Flow
The sequence diagram below shows the series of system interactions in 3DS Tokenization.
- The browser requests the payment page from the webstore server.
- The webstore server sends a request to Radial with the userid and password provided during Radial Integration.
- The webstore server receives nonce and jwt in Radial's response (JWT will be sent in the response only if the store is enabled for 3DS functionality).
- The webstore server provides the payment page along with jwt and nonce, which are used to initialize the JavaScript (with the Radial.setup() method). Webstore server should invoke the Radial.setup() javascript method during the checkout page onload().
- The user enters the card details, and the browser sends a 3DS request to Radial(Radial.tokenizeAndAuthorize()).
- Radial makes a prelude request to 3D Secure Verification Provider.
- Radial receives a prelude response from 3D Secure Verification Provider.
- Radial provides the prelude response to browser.
- The browser (JavaScript) 3DS authentication call is invoked.
- Issuer 3DS popup is displayed. The user provides their authentication password. In case of ghost authentication, the popup does not show.
- The authentication popup is submitted and verified by the issuer.
- The response provided by the JavaScript contains the 3D Secure status results.
- The payment page is submitted with the 3DS results.
- The webstore collects the 3DS results and includes them in payment credit card auth request.
Step #3: Accept Card Data and Invoke Authentication
As soon as card data is captured, the webstore client code should call Radial's javascript method 'Radial.tokenizeAndAuthorize()', passing the card data and the order data as a jsonObject, as shown in the example below:
Radial.tokenizeAndAuthorize('pan', jsonObject, tokenizeAndAuthorizeCallbackHandler);
The webstore must implement the tokenizeAndAuthorizeCallbackHandler and invoke it with the results of the 3DS authentication.
The table below describes the fields in the json object to be passed in to the Radial.tokenizeAndAuthorize() js method. Some fields are marked optional, but the values in these fields are important in the 3D Secure rule utilization. It is recommended that all of the listed fields are passed in, when possible.
Note regarding shipping address: In certain orders for electronic delivery items, shipping address may not be available. In such cases, it is recommended to send the billing address as the shipping address. In scenarios where the order is being shipped to multiple destinations, send the shipping address of the destination that receives the maximum order value.
3d Secure Json Object Format:
Field Name | Description | Required | Field Length |
---|---|---|---|
RequestId | RequestId identifies a request message and is used to protect against duplicate request processing. Use a new RequestId if you want to get a fresh response and not one from the cache. | N | AN(40) |
OrderNumber | Order identifier. Please ensure that the same order number is used in all subsequent transactions for the same order, such as credit card auth request, risk assessment, and order create. If the order number in subsequent calls does not match this order number, it nullifies the effect of the 3DS fraud check. | Y | AN(50) |
CurrencyCode | 3 character alpha code ISO-4217 currency code for the sale amount | Y | AN(3) |
Amount | Unformatted total transaction amount without any decimals. Eg: $100.00 = 10000, $123.67 = 12367 | Y | N(20) |
CardExpMonth | Card number Expiration month. Formatted MM Eg. January = 01 | Y | N(2) |
CardExpYear | Card number expiration year. Formatted YYYY Example YYYY= 2016 | Y | N(4) |
Consumer's email address | Y | AN(255) | |
BillingFirstName | Consumer's first name | Y | AN(50) |
BillingLastName | Consumer's last name | Y | AN(50) |
BillingAddress1 | Consumer's billing address line 1 | Y | AN(50) |
BillingAddress2 | Consumer's billing address line 2 | N | AN(50) |
BillingCity | Consumer's city of billing address | Y | AN(50) |
BillingState | Consumer's billing state | N | AN(50) |
BillingCountryCode | Consumer's alpha 2 digit ISO 3166 country code. Example: United States = US | Y | AN(3) |
BillingPostalCode | Consumer's billing postal code | N | AN(10) |
BillingPhone | Consumer's phone number for billing address. This should be unformatted without hyphens. Example: 222-234-5678 = 2222345678 | Y | AN(20) |
ShippingFirstName | Recepient's first name | Y | AN(50) |
ShippingLastName | Recepient's last name | Y | AN(50) |
ShippingAddress1 | Recepient's address line1 | Y | AN(50) |
ShippingAddress2 | Recepient's address line1 | N | AN(50) |
ShippingCity | Recepient's address city | Y | AN(50) |
ShippingState | Recepient's address state | N | AN(50) |
ShippingCountryCode | Recepient's alpha 2 digit ISO 3166 country code. Example: United States = US | Y | AN(3) |
ShippingPostalCode | Recepient's postal code | N | AN(10) |
ShippingPhone | Recepient’s phone number for billing address. This should be unformatted without hyphens. Example: 222-234-5678 = 2222345678 | Y | AN(20) |
IPAddress | The IP Address of the consumer. Note: IPv4 and IPv6 are supported | Y | AN(50) |
UserAgent | The exact content of the http user agent header | N | AN(500) |
Sample jsonObject Request with Mandatory elements
{
"cmpiRequestObject": {
"OrderNumber": "12345678",
"CurrencyCode": "USD",
"Amount": "500",
"CardExpMonth": "01",
"CardExpYear" : "2020",
"EMail": "johnconsumer@consumerdomain.com",
"BillingFirstName": "John",
"BillingLastName": "Consumer",
"BillingAddress1": "123 Main Street",
"BillingCity": "Cleveland",
"BillingCountryCode": "US",
"BillingPhone": "2162162116",
"ShippingFirstName": "John",
"ShippingLastName": "Consumer",
"ShippingAddress1": "123 Main Street",
"ShippingCity": "Cleveland",
"ShippingCountryCode": "US",
"ShippingPhone": "2162162116",
"IPAddress": "0:0:0:0:0:0:0:1"
}
}
Radial handles the handshake with the 3DS provider and redirects the browser to an 3DS authentication window that looks like the example below:
The user is prompted for authentication information.
Note:In case of passive authentication, there is no challenge popup for the user. The order information is implicitly validated and the 3DS status returned without any user intervention.
Upon completion of the process, call the tokenizeAndAuthorizeCallbackHandler. The webstore must implement a tokenizeAndAuthorizeCallbackHandler() JavaScript method and call it when the 'Radial.tokenizeAndAuthorize()' call receives a response. The webstore can handle the response as shown below:
<script language="javascript">
tokenizeAndAuthorizeCallbackHandler (data) {
switch(data.ActionCode){
case "SUCCESS":
alert(data.account_token);
// Handle successful authentication scenario
break;
case "NOACTION":
alert(data.account_token);
// Handle unenrolled scenario (treat same as success)
break;
case "FAILURE":
alert(data.failure_code);
alert(data.failure_message);
// Handle authentication failed or error encounter scenario
break;
case "ERROR":
alert(data.error_code);
alert(data.error_message);
// Handle service level error
break;
}
</script>
In case of SUCCESS or NOACTION, the webstore can collect the account_token from the json object and proceed. SUCCESS and NOACTION codes indicate everything is good with respect to the card, and the webstore can proceed with the transaction.
Response Format
The response object returned in the callback handler is in json format and in general has the format shown below.
{
"Validated": false,
"Payment": {
"Type": "CCA",
"ProcessorTransactionId": "dk5O2XPRJ6MXMdf2Drv0",
"ExtendedData": {
"CAVV": "",
"ECIFlag": "07",
"XID": "ZGs1TzJYUFJKNk1YTWRmMkRydjA=",
"PAResStatus": "N",
"SignatureVerification": "Y"
}
},
"ActionCode": "SUCCESS",
"ErrorNumber": 0,
"ErrorDescription": "Success"
}
}
The 3DS fields you are required to capture can be found within the nested “ExtendedData” object. The JSON fields that matter are the ExtendedData object, ActionCode and Error code. The rest of the fields are present for informational purposes and can be safely ignored.
In case of failure, it could be because of an invalid credit card number or a number that failed a luhn check. The webstore can prompt the user to correct the error and retry the request.
Below is a list of possible failures that can be returned:
Error Code | Error Message | Description | ||
---|---|---|---|---|
40001 | NonNumericDataException | The account number passed in was not numeric | ||
40002 | PanTooShortException | The account number passed in was too short. | ||
40003 | PanDoesNotPassLuhnCheckException | The account number passed in did not pass luhn check. | ||
40004 | PanTooLongException | The account number passed in was too long. | ||
40005 | Incomplete3dsData | The json object passed in does not have all the required fields. | ||
40006 | TokenNotFoundException | When the token passed in does not exist in Radial System. | ||
40007 | Authentication failure/Signature verification failure. | When user authentication in the 3DS challenge popup fails or there is a signature verification failure at 3D Secure Verification Provider end. | ||
40008 | BasicParamSetupException | Before calling this method, some basic parameters need to be set |
Some errors can be caused by an issue on the network or with one of Radial's internal services. If one of these errors is returned, the webstore can implicitly retry the request without user intervention. The following errors fall into this category.
Error Code | Error Message | Description |
---|---|---|
50001 | TimeoutError | There was a time out attempting to contact Radial's payment service |
50002 | InvalidLoginError | The nonce used to connect to Radial is invalid or timed out. Renew the nonce and try again. |
50003 | RadialInternalError | There was an internal error in Radial's system. |
50004 | InvalidJWTError | The JWT used to connect to Radial is invalid. Get a fresh jwt and try again. |
50005 | 3dsGatewayTimeoutError | The 3DS gateway timed out. At this point, the webstore can choose to take the order without 3DS authentication if it wishes or retry the authentication again. |
50006 | 3dsGatewayInternalError | There was an internal error with the 3DS gateway. |
It is suggested that the client can bypass 3DS and proceed with order checkout in all 5000* error cases except during InvalidLoginError and NonceTimeoutError (50002) scenarios.
Use Case #3: Authentication with Saved Token
Step #1: Nonce Generation
Nonce generation is a server-to-server call. For security purpose, Radial must authenticate the webstore prior to exchange any data. To facilitate authentication, Radial exposes a HTTPS REST endpoint where a webstore can submit its credentials in the request body.
During Radial Integration, each webstore will be provided with authentication credentials. Thewebstore must submit these credentials in the body of the nonce generation request.
Use these environment-specific URLs to generate a nonce:
- Test Environment
https://tst.payments.radial.com/hosted-payments/auth/nonce
- Production Environment
https://hostedpayments.radial.com/hosted-payments/auth/nonce
The following is an example of a nonce generation request body.
{
"username" : "username",
"password" : "password",
}
The nonce generation call provides a response similar to the following.
{
"nonce": "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJUUlVTMiIsImF1ZCI6IndlYiIsImV4cCI6MTU4MjE5NzcxOCwiaWF0IjoxNTgyMTk3NDE4fQ.aaXjnv9SPcKKoOt4k1jzM_tTisgNSZ6OoaNy43SRTI9LPo9APHV-BT1zej7vSCl694qzhJDuqvWyoqYC9ggOow" ,
"expires_in_seconds": 300,
"jwt": "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJjMzQ4MTg3Yy0zNTMzLTRkYjUtYWEwZS1kZjZmZjc5MDI1ZWUiLCJpYXQiOjE1ODIxOTc0MTgsImlzcyI6IjU4NWFkOTY0ZGE1MjkzNjIyMDg5OTY5YSIsIk9yZ1VuaXRJZCI6IjU3OTA4YjhlMzNmYWRkNTQ4ODRiNjcxZCIsIlJlZmVyZW5jZUlkIjoiMmJkMzYzZGQyNjQyNDU0OTlmNjZjN2Q1YWY3ODdkZTkiLCJleHAiOjE1ODIyMDQ2MTh9.gzjxFuAFj6WUYdjlxm_qppaiwqkbAiakvimprTi5tgw”
}
Note: The nonce obtained has an expiration period associated with it. Currently, the expiration duration is set as 300 seconds. But this expiration period can vary from time to time based on security requirements. If the nonce times out, you will receive an InvalidLoginError(50002) as a response for subsequent calls. If that occurs, the webstore can make a new server to server authentication call to get a new nonce.
The webstore must capture the response and send the information to the browser. Two pieces of information in the nonce generation response are required for the JavaScript library: the nonce and the jwt. The webstore must ensure these two elements are available in the browser.
In case of error, the payload below is returned:
{
"error_code" : "50002",
"error_message" : "InvalidLoginError",
}
Below is a list of possible errors that can be returned.
Error Code | Error Message | Description |
---|---|---|
50002 | InvalidLoginError | The nonce used to connect to Radial is invalid or timed out. Renew the nonce and try again. |
50003 | RadialInternalError | There was an internal error in Radial's system. |
The following code snippet generates the nonce.
public class RestCallClient {
public static void main(String[] args) {
try {
URL url = new URL("https://tst.payments.radial.com/hosted-payments/auth/nonce");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json");
String input = "{\n" +
"\t\"username\": \"username\",\n" +
"\t\"password\" : \"password\",\n" +
"}";
OutputStream os = conn.getOutputStream();
os.write(input.getBytes());
os.flush();
System.out.println(conn.getResponseCode());
BufferedReader br = new BufferedReader(new InputStreamReader(
(conn.getInputStream())));
StringBuilder builder = new StringBuilder();
String output;
System.out.println("Output from Server .... \n");
while ((output = br.readLine()) != null) {
System.out.println(output);
builder.append(output);
}
System.out.println(builder);
JSONObject jsonObject = new JSONObject(builder.toString());
System.out.println(jsonObject.getString("nonce"));
conn.disconnect();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Step #2: Download radial_payments.js and Initialize JavaScript
Radial hosts a JavaScript file, radial_payments.js, which provides the tokenization functionality. The nonce received in Step #1 is necessary for subsequent JavaScript calls from the browser. The webstore should download the radial_payments.js file using the script tag when the customer navigates to the checkout page. After downloading the radial_payments.js file, the webstore should invoke the Radial.setup() method by passing the nonce as illustrated in the following example. In other words, Radial.setup() should be invoked in the checkout page onload event.
<head>
<script src="http://tst.payments.radial.com/hosted-payments/radial_payments.js"></script>
<script language="JavaScript">
function loadNonce() {
Radial.setup('<%=request.getAttribute("nonce")%>', '<%=request.getAttribute("jwt")%>');
}
</script>
</head>
<body onload="loadNonce()">
Integration Flow
The sequence diagram below shows the series of system interactions in 3DS Tokenization.
- The browser requests payment page to the webstore server
- The webstore server sends a request to Radial with userid and password.
- The webstore server receives nonce and jwt in Radial's response.
- The webstore server provides the payment page along with jwt and nonce, which are used to initialize the JavaScript (with the Radial.setup() method). The webstore server should invoke the Radial.setup() javascript method during the checkout page onload().
- The user enters their card details, and the browser sends a 3DS request to Radial.(Radial.tokenizeAndAuthorize())
- Radial makes a prelude request to the 3D Secure Verification Provider.
- Radial receives a prelude response from the 3D Secure Verification Provider.
- Radial provides the prelude response to the browser.
- The browser (JavaScript) 3DS authentication call is invoked.
- The issuer 3DS popup is displayed. The user enters their authentication password. In case of ghost authentication, the popup does not show.
- The authentication popup is submitted and verified by issuer.
- The response provided by the JavaScript contains the 3D Secure status results.
- The payment page is submitted with the 3DS results.
- The webstore collects the 3DS results and includes them in a payment credit card auth request.
Step #3: Accept Card Data and Invoke Authentication for Saved Token
This is a case where the webstore already has a saved token and just needs to perform 3DS authentication. The webstore client code should call Radial's javascript method 'Radial.authorizeSavedToken()', passing in the tokenized pan number and orderData as a jsonObject like below:
Radial.authorizeSavedToken('account_token', jsonObject, authorizeSavedTokenCallbackHandler);
The json object format passed here is the same as in the previous use case.
Sample jsonObject Request with Mandatory elements.
{
"cmpiRequestObject": {
"OrderNumber": "12345678",
"CurrencyCode": "USD",
"Amount": "500",
"CardExpMonth": "01",
"CardExpYear" : "2020",
"EMail": "johnconsumer@consumerdomain.com",
"BillingFirstName": "John",
"BillingLastName": "Consumer",
"BillingAddress1": "123 Main Street",
"BillingCity": "Cleveland",
"BillingCountryCode": "US",
"BillingPhone": "2162162116",
"ShippingFirstName": "John",
"ShippingLastName": "Consumer",
"ShippingAddress1": "123 Main Street",
"ShippingCity": "Cleveland",
"ShippingCountryCode": "US",
"ShippingPostalCode": "44111",
"ShippingPhone": "2162162116",
"ShippingPhone": "2162162116",
"IPAddress": "0:0:0:0:0:0:0:1"
}
}
Radial handles the handshake with the 3DS provider and redirects the browser to a 3DS authentication window. The user is prompted for authentication information.
Upon completion of the process, call the tokenizeAndAuthorizeCallbackHandler. The webstore must implement a tokenizeAndAuthorizeCallbackHandler() JavaScript method and call it when the Radial.tokenizeAndAuthorize() call receives a response.
SUCCESS and NOACTION action codes indicate everything is good with the card and the webstore can proceed with the transaction. The webstore can handle the response as shown below.
<script language="javascript">
authorizeSavedTokenCallbackHandler(data) {
switch(data.ActionCode){
case "SUCCESS":
// Handle successful authentication scenario
break;
case "NOACTION":
// Handle unenrolled scenario (treat same as success)
break;
case "FAILURE":
// Handle authentication failed or error encounter scenario
break;
case "ERROR":
// Handle service level error
break;
}
</script>
Response Format
The response object returned in the callback handler is in json format and in general has the format shown in the following example.
{
"Validated": false,
"Payment": {
"Type": "CCA",
"ProcessorTransactionId": "dk5O2XPRJ6MXMdf2Drv0",
"ExtendedData": {
"CAVV": "",
"ECIFlag": "07",
"XID": "ZGs1TzJYUFJKNk1YTWRmMkRydjA=",
"PAResStatus": "N",
"SignatureVerification": "Y"
}
},
"ActionCode": "SUCCESS",
"ErrorNumber": 0,
"ErrorDescription": "Success"
}
The 3DS fields you are required to capture can be found within the nested ExtendedData object. The JSON fields that matter are the ExtendedData object, ActionCode and Error code. The rest of the fields are present for informational purposes and can be safely ignored.
In case of failure, it could be because of an invalid credit card number or a number that failed a luhn check. The webstore can prompt the user to correct the error and retry the request.
Below is a list of possible failures that can be returned:
Error Code | Error Message | Description |
---|---|---|
40001 | TokenNotFoundException | The account number passed in was not numeric |
40005 | Incomplete3dsData | The json object passed in does not have all the required fields. |
40006 | TokenNotFoundException | When the token passed in does not exist in Radial System. |
40007 | Authentication failure/Signature verification failure. | When user authentication in the 3DS challenge popup fails or there is a signature verification failure at 3D Secure Verification Provider end. |
Some errors can be caused by an issue on the network or with one of Radial's internal services. If one of these errors is returned, the webstore can implicitly retry the request without user intervention. The following errors fall into this category.
Error Code | Error Message | Description |
---|---|---|
50001 | TimeoutError | There was a time out attempting to contact Radial's payment service |
50002 | NonceTimedoutError | The nonce used to connect to Radial is invalid or timed out. Get a fresh nonce and try again. |
50003 | RadialInternalError | There was an internal error in Radial's system. |
50004 | InvalidJWTError | The JWT used to connect to Radial is invalid. Get a fresh JWT and try again. |
50005 | 3dsGatewayTimeoutError | The 3DS gateway timed out. At this point, the webstore can choose to take the order without 3DS authentication if it wishes or retry the authentication again. |
50006 | 3dsGatewayInternalError | There was an internal with the 3DS gateway. |
It is suggested that the client can bypass 3DS and proceed with order checkout in all 5000* error cases except during InvalidLoginError and NonceTimeoutError (50002) scenarios.
Testing JavaScript API Integration
Radial offers a set of mock card numbers that can be used when testing your integration with Radial's JavaScript APIs. For details, see Testing JavaScript API Integration.