Ana içeriğe geç

BEX Lite SDK — Entegrasyon Kılavuzu

Bu doküman, BEX Lite SDK’nın Android uygulamanıza güvenli, kurumsal ve PCI-DSS uyumlu biçimde nasıl entegre edileceğini açıklar.
SDK, arkaplan işlemleri ve güvenli kart verisi yönetiminden sorumludur; ekran akışları, UI bileşenleri ve müşteri deneyimi tamamen entegratör kuruma aittir.


1. Genel Bakış

Yüksek seviyede entegrasyon akışı aşağıdaki adımlardan oluşur:

  1. SDK’nın başlatılması: BexLiteSdk.init ile oturum ve iş parametrelerinin tanımlanması
  2. İstemcinin alınması: BexLiteSdk.getPaymentClient() ile BexPaymentClient örneğinin elde edilmesi
  3. Backend ile ilk senkronizasyon: initializeSdk() ve ardından checkStatus() çağrıları
  4. Cüzdan / kart akışı: Cüzdan bağlama, OTP doğrulama, kart ekleme/silme ve kart seçimi
  5. Ödeme ve sonuç: startPayment (veya startPaymentWithRegisteredCard), gerekirse 3D / ödeme OTP akışı; ardından paymentToken ile controlTransaction çağrısıyla nihai işlem sonucunun alınması (ekranlar sizin uygulamanızdadır)

Tüm operasyonlar Kotlin coroutines ile yürütülür ve **UI tarafı tamamen sizin kontrolünüzdedir. **


2. Teknik Gereksinimler

  • Minimum Android sürümü: minSdk 24
  • Derleme hedefi: compileSdk 36
  • Dil: Kotlin (1.9+ önerilir)
  • Asenkron yapı: Kotlin Coroutines
  • Maven artifact: com.bkm.mobil:sdk:0.0.6

3. Kurulum (Gradle)

Modül (app veya ilgili feature modülü) build.gradle.kts dosyasına aşağıdaki bağımlılık eklenmelidir:

// Maven artifact: com.bkm.mobil:sdk:0.0.6
dependencies {
implementation("com.bkm.mobil:sdk:0.0.6")
}

Repository tanımını proje kökündeki settings.gradle.kts veya üst seviye build.gradle dosyasına eklenmesi yeterlidir (Artifactory / Nexus URL ve kimlik bilgileri BKM tarafından paylaşılır).


4. Başlangıç Akışı

4.1. SDK Init Parametreleri

SdkInitParams, ödeme oturumunun temel iş parametrelerini taşır:

  • token: Backend’inizin oluşturduğu, SDK init çağrısında kullanılacak başlangıç token’ı
  • merchantId: İş yeri (merchant) tanımlayıcısı
  • gsmNo: Kullanıcının GSM numarası (örn. "5XXXXXXXXX")
  • merchantUserId: İş yerinizdeki kullanıcı kimliği
  • transactionId: İşlem / sipariş ile ilişkilendirilecek benzersiz işlem kimliği
  • environment: API sunucu ortamı (BexEnvironment: DEV, TEST, PREPROD, PROD).

Örnek:

val initParams = SdkInitParams(
token = "backend_initial_token",
merchantId = "MERCHANT_ID",
gsmNo = "5XXXXXXXXX",
merchantUserId = "merchant_user_id",
transactionId = "ORDER_OR_TX_ID",
environment = BexEnvironment.DEV // veya TEST, PREPROD, PROD
)

4.2. SDK’yı Başlatma

SDK, uygulama ömrü boyunca tek sefer başlatılmalıdır. Önerilen nokta, ödeme akışına girmeden önce (örneğin ilk ödeme ekranını açarken) Activity veya Fragment bağlamında yapılacak bir çağrıdır.

BexLiteSdk.init(
context = this,
initParams = initParams,
)

Ardından istemci alınır:

val client: BexPaymentClient = BexLiteSdk.getPaymentClient()

BexLiteSdk.getPaymentClient() çağrısı yalnızca init sonrası geçerlidir; aksi halde IllegalStateException fırlatılır.

4.3. Başlangıçta önerilen 4 akış (ekran yönlendirme)

SDK ilk senkronizasyonunun ardından (initializeSdk()), checkStatus() sonucundaki screen alanına göre uygulamada açılacak ilk ekran belirlenmelidir. Tipik başlangıç senaryoları aşağıdaki gibidir:

  1. LinkScreen: Kullanıcının iş yeri ile cüzdan eşleştirmesi gerekmektedir. Uygulamada “cüzdan bağlama” ekranı gösterilmelidir ve linkAccount() çağrısı bu ekrandan tetiklenmelidir.
  2. EnterOtpScreen: Devam eden bir OTP adımı bulunmaktadır. Uygulamada OTP giriş ekranı gösterilmeli ve verifyOTP(...) ile doğrulama yapılmalıdır.
  3. DashboardScreen: Cüzdan bağlıdır ve kart listesi gösterilebilir. Uygulamada kart listeleme/seçim ekranı açılmalı, kullanıcı aksiyonlarına göre kart ekleme/silme/ödeme akışlarına ilerlenmelidir.
  4. Diğer / bilinmeyen değerler: Geriye dönük uyumluluk veya beklenmeyen durumlar için genel bir fallback ekranı ve yeniden deneme (örn. checkStatus() tekrar çağrısı) stratejisi uygulanmalıdır.

5. Örnek Akış: SDK Başlatma ve Cüzdan Durumu

Tipik başlangıç senaryosu:

  1. initializeSdk() ile backend ile ilk senkronizasyon
  2. checkStatus() ile kullanıcının mevcut cüzdan durumu ve gösterilecek ilk ekranın belirlenmesi
lifecycleScope.launch {
when (val initResult = client.initializeSdk()) {
is BexResult.Success -> {
// initResult.data: bekleyen sözleşmeler + sözleşme açıklaması metni
val pendingAgreements = initResult.data.pendingAgreements
when (val checkResult = client.checkStatus()) {
is BexResult.Success -> {
val wallet = checkResult.data
when (wallet.screen) {
"LinkScreen" -> showLinkWalletScreen()
"DashboardScreen" -> showCardList(wallet.cards ?: emptyList())
"EnterOtpScreen" -> wallet.otpData?.let { showOtpScreen(it) }
else -> showGenericFallbackScreen()
}
}
is BexResult.Error -> showError(checkResult.error)
}
}
is BexResult.Error -> showError(initResult.error)
}
}

Burada tüm UI ekranları (showLinkWalletScreen, showCardList, showOtpScreen vb.) iş yeri tarafından tasarlanır ve yönetilir.


5.1. Bekleyen Sözleşmeler (Agreements) ve Onaylar (Approvals)

initializeSdk() başarılı olduğunda backend, kullanıcıdan onay bekleyen sözleşmeleri döndürür:

  • pendingAgreements: Sözleşme listesi

Örnek pendingAgreements dönüşü:

"pendingAgreements": [
{
"id": 1,
"code": "TERMS_OF_USE",
"type": "AGREEMENT",
"contentType": "HTML",
"title": "Kullanıcı Sözleşmesi",
"content": "<p>Kullanım Koşulları ...</p>",
"labelHighlight": "Kullanıcı Sözleşmesi",
"label": "Kullanıcı Sözleşmesini onaylıyorum.",
"mandatory": true
},
{
"id": 2,
"code": "KVKK",
"type": "INFO",
"contentType": "URL",
"title": "BKM EXPRESS KVKK Aydınlatma Metni",
"content": "https://bkmexpress.com.tr/KVKK",
"labelHighlight": "",
"label": "",
"mandatory": false
}
]

Notlar:

  • type = "AGREEMENT" olan kayıtlar için UI’da checkbox gösterilmelidir (metin: label, highlight: labelHighlight).
  • type = "INFO" olan kayıtlar için UI’da checkbox gösterilmez (ör. KVKK).
  • SDK, backend’e consent gönderirken tüm pendingAgreements kayıtlarını işler/gönderir.

5.1.1. Sözleşme UI gereksinimi (tek checkbox)

  • SDK’nın sunduğu standalone agreement checkbox bileşeni kullanılmalıdır.
  • Checkbox yanındaki metin uygulamada label ile gösterilebilir: [cb][text].

Compose - renk özelleştirme

BEXAgreementCheckbox varsayılan Material3 checkbox renklerini kullanır. İsterseniz aşağıdaki gibi renkleri özelleştirebilirsiniz:

Row {
BEXAgreementCheckbox(
colors = BEXAgreementCheckboxDefaults.colors(
checkedColor = Color(0xFF00B9C8),
uncheckedColor = Color(0xFFBDBDBD),
checkmarkColor = Color.White
),
onCheckedChange = { isChecked ->
// Örn. butonu enable/disable edebilirsiniz
// isSaveEnabled = isChecked
}
)
Text(text = agreement.label)
}

XML/View - renk özelleştirme

BEXAgreementCheckboxView için app: attribute’ları ile tint renklerini ayarlayabilirsiniz:


<com.bkm.mobil.sdk.lite.ui.BEXAgreementCheckboxView android:id="@+id/agreementCheckbox"
android:layout_width="wrap_content" android:layout_height="wrap_content"
app:bexAgreementCheckedColor="#00B9C8" app:bexAgreementUncheckedColor="#BDBDBD"
app:bexAgreementDisabledCheckedColor="#7F00B9C8"
app:bexAgreementDisabledUncheckedColor="#80BDBDBD" app:bexAgreementCheckmarkColor="#FFFFFF" />

XML/View - drawable özelleştirme (opsiyonel)

Varsayılan durumda BEXAgreementCheckboxView, AppCompat’in standart checkbox button drawable’ını kullanır. İsterseniz:

  • Sadece button drawable override:

<com.bkm.mobil.sdk.lite.ui.BEXAgreementCheckboxView android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:bexAgreementButtonDrawable="@drawable/my_checkbox_button" />
  • Tight mode (intrinsic inset yok, background selector ile çizim):

<com.bkm.mobil.sdk.lite.ui.BEXAgreementCheckboxView android:layout_width="24dp"
android:layout_height="24dp" app:bexAgreementTightMode="true"
app:bexAgreementTightBackground="@drawable/my_checkbox_selector" />

View tarafında kullanıcı etkileşimini yakalamak için Kotlin/Java ile agreementCheckbox.setOnApprovalChangedListener { checked -> ... } kullanabilirsiniz.

5.1.2. Onayların gönderimi

  • Checkbox durumuna göre SDK, tüm pendingAgreements için backend’e otomatik olarak onay gönderir:
    • Checked → ACCEPTED
    • Unchecked → REJECTED (backend bu durumda hata döndürür)

Backend’e giden örnek alan:

"agreementConsents": [
{"id": 1, "status": "ACCEPTED"},
{"id": 2, "status": "ACCEPTED"}
]

Kullanıcı sözleşmeleri onaylanmazsa backend şu hatayı döndürür: MISSED_MANDATORY_AGREEMENT ( 36).


6. Cüzdan Bağlama ve OTP Doğrulama

6.1. Cüzdanı İş Yerine Bağlama

lifecycleScope.launch {
when (val linkResult = client.linkAccount()) {
is BexResult.Success -> {
val data = linkResult.data
when (data.screen) {
"EnterOtpScreen" -> data.otpData?.let { showOtpScreen(it) }
"WalletScreen" -> checkStatus()
else -> showGenericFallbackScreen()
}
}
is BexResult.Error -> showError(linkResult.error)
}
}

6.2. OTP Doğrulama

Kullanıcı OTP’yi girdikten sonra:

lifecycleScope.launch {
val otpData = currentOtpData // OTP ekranına getiren yanıttan aldığınız veri
when (val result = client.verifyOTP(
otpValue = userOtpInput,
transactionId = otpData.transactionId,
otpRefNo = otpData.otpRefNo
)) {
is BexResult.Success -> {
// Gelen ekrana göre (dashboard, tekrar link vb.) UI güncellenmelidir
handleOtpSuccess(result.data)
}
is BexResult.Error -> showError(result.error)
}
}

Gerektiğinde OTP yeniden gönderimi için resendOTP benzer şekilde kullanılabilir.


7. Kart Yönetimi ve Güvenli Kart Girişi

SDK, kart numarasını kurum uygulamanızdan tamamen izole eden BEXSecureCardNumberField bileşenini sunar.
Bu sayede uygulamanız PCI-DSS kapsamı dışında tutulur; ham kart numarası yalnızca SDK içerisinde kalır.

7.1. Compose ile Güvenli Kart Girişi

import androidx.compose.runtime.*
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import com.bkm.mobil.sdk.lite.ui.BEXSecureCardNumberField
import com.bkm.mobil.sdk.lite.ui.rememberBEXSecureCardNumberState
import com.bkm.mobil.sdk.lite.api.BexLiteSdk
import kotlinx.coroutines.launch

@Composable
fun AddCardSection() {
val scope = rememberCoroutineScope()
val cardState = rememberBEXSecureCardNumberState()
val client = BexLiteSdk.getPaymentClient()
val pendingAgreements =
remember { emptyList<AgreementItem>() } // initResult.data.pendingAgreements
val agreement = remember { pendingAgreements.firstOrNull { it.type == "AGREEMENT" } }

Column {
BEXSecureCardNumberField(state = cardState)

// [cb][text]
agreement?.let {
Row {
BEXAgreementCheckbox()
Text(text = it.label)
}
}

Button(onClick = {
scope.launch {
val expiry = "1226" // MMYY formatında son kullanma tarihi
val tokenizedPan = cardState.getTokenizedPan(expiry) ?: return@launch

when (val res = client.storeCard(
tokenizedPan = tokenizedPan,
aliasName = null
)) {
is BexResult.Success -> handleCardInsertSuccess(res.data)
is BexResult.Error -> showError(res.error)
}
}
}) {
Text("Kartı Kaydet")
}
}
}
  • Önemli: Entegratör uygulama hiçbir noktada ham kart numarasına erişmez.
  • Kart ekleme storeCard(BexTokenizedPan, aliasName?) ile yapılır; BexTokenizedPan, güvenli kart bileşeninden (getTokenizedPan) üretilir. aliasName isteğe bağlı kart adıdır (null olabilir).
  • storeCard çağrısı, gerekirse OTP gereksinimini CardInsertResult.otpData üzerinden bildirir; akış sizin UI’niz üzerinden devam eder.

Kısmi kayıt (registerWithTokenizedPan) için de aynı BexTokenizedPan kullanılır; ham PAN veya son kullanma tarihi uygulama koduna alınmaz:

when (val res = client.registerWithTokenizedPan(
tokenizedPan = tokenizedPan,
aliasName = null
)) {
is BexResult.Success -> handleRegisterSuccess(res.data)
is BexResult.Error -> showError(res.error)
}

7.2. XML / View Bazlı Güvenli Kart Girişi (BEXSecureCardNumberEditText)

XML tabanlı ekranlarda güvenli kart girişi için BEXSecureCardNumberEditText bileşeni kullanılabilir. Ham kart numarası bu bileşenden de hiçbir zaman dışarı çıkmaz; yalnızca şifreli token üretilir.

XML Kullanımı:


<com.bkm.mobil.sdk.lite.ui.BEXSecureCardNumberEditText android:id="@+id/secureCardInput"
android:layout_width="match_parent" android:layout_height="wrap_content"
android:background="@drawable/bg_secure_card_input" android:padding="16dp"
android:contentDescription="@string/card_number_field" app:bexCardHint="•••• •••• •••• ••••"
app:bexCardTextColor="@color/on_surface" app:bexCardHintColor="@color/outline"
app:bexCardTextSize="18sp" app:bexCardLetterSpacing="0.08" app:bexCardShowUnderline="false" />

Kotlin Kullanımı:

val secureInput = findViewById<BEXSecureCardNumberEditText>(R.id.secureCardInput)

// Örn. "MMYY" formatında son kullanma tarihi
val expiry = "1226"

lifecycleScope.launch {
val tokenizedPan = secureInput.getTokenizedPan(expiry) ?: return@launch
when (val res = client.storeCard(tokenizedPan, aliasName = null)) {
is BexResult.Success -> handleCardInsertSuccess(res.data)
is BexResult.Error -> showError(res.error)
}
// Kısmi kayıt örneği (aynı tokenizedPan):
// when (val reg = client.registerWithTokenizedPan(tokenizedPan)) { ... }
}

Bu bileşende:

  • getText ve setText çağrıları her zaman IllegalStateException fırlatır (ham PAN erişimini engellemek için).
  • Kopyala-yapıştır, otomatik doldurma ve ham metnin erişilebilirlik ağaçlarına sızması engellenmiştir.
  • Tek güvenli çıktı, RSA-OAEP ile şifrelenmiş ve Base64 kodlanmış BexTokenizedPan nesnesidir.

7.3. Ödeme Başlatma ve İşlem Kontrolü (controlTransaction)

startPayment / startPaymentWithRegisteredCard çağrısı, backend’in kararına göre 3D Secure sayfası, OTP ekranı veya doğrudan paymentToken döndürebilir. Ödeme işleminin banka tarafındaki nihai durumunu (onay/red, tutar, slip bilgileri vb.) almak için elinizdeki paymentToken ile controlTransaction çağrılır.

paymentToken kaynakları (özet):

  • TransactionInitByCardIdResult.paymentToken: Ödeme init yanıtında (3D veya non-3D).
  • OtpControlResult.paymentToken: Ödeme OTP akışında verifyOTP başarılı olduktan sonra (ekran / iş kuralı backend’e göre değişir; demo uygulama belirli bir screen + dolu token kombinasyonunda kontrol çağrısı yapar).

Non-3D ve OTP’siz senaryo (init yanıtında paymentToken var ve bir sonraki adım doğrudan kontrol):

lifecycleScope.launch {
when (val payRes = client.startPayment(
orderId = orderId,
cardId = cardId,
amount = amount,
paymentSecurity = paymentSecurity
)) {
is BexResult.Success -> {
val data = payRes.data
val token = data.paymentToken
if (!token.isNullOrBlank() /* && ekran / iş kuralınıza göre kontrol adımı */) {
when (val ctrl = client.controlTransaction(paymentToken = token)) {
is BexResult.Success -> showPaymentResult(ctrl.data) // TransactionControlResult
is BexResult.Error -> showError(ctrl.error)
}
} else if (data.otpData != null) {
showOtpForPayment(data.otpData!!)
}
// 3D: tdsUrl/htmlForm ile WebView; tamamlanınca aynı init’ten gelen token ile controlTransaction
}
is BexResult.Error -> showError(payRes.error)
}
}

3D Secure tamamlandıktan sonra (ör. yönlendirme / callback URL’si uygulamanızda “işlem bitti” anlamına geldiğinde), init aşamasında sakladığınız paymentToken ile kontrol:

lifecycleScope.launch {
when (val ctrl = client.controlTransaction(paymentToken = paymentTokenFromInit)) {
is BexResult.Success -> showPaymentResult(ctrl.data)
is BexResult.Error -> showError(ctrl.error)
}
}

Ödeme OTP’si sonrası (verifyOTP cevabında paymentToken geldiğinde):

lifecycleScope.launch {
when (val res = client.verifyOTP(otpValue, transactionId, otpRefNo)) {
is BexResult.Success -> {
val token = res.data.paymentToken
if (!token.isNullOrBlank()) {
when (val ctrl = client.controlTransaction(paymentToken = token)) {
is BexResult.Success -> showPaymentResult(ctrl.data)
is BexResult.Error -> showError(ctrl.error)
}
} else {
// Backend’in döndüğü screen / cards ile devam
}
}
is BexResult.Error -> showError(res.error)
}
}

controlTransaction, ağ geçici hatalarında maxAttempts (varsayılan 2) ile sınırlı yeniden dener; sunucu/API hatalarında genelde tek seferlik hata döner. Ayrıntılar için Bölüm 8.2.11 bakınız.


8. API Referansı (Özet)

Bu bölümde, SDK’nın public API yüzeyi özetlenmektedir. Tüm çağrılar Kotlin ve coroutine tabanlıdır.

8.1. BexLiteSdk

Tekil giriş noktasıdır. Önce init, ardından getPaymentClient() kullanılır.

8.1.1. init

BexLiteSdk.init(
context: Context,
initParams: SdkInitParams
)
  • context: Uygulama veya Activity context (applicationContext önerilir).
  • initParams: token, merchantId, gsmNo, merchantUserId, transactionId, environment (varsayılan BexEnvironment.DEV).

Not: init çağrılmadan getPaymentClient() çağrılırsa IllegalStateException fırlatılır.

8.1.2. getPaymentClient

val client: BexPaymentClient = BexLiteSdk.getPaymentClient()

init sonrası çağrılır. Dönen istemci ile tüm ödeme ve cüzdan işlemleri gerçekleştirilir.


8.2. BexPaymentClient

Tüm metotlar suspend fonksiyondur; coroutine içinden çağrılmalıdır.

8.2.1. initializeSdk

suspend fun initializeSdk(): BexResult<SdkInitResult>

Backend ile SDK başlatma (token, encKey). Init parametreleri BexLiteSdk.init ile sağlanır.
Başarılı olduğunda:

  • SdkInitResult.pendingAgreements: bekleyen sözleşmeler

Hata durumunda BexResult.Error(BexSdkError) döner.

8.2.2. checkStatus

suspend fun checkStatus(): BexResult<WalletCheckResult>

Cüzdan durumunu sorgular. Dönen WalletCheckResult şu alanları içerir:

  • screen: Gösterilmesi önerilen ekran (LinkScreen, DashboardScreen, EnterOtpScreen vb.)
  • cards: Kullanıcıya ait kart listesi (List<BexCardInfo>?)
  • otpData: OTP akışı için gerekli bilgiler (OtpData?)

8.2.3. linkAccount

suspend fun linkAccount(): BexResult<LinkWalletResult>

Cüzdanı iş yerine bağlar. Sonuçta screen ve gerekiyorsa otpData bulunur; OTP ekranı entegratör tarafından gösterilir.

8.2.4. verifyOTP

suspend fun verifyOTP(
otpValue: String,
transactionId: String,
otpRefNo: String
): BexResult<OtpControlResult>

OTP doğrulama işlemini gerçekleştirir. transactionId ve otpRefNo değerleri, OTP ekranına getiren yanıttaki OtpData içinden alınmalıdır.

8.2.5. resendOTP

suspend fun resendOTP(
transactionId: String,
otpRefNo: String
): BexResult<OtpResendResult>

Aynı işlem için OTP’nin yeniden gönderilmesini sağlar. transactionId ve otpRefNo, ilgili OtpData içinden alınır.

8.2.6. storeCard

suspend fun storeCard(
tokenizedPan: BexTokenizedPan,
aliasName: String? = null
): BexResult<CardInsertResult>

Yeni kart ekler. merchantId init parametrelerinden alınır. tokenizedPan, yalnızca BEXSecureCardNumberField / BEXSecureCardNumberEditText üzerinden üretilen şifreli değerdir ( Bölüm 7). aliasName isteğe bağlı kart adıdır.
Sonuç OTP gerektiriyorsa CardInsertResult.otpData dolu dönebilir (backend kararıdır).

8.2.7. cardDelete

suspend fun cardDelete(cardId: String): BexResult<CardDeleteResult>

Kayıtlı bir kartı siler. Başarılı yanıtta güncellenmiş kart listesi CardDeleteResult.cards içinde döner.

8.2.8. registerWithTokenizedPan

suspend fun registerWithTokenizedPan(
tokenizedPan: BexTokenizedPan,
aliasName: String? = null
): BexResult<RegisterResult>

Kısmi kayıt akışını yürütür; ham kart numarası veya son kullanma tarihi parametre olarak **yoktur **.
GSM numarası SDK init’inden (SdkInitParams.gsmNo) alınır.

8.2.9. startPayment (KartId ile Ödeme Başlatma)

Kayıtlı bir kart (cardId) ile ödeme başlatır. Güvenlik türü PaymentSecurity ile seçilir:

  • TDS: 3D Secure init endpoint’i; tdsUrl / htmlForm beklenir.
  • OTP: Non-3D init; istek gövdesinde withOtp = true.
  • NONE: Non-3D init; istek gövdesinde withOtp = false.

Önemli: withOtp ve PaymentSecurity yalnızca istemci tarafı tercihidir. İş kuralı veya banka, OTP veya NONE göndermenize rağmen OTP döndürmeyebilir veya tersine OTP zorunlu kılabilir. Her zaman yanıttaki otpData, screen, paymentToken ve 3DS alanlarına göre akış seçilmelidir.

suspend fun startPayment(
orderId: String,
cardId: String,
amount: Double,
paymentSecurity: PaymentSecurity = PaymentSecurity.NONE,
currency: String = "TRY",
installmentCount: Int = 1
): BexResult<TransactionInitByCardIdResult>

8.2.10. startPaymentWithRegisteredCard (tokenizedPan / encData ile Ödeme Başlatma)

Kayıtlı cardId yerine, güvenli kart bileşeninden üretilen BexTokenizedPan (encData olarak) ile ödeme başlatır. Parametreler ve PaymentSecurity semantiği startPayment ile aynıdır.

suspend fun startPaymentWithRegisteredCard(
orderId: String,
tokenizedPan: BexTokenizedPan,
amount: Double,
paymentSecurity: PaymentSecurity = PaymentSecurity.NONE,
currency: String = "TRY",
installmentCount: Int = 1
): BexResult<TransactionInitByCardIdResult>

8.2.11. controlTransaction (İşlem / Ödeme Sonucu Sorgulama)

paymentToken ile işlemin güncel sonucunu backend’den sorgular. Bu token genellikle startPayment / startPaymentWithRegisteredCard yanıtında veya ödeme OTP’si sonrası verifyOTP yanıtında (OtpControlResult.paymentToken) gelir. 3D Secure akışında, kullanıcı banka sayfasında işlemi tamamladıktan sonra (WebView tamamlanma veya redirect sonrası) init sırasında aldığınız paymentToken ile çağrı yapılır.

suspend fun controlTransaction(
paymentToken: String,
maxAttempts: Int = 2
): BexResult<TransactionControlResult>
  • paymentToken: Boş veya yalnızca boşluk olamaz; aksi halde hata döner.
  • maxAttempts: En az 1 olacak şekilde kullanılır. SDK, ağ / bilinmeyen geçici hatalarda en fazla bu kadar deneme yapabilir; Api tipindeki sunucu hatalarında yeniden denemez. Yanıtta success == true görülür görülmez başarılı sonuç döner; aksi halde son yanıt veya hata ile BexResult üretilir.

Örnek (init sonrası doğrudan kontrol):

lifecycleScope.launch {
when (val payRes = client.startPayment(orderId, cardId, amount, paymentSecurity)) {
is BexResult.Success -> {
val token = payRes.data.paymentToken
if (!token.isNullOrBlank()) {
when (val ctrl = client.controlTransaction(paymentToken = token)) {
is BexResult.Success -> {
val r = ctrl.data
if (r.success == true) {
// r.authCode, r.successAmount, r.orderId vb.
} else {
// r.message, r.code ile kullanıcı bilgilendirmesi
}
}
is BexResult.Error -> showError(ctrl.error)
}
}
}
is BexResult.Error -> showError(payRes.error)
}
}

8.3. Sonuç Tipleri (BexResult)

Tüm istemci metotları BexResult<T> döner:

  • BexResult.Success(data: T): İşlem başarıyla tamamlanmıştır.
  • BexResult.Error(error: BexSdkError): Hata durumunda kullanılır; error.displayMessage son kullanıcılara gösterilebilir.

8.4. Veri Modelleri (Özet)

Başlıca veri modelleri aşağıdaki gibidir:

  • WalletCheckResult: screen, cards: List<BexCardInfo>?, otpData: OtpData?
  • LinkWalletResult: screen, otpData?
  • OtpControlResult: screen, cards?, cardId?, paymentToken? (ödeme kontrolü için)
  • OtpResendResult: transactionId, durationTimeInSeconds, otpLength, gsmNo, otpRefNo, sender?
  • CardInsertResult: screen, otpData?
  • RegisterResult: screen, cards?, otpData?, transactionId?
  • BexCardInfo: cardId, maskCardNumber, cardAlias, binValue, imageUrl, bankInformation, active
  • BexBankInformation: cardType, cardBrandType, cardBrand, bankShortName
  • OtpData: transactionId, durationTimeInSeconds, otpLength, gsmNo, otpRefNo, sender
  • TransactionInitByCardIdResult: is3D, screen, paymentToken, otpData, 3D için tdsUrl / htmlForm, ek alanlar success, message, code, bankTransactionId, orderId, key vb.
  • TransactionControlResult: İşlem kontrolü sonucu; success, message, code, orderId, successAmount, authCode, hostRefNum, cardNumber (maskeli), tarih ve terminal bilgileri vb. (alanların doluluğu backend yanıtına bağlıdır)

Örnek kart modeli (backend yanıtı):

{
"cardId": "019d2dad-34bc-7b00-959d-0bef3009afa5",
"maskCardNumber": "123456******1234",
"cardAlias": "Maaş Kartım",
"binValue": "12345678",
"imageUrl": "https://...default_card.png",
"bankInformation": {
"cardType": "CreditCard",
"cardBrandType": "Marka Yok",
"cardBrand": "Troy",
"bankShortName": "TESTBANK"
},
"active": true
}

8.5. BexSdkError

Başlıca hata türleri:

  • Api
  • Network
  • Cancelled
  • Unauthorized
  • Unknown

Son kullanıcılara gösterilecek mesaj için displayMessage alanı kullanılmalıdır.

Detaylı model alanları için SDK içindeki veri sınıflarına (model paketleri) başvurulabilir.


9. Hata Yönetimi ve Sonuç Tipleri (Uygulama Örneği)

Entegre bir hata gösterimi için basit bir kullanım örneği:

when (val result = client.checkStatus()) {
is BexResult.Success -> {
// result.data ile devam edilmelidir
}
is BexResult.Error -> {
Toast.makeText(context, result.error.displayMessage, Toast.LENGTH_SHORT).show()
// İsteğe bağlı: error türüne göre (Network, Api, Unauthorized vb.) loglama
}
}