Процесс оплаты SDK Core
Web View для 3DS
На приведенной ниже диаграмме показан процесс оплаты SDK Core с перенаправлением 3DS через Web View.
- Клиент создает заказ
- Мобильный сервер регистрирует этот заказ в платежном шлюзе через register.do. Используйте параметр
returnUrl
в качестве маркера для закрытия Web View после перенаправления из ACS на Шаге 14. - Мобильный сервер получает в ответе уникальный номер заказа
mdOrder
. - Клиент заполняет платежные данные в мобильном приложении.
-
Мобильное приложение вызывает SDK для создания seToken. (Android: sdkCore.generateWithCard; iOS: CKCToken.generateWithCard).
Публичный ключ, который требуется в соответствующем методе, необходимо брать с online ресурса https://3dsec.berekebank.kz/payment/se/keys.do. Если по этой ссылке доступно несколько ключей, следует использовать первый ключ. (Имейте в виду, что для тестовой и рабочей сред используются разные ключи.)
Мобильное приложение отправляет seToken на мобильный сервер.
-
Мобильный сервер использует этот seToken для совершения платежа через paymentorder.do.
- Используйте seToken вместо pan, cvc и даты истечения срока действия.
- Не забудьте указать имя держателя карты в поле
TEXT
. Если вы не собираете имя держателя карты, просто отправьте значениеCARDHOLDER
.
Мобильный сервер получает ответ без редиректа на ACS. Это означает, что оплата завершена и нам нужно перейти к Шагу 16.
Мобильный сервер получает ответ с редиректом на ACS.
Мобильное приложение открывает Web View с данными редиректа на ACS.
Клиент вводит свой одноразовый пароль в форму ACS.
ACS перенаправляет клиента на платежный шлюз.
Платежный шлюз осуществляет платеж.
Платежный шлюз перенаправляет клиента на
returnUrl
, который можно использовать в качестве маркера для закрытия Web View.Мобильное приложение закрывает Web View.
Платежный шлюз отправляет уведомление обратного вызова на сервер продавца, если оно настроено для продавца.
Мобильный сервер проверяет окончательный статус платежа через getOrderStatusExtended.do.
Мобильное приложение показывает результат платежа клиенту.
IOS
iOS-интеграция
Интеграция SDKCore.framework
Вы можете интегрировать SDKCore.framework, добавив его вручную.
SDKCore.framework
Скачайте последнюю версию фреймворка здесь.
Выберите файл
SDKCore.framework
и добавьте его в папку проекта.

- Откройте страницу Targets -> General -> Frameworks, Libraries, and Embedded Content. Для
SDKCore.framework
с столбце Embed заменитеDo not Embed
наEmbed & Sign
.

Затем импортируйте фреймворк в файл
ViewController.swift
.
//ViewController.swift
...
import SDKCore
...
Работа с API V1
Внешние зависимости
Для генерации токена необходимо задать открытый ключ.
let publicKey: String =
"-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoIITqh9xlGx4tWA+aucb0V0YuFC9aXzJb0epdioSkq3qzNdRSZIxe/dHqcbMN2SyhzvN6MRVl3xyjGAV+lwk8poD4BRW3VwPUkT8xG/P/YLzi5N8lY6ILlfw6WCtRPK5bKGGnERcX5dqL60LhOPRDSYT5NHbbp/J2eFWyLigdU9Sq7jvz9ixOLh6xD7pgNgHtnOJ3Cw0Gqy03r3+m3+CBZwrzcp7ZFs41bit7/t1nIqgx78BCTPugap88Gs+8ZjdfDvuDM+/3EwwK0UVTj0SQOv0E5KcEHENL9QQg3ujmEi+zAavulPqXH5907q21lwQeemzkTJH4o2RCCVeYO+YrQIDAQAB-----END PUBLIC KEY-----"
Метод генерации токена
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)
Модели
CardParams
Название свойства | Тип данных | Значение по умолчанию | Необязательно | Описание |
---|---|---|---|---|
mdOrder | String | - | Нет | Номер заказа |
pan | String | - | Нет | Номер карты |
cvc | String | - | Нет | Секретный код карты |
expiryMMYY | String | - | Нет | Срок действия карты |
cardHolder | String | - | Да | Имя и фамилия держателя карты |
pubKey | String | - | Нет | Открытый ключ |
BindingParams
Название свойства | Тип данных | Значение по умолчанию | Необязательно | Описание |
---|---|---|---|---|
mdOrder | String | - | Нет | Номер заказа |
bindingId | String | - | Нет | Номер связки для карты |
cvc | String | - | Да | Секретный код карты |
pubKey | String | - | Нет | Открытый ключ |
Ошибки валидации полей
ParamField | Ошибка | Описание |
---|---|---|
UNKNOWN | - | Неизвестная ошибка |
PAN | required | Указано пустое поле |
invalid | Некорректное значение | |
invalid-format | Используются недопустимые символы. Доступны только цифры. | |
CVC | required | Указано пустое поле |
invalid | Некорректное значение | |
EXPIRY | required | Указано пустое поле |
invalid | Некорректное значение | |
invalid-format | Формат не соответствует шаблону MM/YY | |
CARDHOLDER | required | Указано пустое поле |
invalid | Некорректное значение | |
invalid-format | Используются недопустимые символы. Доступны только буквы и пробелы. | |
BINDING_ID | required | Указано пустое поле |
invalid | Некорректное значение | |
MD_ORDER | required | Указано пустое поле |
invalid | Некорректное значение | |
PUB_KEY | required | Указано пустое поле |
Android
Android-интеграция
Подключение к Gradle проекту путем добавления файлов .aar библиотеки
Необходимо добавить файл библиотеки sdk_core-release.aar
в папку libs
, а затем указать зависимость добавленной библиотеки.
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
Логирование
Внутренние процессы логируются с тегом SDK-Core
.
Вы также можете логировать свои процессы.
Логирование доступно через объект Logger
.
-
Для добавления log- интерфейсов необходимо вызвать
Logger
-методaddLogInterface()
.Пример для логирования в LogCat:
...
Logger.addLogInterface(object : LogInterface {
override fun log(classMethod: Class<Any>, tag: String, message: String, exception: Exception?) {
Log.i(tag, "$classMethod: $message", exception)
}
})
...
По умолчанию используется тег SDK-Core
. Вы можете установить свой собственный, если хотите.
-
Для логирования собственных событий необходимо вызвать
Logger
-методlog()
.Пример:
...
Logger.log(this.javaClass, "MyTag", "My process...", null)
...
Пример Kotlin_core (без графического интерфейса)
Пример формирования криптограммы
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))
}
}
Модели
NewPaymentMethodCardParams
Название свойства | Тип данных | Значение по умолчанию | Необязательно | Описание |
---|---|---|---|---|
pan | String | - | Нет | Номер карты |
cvc | String | - | Нет | Секретный код карты |
expiryMMYY | String | - | Нет | Срок действия карты |
cardHolder | String | - | Нет | Имя и фамилия держателя карты |
pubKey | String | - | Нет | Открытый ключ |
NewPaymentMethodStoredCardParams
Название свойства | Тип данных | Значение по умолчанию | Необязательно | Описание |
---|---|---|---|---|
storedPaymentId | String | - | Нет | Номер связки для карты |
cvc | String | - | Нет | Секретный код карты |
pubKey | String | - | Нет | Открытый ключ |
TokenResult
Название свойства | Тип данных | Значение по умолчанию | Необязательно | Описание |
---|---|---|---|---|
token | String | - | Нет | Токен как строка |
errors | Map |
- | Нет | Ошибка при генерации токена |
Ошибки валидации полей
ParamField | Ошибка | Описание |
---|---|---|
PAN | required | Указано пустое поле |
invalid | Некорректное значение | |
invalid-format | Используются недопустимые символы. Доступны только цифры. | |
CVC | required | Указано пустое поле |
invalid | Некорректное значение | |
EXPIRY | required | Указано пустое поле |
invalid | Некорректное значение | |
invalid-format | Формат не соответствует шаблону MM/YY. | |
CARDHOLDER | required | Указано пустое поле |
invalid | Некорректное значение | |
invalid-format | Используются недопустимые символы. Доступны только буквы и пробелы. | |
PUB_KEY | required | Указано пустое поле |
STORED_PAYMENT_ID | requrired | Указано пустое поле |
invalid | Некорректное значение |
Работа с API V1
Внешние зависимости
Для генерации токена необходимо установить открытый ключ.
val publicKey: String =
"-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoIITqh9xlGx4tWA+aucb0V0YuFC9aXzJb0epdioSkq3qzNdRSZIxe/dHqcbMN2SyhzvN6MRVl3xyjGAV+lwk8poD4BRW3VwPUkT8xG/P/YLzi5N8lY6ILlfw6WCtRPK5bKGGnERcX5dqL60LhOPRDSYT5NHbbp/J2eFWyLigdU9Sq7jvz9ixOLh6xD7pgNgHtnOJ3Cw0Gqy03r3+m3+CBZwrzcp7ZFs41bit7/t1nIqgx78BCTPugap88Gs+8ZjdfDvuDM+/3EwwK0UVTj0SQOv0E5KcEHENL9QQg3ujmEi+zAavulPqXH5907q21lwQeemzkTJH4o2RCCVeYO+YrQIDAQAB-----END PUBLIC KEY-----"
Метод генерации токена
// 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)
React Native
Для реализации интеграции Mobile SDK Core в React Native-приложение необходимо настроить мост — обёртку на Kotlin/Java или Swift/Objective-C, которая будет принимать вызовы из JavaScript и передавать их в нативный код SDK.
Мосты в React Native позволяют вашему JS-коду вызывать методы нативных библиотек так же просто, как обычные асинхронные функции: вы объявляете нативный модуль с методами, которые возвращают результат через Promise, React Native автоматически связывает эти методы с JavaScript, и дальше вы работаете с ними в приложении без глубоких знаний платформенных API.
IOS
Интегрируйте SDKCore в ваш проект в соответствии с разделом iOS-интеграция.
Проверьте, что для фреймворка
SDKCore.xcframework
в колонке Embed выбрано Embed & Sign.-
Создайте Swift-модуль
RadarSdkBridge.swift
со следующим содержимым:import Foundation import React import SDKCore @objc(RadarSdk) class RadarSdkBridge: NSObject { private let sdkCore = SdkCore() @objc func generateNewCardToken( _ pan: String, cvc: String, expiryMMYY: String, cardHolder: String, mdOrder: String, pubKey: String, resolver resolve: RCTPromiseResolveBlock, rejecter reject: RCTPromiseRejectBlock ) { do { let params = CardParams( pan: pan, cvc: cvc, expiryMMYY: expiryMMYY, cardholder: cardHolder, mdOrder: mdOrder, pubKey: pubKey ) let config = SDKCoreConfig(paymentMethodParams: .cardParams(params: params)) let result = try sdkCore.generateWithConfig(config: config) resolve(result.token) } catch { reject("TOKEN_ERROR", error.localizedDescription, error) } } @objc func generateStoredCardToken( _ storedPaymentId: String, cvc: String, pubKey: String, mdOrder: String, resolver resolve: RCTPromiseResolveBlock, rejecter reject: RCTPromiseRejectBlock ) { do { let params = BindingParams( pubKey: pubKey, bindingId: storedPaymentId, cvc: cvc, mdOrder: mdOrder ) let config = SDKCoreConfig(paymentMethodParams: .bindingParams(params: params)) let result = try sdkCore.generateWithConfig(config: config) resolve(result.token) } catch { reject("TOKEN_ERROR", error.localizedDescription, error) } } @objc static func requiresMainQueueSetup() -> Bool { return false } }
-
Реализуйте Objective-C мост в файле
RadarSdkBridge.m
:#import <React/RCTBridgeModule.h> @interface RCT_EXTERN_MODULE(RadarSdk, NSObject) RCT_EXTERN_METHOD(generateNewCardToken: (NSString *)pan cvc:(NSString *)cvc expiryMMYY:(NSString *)expiryMMYY cardHolder:(NSString *)cardHolder mdOrder:(NSString *)mdOrder pubKey:(NSString *)pubKey resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject ) RCT_EXTERN_METHOD(generateStoredCardToken: (NSString *)storedPaymentId cvc:(NSString *)cvc pubKey:(NSString *)pubKey mdOrder:(NSString *)mdOrder resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject ) @end
Android
Скачайте файлы
sdk_core-release.aar
иsdk_logs-release.aar
и скопируйте их в папкуandroid/app/libs/
согласно разделу Android-интеграция.-
Добавьте плоский репозиторий и зависимости в файл
android/app/build.gradle
:android { // … остальная конфигурация вашего проекта … } repositories { flatDir { dirs 'libs' } } dependencies { // … прочие зависимости … implementation(name: 'sdk_core-release', ext: 'aar') implementation(name: 'sdk_logs-release', ext: 'aar') }
Реализация Native Module для Kotlin
-
Создайте файл
RadarSdkModule.kt
в директорииandroid/app/src/main/java/.../radar/
:package com.mobilesdkdemo.radar import com.facebook.react.bridge.Promise import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.bridge.ReactContextBaseJavaModule import com.facebook.react.bridge.ReactMethod import net.payrdr.mobile.payment.sdk.core.SDKCore import net.payrdr.mobile.payment.sdk.core.model.SDKCoreConfig import net.payrdr.mobile.payment.sdk.core.model.CardParams import net.payrdr.mobile.payment.sdk.core.model.BindingParams class RadarSdkModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) { override fun getName(): String = "RadarSdk" private val sdkCore by lazy { SDKCore(context = reactApplicationContext) } @ReactMethod fun generateNewCardToken( pan: String, cvc: String, expiryMMYY: String, cardHolder: String, mdOrder: String, pubKey: String, promise: Promise ) { try { val params = CardParams( pan = pan, cvc = cvc, expiryMMYY = expiryMMYY, cardHolder = cardHolder, mdOrder = mdOrder, pubKey = pubKey ) val config = SDKCoreConfig(paymentCardParams = params) val result = sdkCore.generateWithConfig(config) promise.resolve(result.token) } catch (e: Exception) { promise.reject("TOKEN_ERROR", e) } } @ReactMethod fun generateStoredCardToken( storedPaymentId: String, cvc: String, pubKey: String, mdOrder: String, promise: Promise ) { try { val params = BindingParams( bindingID = storedPaymentId, mdOrder = mdOrder, cvc = cvc, pubKey = pubKey ) val config = SDKCoreConfig(paymentCardParams = params) val result = sdkCore.generateWithConfig(config) promise.resolve(result.token) } catch (e: Exception) { promise.reject("TOKEN_ERROR", e) } } }
-
Создайте пакет
RadarSdkPackage.kt
в той же директории:package com.mobilesdkdemo.radar import com.facebook.react.ReactPackage import com.facebook.react.bridge.NativeModule import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.uimanager.ViewManager class RadarSdkPackage : ReactPackage { override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> = listOf(RadarSdkModule(reactContext)) override fun createViewManagers( reactContext: ReactApplicationContext ): List<ViewManager<*, *>> = emptyList() }
-
Зарегистрируйте созданный пакет в
MainApplication.kt
:package com.mobilesdkdemo import android.app.Application import com.facebook.react.PackageList import com.facebook.react.ReactApplication import com.facebook.react.ReactNativeHost import com.facebook.react.ReactHost import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load import com.facebook.react.defaults.DefaultReactNativeHost import com.facebook.soloader.SoLoader import com.mobilesdkdemo.radar.RadarSdkPackage class MainApplication : Application(), ReactApplication { override val reactNativeHost: ReactNativeHost = object : DefaultReactNativeHost(this) { override fun getPackages(): List<ReactPackage> = PackageList(this).packages.apply { add(RadarSdkPackage()) // Регистрируем пакет } override fun getJSMainModuleName(): String = "index" override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED } override val reactHost: ReactHost get() = getReactNativeHost(applicationContext, reactNativeHost) override fun onCreate() { super.onCreate() SoLoader.init(this, false) if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { load() } } }
Использование в React Native
Используйте методы из JavaScript/TypeScript следующим образом:
import { NativeModules } from 'react-native';
const { RadarSdk } = NativeModules;
// Генерация токена для новой карты
const token = await RadarSdk.generateNewCardToken(
'4111111111111111', // PAN
'123', // CVC
'12/25', // Expiry MM/YY
'CARDHOLDER NAME', // Имя держателя карты
'mdOrder', // Номер, полученный при регистрации заказа
'-----BEGIN PUBLIC KEY-----...' // Публичный ключ из /payment/se/keys.do
);
// Генерация токена для привязанной карты
const bindToken = await RadarSdk.generateStoredCardToken(
'bindingId', // ID сохранённой карты
'123', // CVC
'-----BEGIN PUBLIC KEY-----…', // Публичный ключ из /payment/se/keys.do
'mdOrder' // Номер, полученный при регистрации заказа
);
Демо приложение
Пример интеграции Mobile Sdk Core в приложение на React Native можно посмотреть на GitHub.