SDK Core process
Web View for 3DS
The diagram below shows the SDK Core payment process with 3DS redirect via Web View
- Client creates an order
- Mobile Server registers that order in Payment Gateway via register.do. Use
returnUrl
parameter as a marker to close Web View after redirect from ACS on step 13. - Mobile Server receives a unique order number
mdOrder
in response. - Client fills in payment data in Mobile App.
-
Mobile App calls SDK to create seToken. (Android: sdkCore.generateWithCard; iOS: CKCToken.generateWithCard).
The public key used in the corresponding method is taken from the https://uat.dskbank.bg/payment/se/keys.do online resource. If multiple keys are available there, the first key should be used (note that the keys for UAT and production environments are different).
Mobile App sends the seToken to Mobile Server.
-
Mobile Server uses the seToken to make a payment via paymentorder.do request.
- Use seToken instead of pan, cvc and expiry date.
- Don't forget to send Cardholder name in
TEXT
field. If you don't collect Cardholder name just send CARDHOLDER.
Mobile Server gets a response with no ACS redirect. It means that the payment is completed and we need to go to step 16.
Mobile Server gets a response with ACS redirect.
Mobile App opens Web View with ACS redirect data.
Client enters their one time password to ACS form.
ACS redirects the Client to Payment Gateway
Payment Gateway makes a payment.
Payment Gateway redirects the Client to
returnUrl
, that can be used as a marker to close Web View.Mobile App closes Web View.
Payment Gateway sends callback notification to Merchant server if it's configured for the merchant.
Mobile Server checks the final payment status via getOrderStatusExtended.do.
Mobile App shows payment result to the Client.
3DS2 SDK for 3DS
The diagram below shows the SDK Core payment process with 3DS redirect 3DS2 SDK. Be aware that many issuers' ACS don't work properly with 3DS Mobile SDKs.
- Client creates an order.
- Mobile Server registers the order in Payment Gateway via register.do. Use
returnUrl
parameter as a marker to close Web View after redirect from ACS on step 13. - Mobile Server receives a unique order number
mdOrder
in response. - Client fills in payment data in Mobile App.
- Mobile App calls SDK to create seToken. (Android: sdkCore.generateWithCard; iOS: CKCToken.generateWithCard).
- Mobile App sends seToken to Mobile Server.
- Mobile Server uses that seToken to make a payment via paymentorder.do request.
- Use seToken instead of pan, cvc and expiry date.
- Don't forget to send Cardholder name in
TEXT
field. If you don't collect Cardholder name just send CARDHOLDER. - Send
threeDSSDK=true
to indicate that 3DS2 SDK should be used.
- Mobile Server gets a response with no ACS keys. It means that payment is completed and we need to go to step 23.
- 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
is returned in response to the first payment call on step 10 inthreeDSServerTransId
parameter. -
sdkEphemPubKey
is returned increateTransaction
method in 3DS2 SDK. -
sdkAppID
is returned increateTransaction
method in 3DS2 SDK. -
sdkTransID
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 the 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 the Client.
IOS
iOS Integration
SDKCore.framework integration
You can integrate SDKCore.framework by adding it manually.
SDKCore.framework
Download the latest version of the framework here.
Take the
SDKCore.framework
file and add it to the project folder.
- Open Targets -> General -> Frameworks, Libraries, and Embedded Content. For
SDKCore.framework
, in the Embed column, changeDo not Embed
toEmbed & Sign
.
Once done, import the framework in the ViewController.swift
file.
//ViewController.swift
...
import SDKCore
...
How to work with API V1
External dependencies
For generation of the token, it is necessary to set the public key.
let publicKey: String =
"-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoIITqh9xlGx4tWA+aucb0V0YuFC9aXzJb0epdioSkq3qzNdRSZIxe/dHqcbMN2SyhzvN6MRVl3xyjGAV+lwk8poD4BRW3VwPUkT8xG/P/YLzi5N8lY6ILlfw6WCtRPK5bKGGnERcX5dqL60LhOPRDSYT5NHbbp/J2eFWyLigdU9Sq7jvz9ixOLh6xD7pgNgHtnOJ3Cw0Gqy03r3+m3+CBZwrzcp7ZFs41bit7/t1nIqgx78BCTPugap88Gs+8ZjdfDvuDM+/3EwwK0UVTj0SQOv0E5KcEHENL9QQg3ujmEi+zAavulPqXH5907q21lwQeemzkTJH4o2RCCVeYO+YrQIDAQAB-----END PUBLIC KEY-----"
Token generation method
let sdkCore = SdkCore()
let cardParams = CardParams(
pan: "4111111111111111",
cvc: "123",
expiryMMYY: "12/28",
cardholder: "TEST CARDHOLDER",
mdOrder: "mdOrder",
pubKey: publicKey
)
let cardParamsConfig = SDKCoreConfig(
paymentMethodParams: .cardParams(params: cardParams)
)
let tokenResult = sdkCore.generateWithConfig(config: cardParamsConfig)
let bindignParams = BindingParams(
pubKey: publicKey,
bindingId: "das",
cvc: "123",
mdOrder: "mdOrder"
)
let bindingParamsConfig = SDKCoreConfig(
paymentMethodParams: .bindingParams(params: bindignParams)
)
let tokenResult = sdkCore.generateWithConfig(config: bindingParamsConfig)
Models
CardParams
Property name | Data type | Default value | Optional | Description |
---|---|---|---|---|
mdOrder | String | - | No | order number |
pan | String | - | No | card number |
cvc | String | - | No | secret card code |
expiryMMYY | String | - | No | expiry date for the card |
cardHolder | String | - | Yes | first and last name of cardholder |
pubKey | String | - | No | public key |
BindingParams
Property name | Data type | Default value | Optional | Description |
---|---|---|---|---|
mdOrder | String | - | No | order number |
bindingId | String | - | No | number of a stored credential for the card |
cvc | String | - | Yes | secret code for the card |
pubKey | String | - | No | public key |
Field validation errors
ParamField | Error | Description |
---|---|---|
UNKNOWN | - | Unknown error |
PAN | required | An empty field is specified |
invalid | Invalid value | |
invalid-format | Invalid characters are used. Only numbers are available. | |
CVC | required | An empty field is specified |
invalid | Invalid value | |
EXPIRY | required | An empty field is specified |
invalid | Invalid value | |
invalid-format | The format does not match the template MM/YY | |
CARDHOLDER | required | An empty field is specified |
invalid | Invalid value | |
invalid-format | Invalid characters are used. Only characters and spaces are available. | |
BINDING_ID | required | An empty field is specified |
invalid | Invalid value | |
MD_ORDER | required | An empty field is specified |
invalid | Invalid value | |
PUB_KEY | required | An empty field is specified |
Android
Android Integration
Connecting to a Gradle project by adding .aar library files
You must add the sdk_core-release.aar
library file to the libs
folder, then specify the
dependency of the added library.
build.gradle.kts
allprojects {
repositories {
// ...
flatDir {
dirs("libs")
}
}
}
dependencies {
// dependency is mandatory to add
implementation(group = "", name = "sdk_core-release", ext = "aar")
}
build.gradle
allprojects {
repositories {
// ...
flatDir {
dirs 'libs'
}
}
}
dependencies {
// dependency is mandatory to add
implementation(group: '', name: 'sdk_core-release', ext: 'aar')
}
Android Configuration
Logging
Internal processes are logged with the SDK-Core
tag.
You can also log your processes.
Logging is available through the Logger
object.
-
To add log- interfaces, you should call the
Logger
-methodaddLogInterface()
.Example of logging into LogCat:
...
Logger.addLogInterface(object : LogInterface {
override fun log(classMethod: Class<Any>, tag: String, message: String, exception: Exception?) {
Log.i(tag, "$classMethod: $message", exception)
}
})
...
The default tag is SDK-Core
. You can set your own one if you like.
-
To log your own events, you should call
Logger
-methodlog()
.Example:
...
Logger.log(this.javaClass, "MyTag", "My process...", null)
...
Example Kotlin_core (no GUI)
Example of cryptogram formation
import net.payrdr.mobile.payment.sdk.core.SDKCore
import net.payrdr.mobile.payment.sdk.core.TokenResult
import net.payrdr.mobile.payment.sdk.core.model.BindingParams
import net.payrdr.mobile.payment.sdk.core.model.CardParams
import net.payrdr.mobile.payment.sdk.core.validation.BaseValidator
import net.payrdr.mobile.payment.sdk.core.validation.CardCodeValidator
import net.payrdr.mobile.payment.sdk.core.validation.CardExpiryValidator
import net.payrdr.mobile.payment.sdk.core.validation.CardHolderValidator
import net.payrdr.mobile.payment.sdk.core.validation.CardNumberValidator
import net.payrdr.mobile.payment.sdk.core.validation.OrderNumberValidator
class MainActivity : AppCompatActivity() {
// initialization of validators for card information entry fields
private val cardNumberValidator by lazy { CardNumberValidator(this) }
private val cardExpiryValidator by lazy { CardExpiryValidator(this) }
private val cardCodeValidator by lazy { CardCodeValidator(this) }
private val cardHolderValidator by lazy { CardHolderValidator(this) }
private val orderNumberValidator by lazy { OrderNumberValidator(this) }
private val sdkCore by lazy { SDKCore(context = this) }
override fun onCreate(savedInstanceState: Bundle?) {
// installation of validators on the card information entry fields
cardNumberInput.setupValidator(cardNumberValidator)
cardExpiryInput.setupValidator(cardExpiryValidator)
cardCodeInput.setupValidator(cardCodeValidator)
cardHolderInput.setupValidator(cardHolderValidator)
mdOrderInput.setupValidator(orderNumberValidator)
// creation of an object and initialization of fields for a new card
val params = NewPaymentMethodCardParams(
pan = cardNumberInput.text.toString(),
cvc = cardCodeInput.text.toString(),
expiryMMYY = cardExpiryInput.text.toString(),
cardHolder = cardHolderInput.text.toString(),
pubKey = pubKeyInput.text.toString()
)
// method call to get the cryptogram for a new card
sdkCore.generateWithConfig(SDKCoreConfig(params))
// Creation of an object and initialization of fields for the linked card
val params = NewPaymentMethodStoredCardParams(
storedPaymentId = "storedPaymentMethodId",
cvc = "123",
pubKey = pubKeyInput.text.toString()
)
// method call to get the cryptogram for the linked card
sdkCore.generateWithConfig(SDKCoreConfig(params))
}
}
Models
NewPaymentMethodCardParams
Property name | Data type | Default value | Optional | Description |
---|---|---|---|---|
pan | String | - | No | card number |
cvc | String | - | No | secret card code |
expiryMMYY | String | - | No | expiry date for the card |
cardHolder | String | - | No | first and last name of the cardholder |
pubKey | String | - | No | public key |
NewPaymentMethodStoredCardParams
Property name | Data type | Default value | Optional | Description |
---|---|---|---|---|
storedPaymentId | String | - | No | number of a stored credential for the card |
cvc | String | - | No | secret code for the card |
pubKey | String | - | No | public key |
TokenResult
Property name | Data type | Default value | Optional | Description |
---|---|---|---|---|
token | String | - | No | token as string |
errors | Map |
- | No | error while generating token |
Field validation errors
ParamField | Error | Description |
---|---|---|
PAN | required | An empty field is specified |
invalid | Invalid value | |
invalid-format | Invalid characters are used. Only numbers are available. | |
CVC | required | An empty field is specified |
invalid | Invalid value | |
EXPIRY | required | An empty field is specified |
invalid | Invalid value | |
invalid-format | The format does not match the template MM/YY. | |
CARDHOLDER | required | An empty field is specified |
invalid | Invalid value | |
invalid-format | Invalid characters are used. Only characters and spaces are available. | |
PUB_KEY | required | An empty field is specified |
STORED_PAYMENT_ID | requrired | An empty field is specified |
invalid | Invalid value |
How to work with API V1
External dependencies
For generation of the token, it is necessary to set the public key.
val publicKey: String =
"-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoIITqh9xlGx4tWA+aucb0V0YuFC9aXzJb0epdioSkq3qzNdRSZIxe/dHqcbMN2SyhzvN6MRVl3xyjGAV+lwk8poD4BRW3VwPUkT8xG/P/YLzi5N8lY6ILlfw6WCtRPK5bKGGnERcX5dqL60LhOPRDSYT5NHbbp/J2eFWyLigdU9Sq7jvz9ixOLh6xD7pgNgHtnOJ3Cw0Gqy03r3+m3+CBZwrzcp7ZFs41bit7/t1nIqgx78BCTPugap88Gs+8ZjdfDvuDM+/3EwwK0UVTj0SQOv0E5KcEHENL9QQg3ujmEi+zAavulPqXH5907q21lwQeemzkTJH4o2RCCVeYO+YrQIDAQAB-----END PUBLIC KEY-----"
Token generation method
// TokenResult with CardParams
val cardParams: CardParams = CardParams(
mdOrder = "mdOrder",
pan = "4111111111111111",
cvc = "123",
expiryMMYY = "12/28",
cardHolder = "TEST CARDHOLDER",
pubKey = "publicKey"
)
val tokenResult = sdkCore.generationWithConfig(paymentCardParams = cardParams)
// TokenResult with BindingParams
val bindingParams: BindingParams = BindingParams(
mdOrder = "mdOrder",
bindingID = "das",
cvc = "123",
pubKey = "publicKey"
)
val tokenResult = sdkCore.generationWithConfig(paymentCardParams = bindingParams)