3DS / Non-3DS payment
3D-Secure is authentication protocol for e-commerce transaction where card is not present on time of the purchase. Initially developed by VISA and known as Verified by VISA. 3D-Secure is adapted by all the major card schemes such as MasterCard, Amex, JCB and Discovery.
Here are 5 steps to make a successful credit card payment:
- Step 1: Get payment token.
- Step 2: Construct credit card request.
- Step 3: Construct transaction request.
- Step 4: Execute payment request.
- Step 5: Authentication handling for 3DS payment.
- Step 6: Get payment result.
Merchant server implementation : Download
Payment Token API
Please refer: Full sample code
Enable / Disable / Force 3DS
Set payment option
$request_3ds = CardSecureMode::YES;
Construct payment token request
$payment_token_request = new stdClass();
$payment_token_request->version = $api_version;
$payment_token_request->merchantID = $mid;
$payment_token_request->invoiceNo = $invoice_no;
$payment_token_request->desc = $desc;
$payment_token_request->amount = $amount;
$payment_token_request->currencyCode = $currency_code;
$payment_token_request->request3DS = $request_3ds;
$payment_token_request->nonceStr = $nonce_str;
Set payment token
String paymentToken = "roZG9I1hk/GYjNt+BYPYbxQtKElbZDs9M5cXuEbE+Z0QTr/yUcl1oG7t0AGoOJlBhzeyBtf5mQi1UqGbjC66E85S4m63CfV/awwNbbLbkxsvfgzn0KSv7JzH3gcs/OIL";
let paymentToken:String = "roZG9I1hk/GYjNt+BYPYbxQtKElbZDs9M5cXuEbE+Z0QTr/yUcl1oG7t0AGoOJlBhzeyBtf5mQi1UqGbjC66E85S4m63CfV/awwNbbLbkxsvfgzn0KSv7JzH3gcs/OIL"
NSString *paymentToken = @"roZG9I1hk/GYjNt+BYPYbxQtKElbZDs9M5cXuEbE+Z0QTr/yUcl1oG7t0AGoOJlBhzeyBtf5mQi1UqGbjC66E85S4m63CfV/awwNbbLbkxsvfgzn0KSv7JzH3gcs/OIL";
2C2P PGW SDK:
Step 2: Construct credit card request.
CreditCardPayment creditCardPayment = new CreditCardPaymentBuilder("4111111111111111")
.setExpiryMonth(12)
.setExpiryYear(2019)
.setSecurityCode("123")
.build();
let creditCardPayment:CreditCardPayment = CreditCardPaymentBuilder(pan: "4111111111111111")
.expiryMonth(12)
.expiryYear(2019)
.securityCode("123")
.build()
CreditCardPayment *creditCardPayment = [[[[[[CreditCardPaymentBuilder alloc]
initWithPan:@"4111111111111111"]
expiryMonth:12]
expiryYear:2019]
securityCode:@"123"]
build];
Step 3: Construct transaction request.
TransactionRequest transactionRequest = new TransactionRequestBuilder(paymentToken)
.withCreditCardPayment(creditCardPayment)
.build();
let transactionRequest:TransactionRequest = TransactionRequestBuilder(paymentToken: paymentToken)
.withCreditCardPayment(creditCardPayment)
.build()
TransactionRequest *transactionRequest = [[[[TransactionRequestBuilder alloc]
initWithPaymentToken:paymentToken]
withCreditCardPayment:creditCardPayment]
build];
Step 4: Execute payment request.
PGWSDK.getInstance().proceedTransaction(transactionRequest, new TransactionResultCallback() {
@Override
public void onResponse(TransactionResultResponse response) {
//For 3DS
if(response.getResponseCode().equals(APIResponseCode.TRANSACTION_AUTHENTICATE)) {
String redirectUrl = response.getRedirectUrl();
openWebviewFragment(redirectUrl); //Open WebView for 3DS
} else if(response.getResponseCode().equals(APIResponseCode.TRANSACTION_COMPLETED)) {
//Inquiry payment result by using transaction id.
String transactionID = response.getTransactionID();
} else {
//Get error response and display error
}
}
@Override
public void onFailure(Throwable error) {
//Get error response and display error
}
});
PGWSDK.shared.proceedTransaction(transactionRequest: transactionRequest,
success: { (response:TransactionResultResponse) in
//For 3DS
if response.responseCode == APIResponseCode.TRANSACTION_AUTHENTICATE {
let redirectUrl:String = response.redirectUrl!
self.openWebViewController(redirectUrl) //Open WebView for 3DS
} else if response.responseCode == APIResponseCode.TRANSACTION_COMPLETED {
//Inquiry payment result by using transaction id.
let transactionID:String = response.transactionID!
} else {
//Get error response and display error
}
}) { (error:NSError) in
//Get error response and display error
}
[[PGWSDK shared] proceedTransactionWithTransactionRequest:transactionRequest
success:^(TransactionResultResponse * _Nonnull response) {
//For 3DS
if ([response.responseCode isEqualToString:APIResponseCode.TRANSACTION_AUTHENTICATE]) {
NSString *redirectUrl = response.redirectUrl;
[self openWebViewController:redirectUrl]; //Open WebView for 3DS
} else if ([response.responseCode isEqualToString:APIResponseCode.TRANSACTION_COMPLETED]) {
//Inquiry payment result by using transaction id.
NSString *transactionID = response.transactionID;
} else {
//Get error response and display error
}
} failure:^(NSError * _Nonnull error) {
//Get error response and display error
}];
Step 5: Authentication handling for 3DS payment.
Load authentication redirect URL.
public class WebViewFragment extends Fragment {
//...
@Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState) {
WebView webview = new WebView(getActivity());
webview.getSettings().setJavaScriptEnabled(true);
webview.setWebViewClient(new PGWWebViewClient());
webview.addJavascriptInterface(new PGWJavaScriptInterface(mTransactionResultCallback),
PGWJavaScriptInterface.JAVASCRIPT_TRANSACTION_RESULT_KEY);
webview.loadUrl(mRedirectUrl);
return webview;
}
}
//For UIWebView implementation
class UIWebViewController: UIViewController {
//…
override func viewDidLoad() {
super.viewDidLoad()
//Authentication handling for 3DS payment
let requestUrl:URL = URL.init(string: self.redirectUrl!)!
let request:URLRequest = URLRequest.init(url: requestUrl)
self.webView = UIWebView(frame: UIScreen.main.bounds)
self.webView.delegate = self.transactionResultCallback()
self.webView.loadRequest(request)
self.view.addSubview(self.webView)
}
}
//For WKWebView implementation
class WKWebViewController: UIViewController {
//…
override func viewDidLoad() {
super.viewDidLoad()
//Authentication handling for 3DS payment
let requestUrl:URL = URL.init(string: self.redirectUrl!)!
let request:URLRequest = URLRequest.init(url: requestUrl)
let webConfiguration = WKWebViewConfiguration()
self.webView = WKWebView(frame: UIScreen.main.bounds, configuration: webConfiguration)
self.webView.navigationDelegate = self.transactionResultCallback()
self.webView.load(request)
self.view.addSubview(self.webView)
}
}
//For UIWebView implementation
@implementation UIWebViewController
- (void)viewDidLoad {
[super viewDidLoad];
//Authentication handling for 3DS payment
NSURL *requestUrl = [[NSURL alloc] initWithString:self.redirectUrl];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:requestUrl];
self.webView = [[UIWebView alloc] initWithFrame: UIScreen.mainScreen.bounds];
self.webView.delegate = [self transactionResultCallback];
[self.webView loadRequest:request];
[self.view addSubview:self.webView];
}
@end
//For WKWebView implementation
@implementation WKWebViewController
- (void)viewDidLoad {
[super viewDidLoad];
//Authentication handling for 3DS payment
NSURL *requestUrl = [[NSURL alloc] initWithString:self.redirectUrl];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:requestUrl];
WKWebViewConfiguration *webConfiguration = [[WKWebViewConfiguration alloc] init];
self.webView = [[WKWebView alloc] initWithFrame:UIScreen.mainScreen.bounds
configuration:webConfiguration];
self.webView.navigationDelegate = [self transactionResultCallback];
[self.webView loadRequest:request];
[self.view addSubview:self.webView];
}
@end
Get result transaction ID.
private TransactionResultCallback mTransactionResultCallback = new TransactionResultCallback() {
@Override
public void onResponse(TransactionResultResponse response) {
if(response.getResponseCode().equals(APIResponseCode.TRANSACTION_COMPLETED)) {
//Inquiry payment result by using transaction id.
String transactionID = response.getTransactionID();
} else {
//Get error response and display error
}
}
@Override
public void onFailure(Throwable error) {
//Get error response and display error
}
};
//For UIWebView implementation
func transactionResultCallback() -> PGWUIWebViewDelegate {
self.pgwWebViewDelegate = PGWUIWebViewDelegate(
success: { (response: TransactionResultResponse) in
if response.responseCode == APIResponseCode.TRANSACTION_COMPLETED {
//Inquiry payment result by using transaction id.
let transactionID:String = response.transactionID!
} else {
//Get error response and display error
}
}, failure: { (error: NSError) in
//Get error response and display error
})
return self.pgwWebViewDelegate
}
//For WKWebView implementation
func transactionResultCallback() -> PGWWKWebViewDelegate {
self.pgwWebViewDelegate = PGWWKWebViewDelegate(
success: { (response: TransactionResultResponse) in
if response.responseCode == APIResponseCode.TRANSACTION_COMPLETED {
//Inquiry payment result by using transaction id.
let transactionID:String = response.transactionID!
} else {
//Get error response and display error
}
}, failure: { (error: NSError) in
//Get error response and display error
})
return self.pgwWebViewDelegate
}
//For UIWebView implementation
- (PGWUIWebViewDelegate *)transactionResultCallback {
self.pgwWebViewDelegate = [[PGWUIWebViewDelegate alloc]
initWithSuccess:^(TransactionResultResponse * _Nonnull response) {
if ([response.responseCode isEqualToString:APIResponseCode.TRANSACTION_COMPLETED]) {
//Inquiry payment result by using transaction id.
NSString *transactionID = response.transactionID;
} else {
//Get error response and display error
}
} failure:^(NSError * _Nonnull error) {
//Get error response and display error
}];
return self.pgwWebViewDelegate;
}
//For WKWebView implementation
- (PGWWKWebViewDelegate *)transactionResultCallback {
self.pgwWebViewDelegate = [[PGWWKWebViewDelegate alloc]
initWithSuccess:^(TransactionResultResponse * _Nonnull response) {
if ([response.responseCode isEqualToString:APIResponseCode.TRANSACTION_COMPLETED]) {
//Inquiry payment result by using transaction id.
NSString *transactionID = response.transactionID;
} else {
//Get error response and display error
}
} failure:^(NSError * _Nonnull error) {
//Get error response and display error
}];
return self.pgwWebViewDelegate;
}
Payment Inquiry API
Please refer: Full sample code
Complete Code
Merchant Server:
Copy & Paste below source code and put this file in your Web Server.
<?php
//Import necessary classes
require "../utils/PaymentGatewayHelper.php";
require "../enum/APIEnvironment.php";
require "../model/SignatureError.php";
require "enum/CardSecureMode.php";
require "enum/PaymentChannel.php";
//Set API request enviroment
$api_env = APIEnvironment::SANDBOX . "/paymentToken";
//Request information
$api_version = "10.01";
$nonce_str = uniqid('', true);
//Merchant's account information
$mid = "JT01"; //Get MerchantID when opening account with 2C2P
$secret_key = "7jYcp4FxFdf0"; //Get SecretKey from 2C2P PGW dashboard
//Transaction information
$desc = "2 days 1 night hotel room";
$invoice_no = time();
$currency_code = "SGD";
$amount = "000000001000";
//Set payment options
$request_3ds = CardSecureMode::YES; //Set 3D Secure
//Build payment token request
$payment_token_request = new stdClass();
$payment_token_request->version = $api_version;
$payment_token_request->merchantID = $mid;
$payment_token_request->invoiceNo = $invoice_no;
$payment_token_request->desc = $desc;
$payment_token_request->amount = $amount;
$payment_token_request->currencyCode = $currency_code;
$payment_token_request->request3DS = $request_3ds;
$payment_token_request->nonceStr = $nonce_str;
//Important: Generate signature
$pgw_helper = new PaymentGatewayHelper();
$hashed_signature = $pgw_helper->generateSignature($payment_token_request, $secret_key);
$payment_token_request->signature = $hashed_signature;
//Do Payment Token API request
$encoded_payment_token_response = $pgw_helper->requestAPI($api_env, $payment_token_request);
//Important: Verify response signature
$is_valid_signature = $pgw_helper->validateSignature($encoded_payment_token_response, $secret_key);
if($is_valid_signature) {
//Valid signature, get payment result
$payment_token_response = $pgw_helper->parseAPIResponse($encoded_payment_token_response);
echo $payment_token = $payment_token_response->paymentToken;
} else {
//Invalid signature, return error response
}
?>
2C2P PGW SDK:
Copy & Paste below source code into your application.
Proceed credit card payment.
String paymentToken = "roZG9I1hk/GYjNt+BYPYbxQtKElbZDs9M5cXuEbE+Z0QTr/yUcl1oG7t0AGoOJlBhzeyBtf5mQi1UqGbjC66E85S4m63CfV/awwNbbLbkxsvfgzn0KSv7JzH3gcs/OIL";
//Construct credit card request
CreditCardPayment creditCardPayment = new CreditCardPaymentBuilder("4111111111111111")
.setExpiryMonth(12)
.setExpiryYear(2019)
.setSecurityCode("123")
.build();
//Construct transaction request
TransactionRequest transactionRequest = new TransactionRequestBuilder(paymentToken)
.withCreditCardPayment(creditCardPayment)
.build();
//Execute payment request
PGWSDK.getInstance().proceedTransaction(transactionRequest, new TransactionResultCallback() {
@Override
public void onResponse(TransactionResultResponse response) {
//For 3DS
if(response.getResponseCode().equals(APIResponseCode.TRANSACTION_AUTHENTICATE)) {
String redirectUrl = response.getRedirectUrl();
openWebviewFragment(redirectUrl); //Open WebView for 3DS
} else if(response.getResponseCode().equals(APIResponseCode.TRANSACTION_COMPLETED)) {
//Inquiry payment result by using transaction id.
String transactionID = response.getTransactionID();
} else {
//Get error response and display error
}
}
@Override
public void onFailure(Throwable error) {
//Get error response and display error
}
});
let paymentToken:String = "roZG9I1hk/GYjNt+BYPYbxQtKElbZDs9M5cXuEbE+Z0QTr/yUcl1oG7t0AGoOJlBhzeyBtf5mQi1UqGbjC66E85S4m63CfV/awwNbbLbkxsvfgzn0KSv7JzH3gcs/OIL"
//Construct credit card request
let creditCardPayment:CreditCardPayment = CreditCardPaymentBuilder(pan: "4111111111111111")
.expiryMonth(12)
.expiryYear(2019)
.securityCode("123")
.build()
//Construct transaction request
let transactionRequest:TransactionRequest = TransactionRequestBuilder(paymentToken: paymentToken)
.withCreditCardPayment(creditCardPayment)
.build()
//Execute payment request
PGWSDK.shared.proceedTransaction(transactionRequest: transactionRequest,
success: { (response:TransactionResultResponse) in
//For 3DS
if response.responseCode == APIResponseCode.TRANSACTION_AUTHENTICATE {
let redirectUrl:String = response.redirectUrl!
self.openWebViewController(redirectUrl) //Open WebView for 3DS
} else if response.responseCode == APIResponseCode.TRANSACTION_COMPLETED {
//Inquiry payment result by using transaction id.
let transactionID:String = response.transactionID!
} else {
//Get error response and display error
}
}) { (error:NSError) in
//Get error response and display error
}
NSString *paymentToken = @"roZG9I1hk/GYjNt+BYPYbxQtKElbZDs9M5cXuEbE+Z0QTr/yUcl1oG7t0AGoOJlBhzeyBtf5mQi1UqGbjC66E85S4m63CfV/awwNbbLbkxsvfgzn0KSv7JzH3gcs/OIL";
//Construct credit card request
CreditCardPayment *creditCardPayment = [[[[[[CreditCardPaymentBuilder alloc]
initWithPan:@"4111111111111111"]
expiryMonth:12]
expiryYear:2019]
securityCode:@"123"]
build];
//Construct transaction request
TransactionRequest *transactionRequest = [[[[TransactionRequestBuilder alloc]
initWithPaymentToken:paymentToken]
withCreditCardPayment:creditCardPayment]
build];
//Execute payment request
[[PGWSDK shared] proceedTransactionWithTransactionRequest:transactionRequest
success:^(TransactionResultResponse * _Nonnull response) {
//For 3DS
if ([response.responseCode isEqualToString:APIResponseCode.TRANSACTION_AUTHENTICATE]) {
NSString *redirectUrl = response.redirectUrl;
[self openWebViewController:redirectUrl]; //Open WebView for 3DS
} else if ([response.responseCode isEqualToString:APIResponseCode.TRANSACTION_COMPLETED]) {
//Inquiry payment result by using transaction id.
NSString *transactionID = response.transactionID;
} else {
//Get error response and display error
}
} failure:^(NSError * _Nonnull error) {
//Get error response and display error
}];
Authentication handling for 3DS payment on (Fragment / Activity / UIViewController).
public class WebViewFragment extends Fragment {
private static final String ARG_REDIRECT_URL = "ARG_REDIRECT_URL";
private String mRedirectUrl;
public WebViewFragment() { }
public static WebViewFragment newInstance(String redirectUrl) {
WebViewFragment fragment = new WebViewFragment();
Bundle args = new Bundle();
args.putString(ARG_REDIRECT_URL, redirectUrl);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(getArguments() != null) {
mRedirectUrl = getArguments().getString(ARG_REDIRECT_URL);
}
}
@Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState) {
//Authentication handling for 3DS payment
WebView webview = new WebView(getActivity());
webview.getSettings().setJavaScriptEnabled(true);
webview.setWebViewClient(new PGWWebViewClient());
webview.addJavascriptInterface(new PGWJavaScriptInterface(mTransactionResultCallback),
PGWJavaScriptInterface.JAVASCRIPT_TRANSACTION_RESULT_KEY);
webview.loadUrl(mRedirectUrl);
return webview;
}
private TransactionResultCallback mTransactionResultCallback = new TransactionResultCallback() {
@Override
public void onResponse(TransactionResultResponse response) {
if(response.getResponseCode().equals(APIResponseCode.TRANSACTION_COMPLETED)) {
String transactionID = response.getTransactionID();
} else {
//Get error response and display error
}
}
@Override
public void onFailure(Throwable error) {
//Get error response and display error
}
};
}
//For UIWebView implementation
class UIWebViewController: UIViewController {
var webView: UIWebView!
var pgwWebViewDelegate:PGWUIWebViewDelegate!
var redirectUrl:String?
override func viewDidLoad() {
super.viewDidLoad()
//Authentication handling for 3DS payment
let requestUrl:URL = URL.init(string: self.redirectUrl!)!
let request:URLRequest = URLRequest.init(url: requestUrl)
self.webView = UIWebView(frame: UIScreen.main.bounds)
self.webView.delegate = self.transactionResultCallback()
self.webView.loadRequest(request)
self.view.addSubview(self.webView)
}
func transactionResultCallback() -> PGWUIWebViewDelegate {
self.pgwWebViewDelegate = PGWUIWebViewDelegate(
success: { (response: TransactionResultResponse) in
if response.responseCode == APIResponseCode.TRANSACTION_COMPLETED {
//Inquiry payment result by using transaction id.
let transactionID:String = response.transactionID!
} else {
//Get error response and display error
}
}, failure: { (error: NSError) in
//Get error response and display error
})
return self.pgwWebViewDelegate
}
}
//For WKWebView implementation
class WKWebViewController: UIViewController {
var webView:WKWebView!
var pgwWebViewDelegate:PGWWKWebViewDelegate!
var redirectUrl:String?
override func viewDidLoad() {
super.viewDidLoad()
//Authentication handling for 3DS payment
let requestUrl:URL = URL.init(string: self.redirectUrl!)!
let request:URLRequest = URLRequest.init(url: requestUrl)
let webConfiguration = WKWebViewConfiguration()
self.webView = WKWebView(frame: UIScreen.main.bounds, configuration: webConfiguration)
self.webView.navigationDelegate = self.transactionResultCallback()
self.webView.load(request)
self.view.addSubview(self.webView)
}
func transactionResultCallback() -> PGWWKWebViewDelegate {
self.pgwWebViewDelegate = PGWWKWebViewDelegate(
success: { (response: TransactionResultResponse) in
if response.responseCode == APIResponseCode.TRANSACTION_COMPLETED {
//Inquiry payment result by using transaction id.
let transactionID:String = response.transactionID!
} else {
//Get error response and display error
}
}, failure: { (error: NSError) in
//Get error response and display error
})
return self.pgwWebViewDelegate
}
}
//For UIWebView implementation
@interface UIWebViewController : UIViewController
@property (nonatomic, copy) NSString *redirectUrl;
@end
@interface UIWebViewController ()
@property (nonatomic, strong) UIWebView *webView;
@property (nonatomic, strong) PGWUIWebViewDelegate *pgwWebViewDelegate;
@end
@implementation UIWebViewController
- (void)viewDidLoad {
[super viewDidLoad];
//Authentication handling for 3DS payment
NSURL *requestUrl = [[NSURL alloc] initWithString:self.redirectUrl];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:requestUrl];
self.webView = [[UIWebView alloc] initWithFrame: UIScreen.mainScreen.bounds];
self.webView.delegate = [self transactionResultCallback];
[self.webView loadRequest:request];
[self.view addSubview:self.webView];
}
- (PGWUIWebViewDelegate *)transactionResultCallback {
self.pgwWebViewDelegate = [[PGWUIWebViewDelegate alloc]
initWithSuccess:^(TransactionResultResponse * _Nonnull response) {
if ([response.responseCode isEqualToString:APIResponseCode.TRANSACTION_COMPLETED]) {
//Inquiry payment result by using transaction id.
NSString *transactionID = response.transactionID;
} else {
//Get error response and display error
}
} failure:^(NSError * _Nonnull error) {
//Get error response and display error
}];
return self.pgwWebViewDelegate;
}
@end
//For WKWebView implementation
@interface WKWebViewController : UIViewController
@property (nonatomic, copy) NSString *redirectUrl;
@end
@interface WKWebViewController ()
@property (nonatomic, strong) WKWebView *webView;
@property (nonatomic, strong) PGWWKWebViewDelegate *pgwWebViewDelegate;
@end
@implementation WKWebViewController
- (void)viewDidLoad {
[super viewDidLoad];
//Authentication handling for 3DS payment
NSURL *requestUrl = [[NSURL alloc] initWithString:self.redirectUrl];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:requestUrl];
WKWebViewConfiguration *webConfiguration = [[WKWebViewConfiguration alloc] init];
self.webView = [[WKWebView alloc] initWithFrame:UIScreen.mainScreen.bounds
configuration:webConfiguration];
self.webView.navigationDelegate = [self transactionResultCallback];
[self.webView loadRequest:request];
[self.view addSubview:self.webView];
}
- (PGWWKWebViewDelegate *)transactionResultCallback {
self.pgwWebViewDelegate = [[PGWWKWebViewDelegate alloc]
initWithSuccess:^(TransactionResultResponse * _Nonnull response) {
if ([response.responseCode isEqualToString:APIResponseCode.TRANSACTION_COMPLETED]) {
//Inquiry payment result by using transaction id.
NSString *transactionID = response.transactionID;
} else {
//Get error response and display error
}
} failure:^(NSError * _Nonnull error) {
//Get error response and display error
}];
return self.pgwWebViewDelegate;
}
@end
Updated over 3 years ago