3DS2 SDK process
The diagram below shows the 3DS2 SDK payment process.
Be aware that many issuers' ACS don't work properly with 3DS Mobile SDKs.
- Client creates an Order
- Mobile Server registers that order in Payment Gateway via register.do.
- Mobile Server receives a unique order number
mdOrder
in response. - Client fills in payment data
- Mobile App sends payment data to Mobile Server
- Mobile Server uses that payment data to make a payment via paymentorder.do request
- Send
threeDSSDK=true
to indicate that 3DS2 SDK should be used
- Send
- Mobile Server gets a response with no ACS keys. It means that payment is completed and we need to go to step 22
- Mobile Server gets a response with ACS keys.
- Response must contain
threeDSServerTransId
andthreeDSSDKKey
- Response should not contain
threeDSMethodURL
which is used in case of browser based redirect to ACS
- Response must contain
- Mobile Server sends 3DS2 SDK data to Mobile App
- Mobile App initiates 3DS2 SDK via
createTransaction
method-
directoryServerID
depends on Payment System (for tests A000000003 can be used) -
messageVersion
is 2.1.0 for now -
pemPublicKey
for Android and for iOS is a pem certificate that is got in response inthreeDSSDKKey
on step 10 -
dsRoot
for Android and for iOS depends on Payment System. Download test key
-
- 3DS2 SDK collects device data and encrypts it
- Mobile App sends encrypted device data to Mobile Server
- Mobile Server initiates second payment API call via paymentorder.do request
-
sdkEncData
encrypted device data that is returned increateTransaction
method in 3DS2 SDK -
threeDSSDKReferenceNumber
3DS2 SDK officially ids. Don't hardcode them. iOS: 3DS_LOA_SDK_BPBT_020100_00233, Android: 3DS_LOA_SDK_BPBT_020100_00231 -
threeDSServerTransactionID
it's returned in response to first payment call on step 10 inthreeDSServerTransId
parameter -
sdkEphemPubKey
it is returned increateTransaction
method in 3DS2 SDK -
sdkAppID
it is returned increateTransaction
method in 3DS2 SDK -
sdkTransID
it is returned increateTransaction
method in 3DS2 SDK
-
- Payment Gateway returns new special parameters for 3DS2 SDK
- Mobile Server sends those parameters to Mobile App
- Mobile App initiates challenge flow via
doChallenge
method- doChallenge
acsTransactionID
parameter corresponds tothreeDSAcsTransactionId
in Payment Gateway response - doChallenge
acsRefNumber
parameter corresponds tothreeDSAcsRefNumber
in Payment Gateway response - doChallenge
acsSignedContent
parameter corresponds tothreeDSAcsSignedContent
in Payment Gateway response - doChallenge
3DSServerTransactionID
parameter corresponds tothreeDSServerTransId
in Payment Gateway response
- doChallenge
- 3DS2 SDK communicates with issuers ACS via CReq/CRes API until Client confirms his payment
- ACS sends RReq to Payment Gateway to confirm or reject the payment
- 3DS2 SDK informs Mobile App that 3DS2 flow is over via
ChallengeStatusReceiver
- Mobile Server finalizes the payment with finish3dsVer2Payment.do
- Payment Gateway makes a payment
- Payment Gateway sends callback notification to Merchant server if it's configured for merchant
- Mobile Server checks the final payment status via getOrderStatusExtended.do
- Mobile App shows payment result to client
IOS
For integration SDK ThreeDS:
- Download and add ThreeDSSDK.xcframework in a project;

- Mark ThreeDSSDK.xcframework as
Embed & Sign
in tagrete -> general;

- Example ThreeDSSDK
Full example you can find: TransactionManager
import UIKit
import ThreeDSSDK....
var _service: ThreeDS2Service = Ecom3DS2Service()
// Init ThreeDS SDK
try _service.initialize(configParameters: ConfigParameters(), locale: Locale.current.languageCode, uiCustomization: _setUpTheme())
var _sdkTransaction = try _service.createTransaction(directoryServerID: "", messageVersion: nil, publicKeyBase64: "", rootCertificateBase64: "", logoBase64: "")
// get progress view
var _sdkProgressDialog = try _sdkTransaction!.getProgressView()
// Show progress dialog
_sdkProgressDialog?.show()
// get authentication request parameters, to be sent to the payment gateway
var authParameters = _sdkTransaction!.getAuthenticationRequestParameters()
var deviceData = authParameters.getDeviceData()
var ephemeralPublickKey = authParameters.getSDKEphemeralPublicKey()
var threeDSSDKAppId = authParameters.getSDKAppID()
var threeDSSDKTransId = authParameters.getSDKTransactionID()
// if you get error during initial sdk, you can close spinner.
// _sdkProgressDialog?.close()
// Set challenge parameters and start challenge flow
let challengeParameters = ChallengeParameters()
challengeParameters.setAcsSignedContent("acsSignedContent")
challengeParameters.setAcsRefNumber("acsReferenceNumber")
challengeParameters.setAcsTransactionID("acsTransID")
challengeParameters.set3DSServerTransactionID("threeDSServerTransID")
// Start challenge flow
self._sdkTransaction?.doChallenge(challengeParameters: challengeParameters, challengeStatusReceiver: self, timeOut: 5)
// If you get error during sdk flow, you can finish sdk transaction
// _sdkTransaction?.close()
// Delegate functions
extension TransactionManager: ChallengeStatusReceiver {
public func completed(completionEvent e: CompletionEvent) {}
public func cancelled() {}
public func timedout() {}
public func protocolError(protocolErrorEvent e: ProtocolErrorEvent) {}
public func runtimeError(runtimeErrorEvent: RuntimeErrorEvent) {}
}
Android
Logging
Internal processes are logged with SDK-ThreeDS
tag.
Also you can log your processes.
Logging is available through the class ThreeDSLogger
which has an instance available through static field INSTANCE
.
- To add log- interfaces you should call ThreeDSLogger
-method addLogInterface()
.
For example to log into LogCat:
...
ThreeDSLogger.INSTANCE.addLogInterface(object : net.payrdr.mobile.payment.sdk.threeds.LogInterface {
override fun log(classMethod: Class<*>, tag: String, message: String, p3: Throwable?) {
Log.i(tag, "$classMethod: $message")
}
})
...
The default is the tag SDK-ThreeDS
. You can set your own one if you like.
-
To log own events you should call
Logger
-methodlog()
.For example:
...
ThreeDSLogger.INSTANCE.log(this.javaClass, "MyTag", "My process", null)
...
Example of payment with 3DS
Connecting the 3DS2 library
You need to add the sdk_threeds-release.aar
library file to the libs
folder, then specify the
dependency on the added library.
In SDK versions <= 2.5.5 add the sdk_listeners_android.jar
file to the libs
folder. Since SDK
2.5.6 there is no need to add the sdk_listeners_android.jar
file.
build.gradle.kts
allprojects {
repositories {
// ...
flatDir {
dirs("libs")
}
}
}dependencies {
// dependency for connecting the confirmation functionality via 3DS
implementation(group = "", name = "sdk_threeds-release", ext = "aar")
implementation("com.google.code.gson:gson:2.8.5")
implementation("com.squareup.okhttp3:okhttp:3.11.0")
implementation("com.google.android.gms:play-services-ads:17.2.1")
implementation("com.google.android.gms:play-services-location:16.0.0")
}
build.gradle
allprojects {
repositories {
// ...
flatDir {
dirs 'libs'
}
}
}dependencies {
// dependency for connecting the confirmation functionality via 3DS
implementation(group = "", name = "sdk_threeds-release", ext = "aar")
implementation("com.google.code.gson:gson:2.8.5")
implementation("com.squareup.okhttp3:okhttp:3.11.0")
implementation("com.google.android.gms:play-services-ads:17.2.1")
implementation("com.google.android.gms:play-services-location:16.0.0")
}
Payment execution with confirmation via 3DS2
private val factory = Factory()threeDS2Service = factory.newThreeDS2Service()
val configParams = factory.newConfigParameters()
val uiCustomization = factory.newUiCustomization()
threeDS2Service.initialize(
context,
configParams,
"en-US",
uiCustomization,
sslContext, // Optional field (needs if you want to pass a custom SSL certificate)
trustManager, // Optional field (needs if you want to pass a custom SSL certificate)
)
// An example of creating a transaction with custom SSL certificate.
// To create a transaction with a custom certificate, you need to create an SSLContext object and a TrustManager.
// Then pass it to initialize method of threeDS2Service.
// Both (sslContext and trustManager) parameters must be passed, or neither (they are optional).
//
// threeDS2Service.initialize(
// context,
// configParams,
// "en-US",
// uiCustomization,
// sslContext, // Optional field
// trustManager, // Optional field
// )
val dsRoot: String = "MII346GU349HDE5FH..." //your root-certificate in base64 format
val transaction = threeDS2Service.createTransaction("F000000000", "", "2.1.0", dsRoot)
// An example of creating a transaction with deviceInfo encryption with a transmitted RSA key.
// val rsaPem: String = ...
// val dsRoot: String = ...
// transaction = threeDS2Service.createTransaction(
// "",
// rsaPem,
// "2.1.0",
// dsRoot
// )
// An example of creating a transaction with deviceInfo encryption with a transmitted EC key.
// val ecPem: String = ...
// val directoryServerID: String = ...
// val dsRoot: String = ...
// transaction = threeDS2Service.createTransaction(
// directoryServerID,
// ecPem,
// "2.1.0",
// dsRoot
// )
// Available data, to be sent to the payment gateway
val authRequestParams = transaction.authenticationRequestParameters!!
val encryptedDeviceInfo: String = authRequestParams.deviceData
val sdkTransactionID: String = authRequestParams.sdkTransactionID
val sdkAppId: String = authRequestParams.sdkAppID
val sdkEphmeralPublicKey: String = authRequestParams.sdkEphemeralPublicKey
val sdkReferenceNumber: String = authRequestParams.sdkReferenceNumber
val challengeParameters = factory.newChallengeParameters()
// Parameters for starting Challenge Flow.
challengeParameters.acsTransactionID =
paymentOrderSecondStepResponse.threeDSAcsTransactionId
challengeParameters.acsRefNumber = paymentOrderSecondStepResponse.threeDSAcsRefNumber
challengeParameters.acsSignedContent =
paymentOrderSecondStepResponse.threeDSAcsSignedContent
challengeParameters.set3DSServerTransactionID(paymentOrderResponse.threeDSServerTransId)
// Listener to handle the Challenge Flow execution process.
val challengeStatusReceiver: ChallengeStatusReceiver = object : ChallengeStatusReceiver {
override fun cancelled() {}
override fun protocolError(protocolErrorEvent: ProtocolErrorEvent) {}
override fun runtimeError(runtimeErrorEvent: RuntimeErrorEvent) {}
override fun completed(completionEvent: CompletionEvent) {}
override fun timedout() {}
}
val timeOut = 5
// Starting Challenge Flow.
transaction.doChallenge(
activity,
challengeParameters,
challengeStatusReceiver,
timeOut
)
You can see a complete code sample in the
file net.payrdr.mobile.payment.sample.kotlin.threeds.ThreeDSActivity
.
Features of app self-test with connected 3DS2
When initializing the ThreeDS2Service
, the application performs a series of self-compromising
checks. The list with warnings is returned using the ThreeDS2Service.getWarnings
method If there
are no warnings, an empty list is returned.
The list of checks includes:
1) Checking root access on the device (according to rule SW01
)
* It returns a warning when triggered The device is rooted
.
2) Checking to install the app only from approved app stores (according to rule SW02
)
* It returns a warning when triggered The integrity of the SDK has been tampered
.
* By default, sdk allows installation of the application only from the Play Market.
* If it is necessary to add other markets (for example, App Gallery), they can be passed
to configParams
.
val factory = Factory()
val threeDS2Service = factory.newThreeDS2Service()
val configParams = factory.newConfigParameters()
val trustedAppStores = listOf<String>("com.android.vending", "com.huawei.appmarket")configParams.removeParam("security", "trustedAppStores")
configParams.addParam("security", "trustedAppStores", StringUtils.makeString(trustedAppStores))
3) Checking application signature mismatch (according to rule SW02
)
* It returns a warning when triggered The integrity of the SDK has been tampered.
* An example of passing a signature in configParams
:
val factory = Factory()
val threeDS2Service = factory.newThreeDS2Service()
val configParams = factory.newConfigParameters()
val youAppSignature = //signature of your application configParams.removeParam("security", "appSignature")
configParams.addParam("security", "appSignature", youAppSignature)
4) Checking for malicious applications on the device (according to rule SW02
)
* It returns a warning when triggered The integrity of the SDK has been tampered
.
* By default, applications with the following package names are denied:
* de.robv.android.xposed
* de.robv.android.xposed.installer
* com.saurik.substrate
* If it is necessary to set your own list of prohibited applications, the names of their
packages can be passed to configParams
.
val factory = Factory()
val threeDS2Service = factory.newThreeDS2Service()
val configParams = factory.newConfigParameters()
val maliciousApps = listOf<String>("com.zhiliaoapp.musically", "com.othersapp.harmful")configParams.removeParam("security", "maliciousApps")
configParameters.addParam("security", "maliciousApps", StringUtils.makeString(maliciousApps))
5) Checking to run the application from under the emulator (according to rule SW03
)
* It returns a warning when triggered An emulator is being used to run the App
.
6) Checking for the presence of a debugger connected to the application (according to rule SW04
)
* It returns a warning when triggered A debugger is attached to the App
.
7) Checking that the Android version is up-to-date (according to rule SW05
)
* It returns a warning when triggered The OS or the OS version is not supported.
* Versions over API 16 (JELLY BEAN) are considered to be up-to-date (safe)
Under documentation/threeds
you can find more information describing the
available ConfigParameters
and
UiCustomization
parameters to customize the 3DS screen, as well as a description of the 3DS SDK
server application interaction process
Example of a confirmation code input screen:
3DS2 stub
3DS2 stub can be used with the SDK. SDK screens depend on the order amount in 3DS2 stub
Radio group
Amount: 111
Multiple choice
Amount: 222
Web (embedded HTML)
Amount: 333
One-Time password
Amount: any other