For any question, we are one click away

Contact us

SDK Core process

Web View for 3DS

The diagram below shows the SDK Core payment process with 3DS redirect via Web View

sequenceDiagram participant MA as Mobile App participant MS as Mobile Server participant SDK as SDK participant PG as Payment Gateway participant 3DS as 3DSS/ACS/DS MA ->> MS: 1. client creates an Order MS ->> PG: 2. register order via API PG -->> MS: 3. unique order number (mdOrder) MA ->> MA: 4. client enters data MA -->> SDK: 5. generate seToken MA ->> MS: 6. send seToken to server MS ->> PG: 7. call payment API alt Payment finished PG -->> MS: 8. response with payment status (go to 16) else 3DS2 required PG -->> MS: 9. response with 3DS redirect MS ->> MA: 10. open Web View for 3DS MA ->> ACS: 11. client enters password ACS -->> PG: 12. redirect to Payment Gateway PG ->> PG: 13. make payment PG -->> MA: 14. redirect to returnUrl MA ->> MA: 15. close Web View end opt Callback is configured PG -->> MS: 16. callback notification end MS ->> PG: 17. check payment status MS ->> MA: 18. show payment result to Client
  1. Client creates an Order
  2. 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
  3. Mobile Server receives a unique order number mdOrder in response.
  4. Client fills in payment data in Mobile App
  5. 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://dev.bpcbt.com/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).

  6. Mobile App sends seToken to Mobile Server

  7. 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
  8. Mobile Server gets a response with no ACS redirect. It means that payment is completed and we need to go to step 16

  9. Mobile Server gets a response with ACS redirect.

  10. Mobile App opens Web View with ACS redirect data

  11. Clients enters his one time password to ACS form

  12. ACS redirects Client to Payment Gateway

  13. Payment Gateway makes a payment

  14. Payment Gateway redirects Client to returnUrl, that can be used as a marker to close Web View

  15. Mobile App closes Web View

  16. Payment Gateway sends callback notification to Merchant server if it's configured for merchant

  17. Mobile Server checks the final payment status via getOrderStatusExtended.do

  18. Mobile App shows payment result to 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.

sequenceDiagram participant MA as Mobile App participant MS as Mobile Server participant SDK as SDK participant SDK2 as 3DS2 SDK participant PG as Payment Gateway participant 3DS as 3DSS/ACS/DS MA ->> MS: 1. client creates an Order MS ->> PG: 2. register order via API PG -->> MS: 3. unique order number (mdOrder) MA ->> MA: 4. client enters data MA -->> SDK: 5. generate seToken MA ->> MS: 6. send seToken to server MS ->> PG: 7. call payment API with threeDSSDK alt Payment finished PG -->> MS: 8. response with payment status (go to 23) else 3DS2 required PG -->> MS: 9. response with 3DS2 SDK keys MS ->> MA: 10. send data to SDK MA ->> SDK2: 11. init 3DS2 SDK SDK2 -->> MA: 12. collect device data MA ->> MS: 13. send device data MS ->> PG: 14. second payment API call PG -->> MS: 15. acs signed content MS ->> MA: 16. send acs data MA ->> SDK2: 17. init Challenge flow SDK2 ->> ACS: 18. communicates via CReq/CRes ACS -->> PG: 19. confirms transaction with AReq SDK2 -->> MA: 20. 3DS procedure is over MS ->> PG: 21. finish 3DS2 payment PG ->> PG: 22. make payment end opt Callback is configured PG -->> MS: 23. callback notification end MS ->> PG: 24. check payment status MS ->> MA: 25. show payment result to Client
  1. Client creates an Order
  2. 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
  3. Mobile Server receives a unique order number mdOrder in response.
  4. Client fills in payment data in Mobile App
  5. Mobile App calls SDK to create seToken. (Android: sdkCore.generateWithCard; iOS: CKCToken.generateWithCard)
  6. Mobile App sends seToken to Mobile Server
  7. 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
  8. Mobile Server gets a response with no ACS keys. It means that payment is completed and we need to go to step 23
  9. Mobile Server gets a response with ACS keys.
    • Response must contain threeDSServerTransId and threeDSSDKKey
    • Response should not contain threeDSMethodURL which is used in case of browser based redirect to ACS
  10. Mobile Server sends 3DS2 SDK data to Mobile App
  11. 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
    • pemPublicKeyfor Android and for iOS is a pem certificate that is got in response in threeDSSDKKey on step 10
    • dsRootfor Android and for iOS depends on Payment System. Download test key
  12. 3DS2 SDK collects device data and encrypts it
  13. Mobile App sends encrypted device data to Mobile Server
  14. Mobile Server initiates second payment API call via paymentorder.do request
    • sdkEncData encrypted device data that is returned in createTransaction 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 in threeDSServerTransId parameter
    • sdkEphemPubKey it is returned in createTransaction method in 3DS2 SDK
    • sdkAppID it is returned in createTransaction method in 3DS2 SDK
    • sdkTransID it is returned in createTransaction method in 3DS2 SDK
  15. Payment Gateway returns new special parameters for 3DS2 SDK
  16. Mobile Server sends those parameters to Mobile App
  17. Mobile App initiates challenge flow via doChallenge method
    • doChallenge acsTransactionIDparameter corresponds to threeDSAcsTransactionId in Payment Gateway response
    • doChallenge acsRefNumberparameter corresponds to threeDSAcsRefNumber in Payment Gateway response
    • doChallenge acsSignedContentparameter corresponds to threeDSAcsSignedContent in Payment Gateway response
    • doChallenge 3DSServerTransactionIDparameter corresponds to threeDSServerTransId in Payment Gateway response
  18. 3DS2 SDK communicates with issuers ACS via CReq/CRes API until Client confirms his payment
  19. ACS sends RReq to Payment Gateway to confirm or reject the payment
  20. 3DS2 SDK informs Mobile App that 3DS2 flow is over via ChallengeStatusReceiver
  21. Mobile Server finalizes the payment with finish3dsVer2Payment.do
  22. Payment Gateway makes a payment
  23. Payment Gateway sends callback notification to Merchant server if it's configured for merchant
  24. Mobile Server checks the final payment status via getOrderStatusExtended.do
  25. Mobile App shows payment result to client

IOS

iOS Integration

CardKitCore.framework integration

You can integrate CardKitCore.framework in two ways:

CardKitCore.framework

Image 1. Adding the CardKitCore.framework file

Image 2. Changing CardKitCore.framework properties

Pod

Once done, import framework in the ViewController.swift file.

//ViewController.swift
...
import CardKitCore
...

iOS Configuration

CardKitCore API

type CKCCardParams = {
  pan: string               // card number (without separators and spaces)
  cvc: string
  expiryMMYY: string        // date in MM/YYY or MMYYY format
  cardholder: string | null // if null - not validated
  mdOrder: string | null
  pubKey: string
  seTokenTimestamp: string | null // if null - the sdk gets a smartphone local time
}
type CKCBindingParams = {
  bindingID: string
  cvc: string | null // if null, then it is not validated
  mdOrder: string | null
  pubKey: string
  seTokenTimestamp: string | null // if null - the sdk gets in a smartphone local time
}
type CKCError = 
   | 'invalid-pub-key' // empty or invalid key
   | 'required'        // Required field
   | 'invalid-format'  // invalid data format (for example, numbers in a cardholder)
   | 'invalid-length'  // invalid field length
   | 'invalid'         // invalid field value (general)

type CKCField = | 'pan' | 'cvc' | 'expiryMMYY' | 'cardholder' | 'bindingID' | 'mdOrder' | 'pubKey' type CKCTokenResult = { token: string | null errors: [{field: CKCField, error: CKCError }] | null } class CKCPubKey { // utility for parsing JSON response from public key servers static fromJSONString(json: string): string | null } class CKCToken { static generateWithBinding(params: CKCBindingParams): CKCTokenResult static generateWithCard(params: CKCCardParams): CKCTokenResult static timestampForDate(NSDate: date): string }

Implementation example

Generating a token from card data

import CardKitCore
let cardParams = CKCCardParams()
cardParams.cardholder= "Korotkov Alex"
cardParams.expiryMMYY= "1222" // or 12/22
cardParams.pan= "5536913776755304"
cardParams.cvc =  "123"
cardParams.mdOrder =  "mdorder"
cardParams.pubKey =  "-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoIITqh9xlGx4tWA+aucb0V0YuFC9aXzJb0epdioSkq3qzNdRSZIxe/dHqcbMN2SyhzvN6MRVl3xyjGAV+lwk8poD4BRW3VwPUkT8xG/P/YLzi5N8lY6ILlfw6WCtRPK5bKGGnERcX5dqL60LhOPRDSYT5NHbbp/J2eFWyLigdU9Sq7jvz9ixOLh6xD7pgNgHtnOJ3Cw0Gqy03r3+m3+CBZwrzcp7ZFs41bit7/t1nIqgx78BCTPugap88Gs+8ZjdfDvuDM+/3EwwK0UVTj0SQOv0E5KcEHENL9QQg3ujmEi+zAavulPqXH5907q21lwQeemzkTJH4o2RCCVeYO+YrQIDAQAB-----END PUBLIC KEY-----"
let res = CKCToken.generate(withCard: cardParams);

Generating a token from BindingId

import CardKitCore
let bindingParams = CKCBindingParams()
bindingParams.bindingID = "das"
bindingParams.cvc = "123"
bindingParams.mdOrder = "mdOrder"
bindingParams.pubKey = "-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoIITqh9xlGx4tWA+aucb0V0YuFC9aXzJb0epdioSkq3qzNdRSZIxe/dHqcbMN2SyhzvN6MRVl3xyjGAV+lwk8poD4BRW3VwPUkT8xG/P/YLzi5N8lY6ILlfw6WCtRPK5bKGGnERcX5dqL60LhOPRDSYT5NHbbp/J2eFWyLigdU9Sq7jvz9ixOLh6xD7pgNgHtnOJ3Cw0Gqy03r3+m3+CBZwrzcp7ZFs41bit7/t1nIqgx78BCTPugap88Gs+8ZjdfDvuDM+/3EwwK0UVTj0SQOv0E5KcEHENL9QQg3ujmEi+zAavulPqXH5907q21lwQeemzkTJH4o2RCCVeYO+YrQIDAQAB-----END PUBLIC KEY-----"
let res = CKCToken.generate(withBinding: bindingParams)

Extracting public key from JSON

Public keys for seToken are available at https://dev.bpcbt.com/payment/se/keys.do

let JSONWithPubKey = """{
  "keys":[{
    "keyValue":"-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhjH8R0jfvvEJwAHRhJi2Q4fLi1p2z10PaDMIhHbD3fp4OqypWaE7p6n6EHig9qnwC/4U7hCiOCqY6uYtgEoDHfbNA87/X0jV8UI522WjQH7Rgkmgk35r75G5m4cYeF6OvCHmAJ9ltaFsLBdr+pK6vKz/3AzwAc/5a6QcO/vR3PHnhE/qU2FOU3Vd8OYN2qcw4TFvitXY2H6YdTNF4YmlFtj4CqQoPL1u/uI0UpsG3/epWMOk44FBlXoZ7KNmJU29xbuiNEm1SWRJS2URMcUxAdUfhzQ2+Z4F0eSo2/cxwlkNA+gZcXnLbEWIfYYvASKpdXBIzgncMBro424z/KUr3QIDAQAB-----END PUBLIC KEY-----",
    "protocolVersion":"RSA",
    "keyExpiration":1661599747000
    }
  ]}""";
CKCPubKey.fromJSONString(JSONWithPubKey); // Return "-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhjH8R0jfvvEJwAHRhJi2Q4fLi1p2z10PaDMIhHbD3fp4OqypWaE7p6n6EHig9qnwC/4U7hCiOCqY6uYtgEoDHfbNA87/X0jV8UI522WjQH7Rgkmgk35r75G5m4cYeF6OvCHmAJ9ltaFsLBdr+pK6vKz/3AzwAc/5a6QcO/vR3PHnhE/qU2FOU3Vd8OYN2qcw4TFvitXY2H6YdTNF4YmlFtj4CqQoPL1u/uI0UpsG3/epWMOk44FBlXoZ7KNmJU29xbuiNEm1SWRJS2URMcUxAdUfhzQ2+Z4F0eSo2/cxwlkNA+gZcXnLbEWIfYYvASKpdXBIzgncMBro424z/KUr3QIDAQAB-----END PUBLIC KEY-----"

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 card
cardHolder String? - No 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 stored credential for card
cvc String? - No secret code for 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
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') }

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

val context: Context = //android context for getting string resources
val sdkCore: SDKCore = SDKCore(context)

val cardParams: CardParams = CardParams( mdOrder = "mdOrder", pan = "5536913776755304", cvc = "123", expiryMMYY = "12/22", cardHolder = "Korotkov Alex", pubKey = "publicKey" ) val tokenResult = sdkCore.generationWithCard(cardParams)

val bindingParams: BindingParams = BindingParams( mdOrder = "mdOrder", bindingID = "das", cvc = "123", pubKey = "publicKey" )

val tokenResult = sdkCore.generateWithBinding(bindingParams)

Android Configuration

Logging

Internal processes are logged with SDK-Core tag. Also you can log your processes.

Logging is available through the object Logger. - To add log- interfaces you should call Logger-method addLogInterface().

For example to log 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 is the tag SDK-Core. You can set your own one if you like.

...
     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 = CardParams( mdOrder = mdOrderInput.text.toString(), 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.generateWithCard(params)

// Creation of an object and initialization of fields for the linked card val params = BindingParams( mdOrder = mdOrderInput.text.toString(), bindingID = bindingIdInput.text.toString(), cvc = "123", pubKey = pubKeyInput.text.toString() ) // method call to get the cryptogram for the linked card sdkCore.generateWithBinding(params) } }

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 card
cardHolder String? - No 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 stored credential for card
cvc String? - No secret code for 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
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
Categories:
eCommerce SDK
Categories
Search results