Ana içeriğe geç

BEX Lite SDK Entegrasyonu

Bu doküman, BEX Lite SDK'nın iOS 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ı: BKMExpress.initialize(context:) ile oturum ve iş parametrelerinin tanımlanmasıyla bir API nesnesi elde edilmesi
  2. Backend ile ilk senkronizasyon: initialize çağrısı başarılı olduğunda sözleşmeler ve şifreleme anahtarı otomatik olarak hazırlanır
  3. Cüzdan durumu: checkStatus() ile kullanıcının mevcut durumunun sorgulanması
  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 controlPayment çağrısıyla nihai işlem sonucunun alınması (ekranlar sizin uygulamanızdadır)

Tüm operasyonlar Swift Concurrency (async/await) ile yürütülür ve UI tarafı tamamen sizin kontrolünüzdedir.


2. Teknik Gereksinimler

  • Minimum iOS sürümü: iOS 15.0+
  • Dil: Swift
  • Asenkron yapı: Swift Concurrency (async/await)
  • UI Çerçeveleri: SwiftUI ve UIKit için ayrı bileşenler mevcuttur; SwiftUI bileşenleri UIKit desteklenmeyen platformlarda (örn. macOS) çalışmaz

3. Kurulum

BEX Lite SDK yalnızca Swift Package Manager ile dağıtılmaktadır.

3.1. Xcode Proje Ayarlarından Ekleme

Projenizin Package Dependencies bölümünden gerekli sürüm bilgisini girerek SDK'yı ekleyebilirsiniz.

3.2. Package.swift ile Ekleme

Başka bir Swift Package içinde kullanılacaksa:

  1. Package.swift dosyanızdaki dependencies parametresine bağımlılığı ekleyin:
.package(url: "https://github.com/BKMExpress/iOS-Lite-SDK.git", branch: "main")
  1. Bağımlılığı kullanmak istediğiniz target'in dependencies kısmına SDK product'ını ekleyin:
"BKMExpressLiteSDK"

4. Başlangıç Akışı

4.1. SDK Başlatma Parametreleri

BKMExpress.InitializationContext, ödeme oturumunun temel iş parametrelerini taşır:

  • authToken: Backend'inizin oluşturduğu, SDK başlatma çağrısında kullanılacak token
  • merchantID: İş yeri (merchant) tanımlayıcısı
  • merchantUserID: İş yerinizdeki kullanıcı kimliği
  • gsmNo: Kullanıcının GSM numarası (BKMExpress.GSMNO struct'ı olarak; örn. "5XXXXXXXXX")
  • currencyCode: Ödeme para birimi kodu (büyük harf ISO 4217 formatında; örn. "TRY", "USD", "EUR"). Desteklenmeyen bir değer gönderilirse backend INVALID_CURRENCY hatası döner (bkz. Bölüm 9.1).
  • mode: API sunucu ortamı (BKMExpress.Mode: .test, .preprod, .production)

Örnek:

let context = BKMExpress.InitializationContext(
authToken: "backend_initial_token",
merchantID: "MERCHANT_ID",
merchantUserID: "merchant_user_id",
gsmNo: try .init("5XXXXXXXXX"),
currencyCode: "TRY", // ISO 4217 para birimi kodu
mode: .test // veya .preprod, .production
)

BKMExpress.GSMNO struct'ı kendi doğrulama kurallarını işletir: 10 haneli, yalnızca rakamlardan oluşan ve 5 ile başlayan bir numara beklenir. Aksi hâlde InitializationError fırlatılır.

4.2. SDK'yı Başlatma ve API Nesnesini Alma

BKMExpress.initialize(context:) çağrısı, oturumu başlatır ve tüm SDK işlemlerini yürüteceğiniz API nesnesini döndürür. Bu çağrı ödeme akışına girmeden önce, API nesnesini kullanacak ekranın bir önceki adımında yapılmalıdır.

func pairButtonTapped() async {
do {
let api = try await BKMExpress.initialize(context: context)
// API nesnesini kullanacak ekrana tercih ettiğiniz DI mekanizmasıyla iletin.
// Örn: delegate?.bkmExpressInitialized(api)
} catch {
showAlert("BKM Express başlatılamadı.")
}
}

Önemli: Optional kontrollerinden kaçınmak için API nesnesini kullanacağınız ekranda oluşturmak yerine bir önceki ekranda oluşturup DI ile iletmeniz tavsiye edilir.

4.3. Başlangıçta Önerilen Akış (Ekran Yönlendirme)

SDK başlatıldıktan sonra checkStatus() sonucuna göre uygulamada açılacak ilk ekran belirlenir. Tipik başlangıç senaryoları:

  1. .unregistered: Kullanıcı hiç kayıtlı değildir. Kayıt akışı (register) veya kart ekleme ekranı gösterilmelidir.
  2. .unlinked: Kullanıcı kayıtlıdır ancak iş yeriyle eşleştirme yapmamıştır. "Cüzdan bağlama" ekranı gösterilmeli ve linkAccount() bu ekrandan tetiklenmelidir.
  3. .linked(cards): Cüzdan bağlıdır ve kart listesi gösterilebilir. Kart listeleme/seçim ekranı açılmalı, kullanıcı aksiyonlarına göre kart ekleme/silme/ödeme akışlarına ilerlenmelidir.

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

Tipik başlangıç senaryosu:

  1. BKMExpress.initialize(context:) ile oturum başlatma ve API nesnesini alma
  2. checkStatus() ile kullanıcının mevcut cüzdan durumu ve gösterilecek ilk ekranın belirlenmesi
func startBKMExpressFlow() async {
do {
let api = try await BKMExpress.initialize(context: context)

let status = try await api.checkStatus()
switch status {
case let .linked(cards):
showCardList(cards)
case .unlinked:
showLinkWalletScreen(api: api)
case .unregistered:
showRegistrationScreen(api: api)
}
} catch let error as BKMExpress.Failure {
showError(error.message)
}
}

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


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

BKMExpress.initialize(context:) başarılı olduğunda bekleyen sözleşmeler SDK içinde hazır hâle gelir. Bu sözleşmelere api.pendingAgreements() metoduyla erişilir.

let agreements = api.pendingAgreements()

Örnek sözleşme alanları:

  • id: Sözleşmenin tanımlayıcısı
  • code: Sözleşme kodu (örn. "TERMS_OF_USE", "KVKK")
  • kind: Sözleşme türü (.agreement veya .info)
  • title: Sözleşmenin başlığı
  • content: Sözleşmenin içeriğinin bulunduğu URL
  • label: Checkbox yanında gösterilecek metin
  • labelHighlight: Label içinde vurgulanacak metin
  • mandatory: Onayın zorunlu olup olmadığı

Notlar:

  • kind == .agreement olan kayıtlar için UI'da checkbox gösterilmelidir (metin: label, highlight: labelHighlight).
  • kind == .info olan kayıtlar için checkbox gösterilmez (örn. KVKK).
  • SDK, backend'e onay gönderirken tüm pendingAgreements kayıtlarını işler.

5.1.1. Sözleşme UI Gereksinimi (Tek Checkbox)

SDK'nın sunduğu standalone agreement checkbox bileşeni kullanılmalıdır.

Önemli: Checkbox bileşeninin UI hiyerarşinizde yalnızca bir adet bulunduğundan emin olun. Aksi takdirde onay mekanizması beklendiği gibi çalışmayabilir.

SwiftUI — Renk Özelleştirme

BKMExpressAgreementCheckboxView varsayılan görünümüyle kullanılabilir; isteğe bağlı özelleştirme parametreleri de mevcuttur:

HStack {
BKMExpressAgreementCheckboxView(
isSelected: $isCheckboxSelected,
checkmarkTint: Color(hex: "#FFFFFF"),
borderColor: Color(hex: "#BDBDBD"),
errorTintColor: .red,
disabledTintColor: .gray
)
Text(agreement.label)
}

UIKit — Renk Özelleştirme

BKMExpressAgreementCheckbox, UIControl subclass'ıdır. Renkleri doğrudan property'ler aracılığıyla ayarlayabilirsiniz:

let checkbox = BKMExpressAgreementCheckbox()
checkbox.tintColor = UIColor(hex: "#00B9C8")
checkbox.checkmarkColor = .white
checkbox.borderColor = UIColor(hex: "#BDBDBD")
checkbox.disabledTintColor = UIColor(hex: "#80BDBDBD")
checkbox.errorTintColor = .red

5.1.2. Onayların Gönderimi

Checkbox durumuna göre SDK, tüm pendingAgreements için backend'e otomatik olarak onay gönderir. Kullanıcı sözleşmeleri onaylanmazsa backend MISSED_MANDATORY_AGREEMENT (36) hatasını döndürür.


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

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

func linkBKMExpress() async {
do {
let response = try await api.linkAccount()
switch response {
case .recheck:
// Hesap bağlandı; kart listesi için checkStatus() yeniden çağrılmalıdır.
let status = try await api.checkStatus()
handleCheckStatus(status)
case let .verificationRequired(otp):
showOtpScreen(otp: otp)
}
} catch let error as BKMExpress.Failure {
showError(error.message)
}
}

6.2. OTP Doğrulama

Her OTP nesnesi (LinkOTP, StoreCardOTP, RegisterOTP, PaymentOTP) aynı arayüzü (BKMExpress.OTP protokolü) paylaşır. Kullanıcı OTP'yi girdikten sonra:

func verifyOTP(otp: some BKMExpress.OTP, code: String) async {
do {
let result = try await otp.verify(code: code)
handleOtpSuccess(result)
} catch let error as BKMExpress.Failure {
showError(error.message)
}
}

OTP'yi yeniden göndermek için:

func resendOTP(otp: some BKMExpress.OTP) async {
do {
let newInfo = try await otp.resend()
// newInfo ile OTP ekranı güncellenir.
// Dilerseniz aynı bilgiye otp.info üzerinden de erişebilirsiniz.
updateOtpUI(info: newInfo)
} catch let error as BKMExpress.Failure {
showError(error.message)
}
}

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

SDK, kart numarasını kurum uygulamanızdan tamamen izole eden BKMExpressCardNumberField (UIKit) ve BKMExpressCardNumberView (SwiftUI) bileşenlerini sunar. Bu sayede uygulamanız PCI-DSS kapsamı dışında tutulur; ham kart numarası yalnızca SDK içinde kalır.

7.1. SwiftUI ile Güvenli Kart Girişi

// Bu view oluşturulmadan önce başarılı initialize() çağrısının yapıldığından emin olunuz.
struct AddCardScreen: View {
@State var cardNumber: BKMExpress.CardNumber?
@State var isCheckboxSelected = false

var body: some View {
VStack {
BKMExpressCardNumberView(
font: .systemFont(ofSize: 17),
placeholder: "Kart Numarası",
number: $cardNumber
)

// iOS 26 ve sonrasında font modifier ile de kullanılabilir:
// BKMExpressCardNumberView(placeholder: "Kart Numarası", number: $cardNumber)
// .font(.system(size: 17))

if let agreement = agreements.first(where: { $0.kind == .agreement }) {
HStack {
BKMExpressAgreementCheckboxView(isSelected: $isCheckboxSelected)
Text(agreement.label)
}
}

Button("Kartı Kaydet") {
Task { await storeCard() }
}
}
}
}

Önemli: Entegratör uygulama hiçbir noktada ham kart numarasına erişemez. cardNumber binding'i yalnızca SDK'nın type-safe BKMExpress.CardNumber wrapper'ını içerir.

BKMExpressCardNumberView'ün AttributedString placeholder kabul eden bir versiyonu da mevcuttur:

BKMExpressCardNumberView(
font: .systemFont(ofSize: 17),
attributedPlaceholder: attributedPlaceholder,
number: $cardNumber
)

7.2. UIKit ile Güvenli Kart Girişi (BKMExpressCardNumberField)

BKMExpressCardNumberField bir UITextField subclass'ıdır ve subclass edilebilir. text ile attributedText gibi özellikler güvenlik nedeniyle kapatılmıştır. Bileşenin original delegate'i (UITextFieldDelegate) yerine bkmExpressDelegate kullanılmalıdır.

// Bu controller oluşturulmadan önce başarılı initialize() çağrısının yapıldığından emin olunuz.
class AddCardViewController: UIViewController, BKMExpressCardNumberFieldDelegate {
let cardNumberField = BKMExpressCardNumberField()
let checkbox = BKMExpressAgreementCheckbox()

override func viewDidLoad() {
super.viewDidLoad()
cardNumberField.bkmExpressDelegate = self
checkbox.addTarget(self, action: #selector(checkboxChanged), for: .valueChanged)
// Layout kurulumu...
}

func bkmExpressCardNumberField(
_ field: BKMExpressCardNumberField,
didReceiveValidCardNumber cardNumber: BKMExpress.CardNumber
) {
// Geçerli bir kart numarası alındı; gerekirse devam tuşunu aktifleştirebilirsiniz.
}

@objc func checkboxChanged(_ checkbox: BKMExpressAgreementCheckbox) {
print("Checkbox durumu: \(checkbox.isSelected)")
}
}

Interface Builder kullanıyorsanız bkmExpressDelegate atamasını koddan yapmalısınız.

Bu bileşende:

  • text ve attributedText özellikleri güvenlik nedeniyle erişime kapatılmıştır.
  • Kopyala/kes işlemleri engellenir; ham metin hiçbir zaman dışarı çıkmaz.
  • Tek güvenli çıktı, RSA-OAEP ile şifreli BKMExpress.CardNumber nesnesidir.

7.3. Kart Ekleme (storeCard)

func storeCard() async {
guard let number = cardNumber else { return }
let expiryDate = try! BKMExpress.CardExpiryDate(month: 12, year: 2026)

do {
let response = try await api.storeCard(
context: .init(
number: number,
expiryDate: expiryDate,
alias: nil // İsteğe bağlı kart adı
)
)
switch response {
case let .added(cards):
showCardList(cards)
case let .verificationRequired(otp):
showOtpScreen(otp: otp)
}
} catch let error as BKMExpress.Failure {
showError(error.message)
}
}

7.4. Kart Silme (deleteCard)

func deleteCard(id: BKMExpress.Card.ID) async {
do {
let response = try await api.deleteCard(id: id)
switch response {
case let .cardDeleted(cards):
showCardList(cards)
case .accountDeleted:
// Son kart silindi; BKM Express hesabı da silindi.
showRegistrationScreen()
}
} catch let error as BKMExpress.Failure {
showError(error.message)
}
}

7.5. Ödeme Başlatma ve İşlem Kontrolü (controlPayment)

startPayment / startPaymentWithRegisteredCard çağrısı sırasında kullandığınız successUrl ve failUrl değerleri, ödeme init isteğiyle birlikte BEX backend’ine gönderilir. Amaç, ödeme süreci (3D Secure dahil) tamamlandığında iş yeri backend’inizin ilgili adrese yönlendirilerek veya sunucu bildirimi alarak ödeme sonucunu öğrenmesini sağlamaktır.

startPayment / startPaymentWithRegisteredCard çağrısı, backend'in kararına göre 3D Secure bilgisi, OTP nesnesi veya doğrudan PaymentToken döndürebilir. Ödeme işleminin nihai durumunu almak için elinizdeki PaymentToken ile controlPayment çağrılır.

Non-3D ve OTP'siz senaryo (init yanıtında .control(token) geldiğinde):

func startAndControlPayment(cardID: BKMExpress.Card.ID) async {
do {
let response = try await api.startPayment(
context: .init(
cardID: cardID,
security: .none,
amount: 100.00,
orderID: "ORDER_123",
installmentCount: .init(1)!
)
)
switch response {
case let .control(token):
let result = try await api.controlPayment(token: token)
showPaymentResult(result)
case let .otp(otp):
showOtpForPayment(otp: otp)
case let .tds(tdsInfo):
showTdsWebView(tdsInfo: tdsInfo)
}
} catch let error as BKMExpress.Failure {
showError(error.message)
}
}

3D Secure tamamlandıktan sonra (WebView'da işlem bitti anlamına gelen yönlendirme/callback algılandığında), init aşamasında sakladığınız TDSInfo.paymentToken ile:

func onTdsCompleted(token: BKMExpress.PaymentToken) async {
do {
let result = try await api.controlPayment(token: token)
showPaymentResult(result)
} catch let error as BKMExpress.Failure {
showError(error.message)
}
}

Ödeme OTP'si sonrası (PaymentOTP.verify cevabında PaymentToken geldiğinde):

func onPaymentOtpVerified(otp: BKMExpress.PaymentOTP, code: String) async {
do {
let token = try await otp.verify(code: code)
let result = try await api.controlPayment(token: token)
showPaymentResult(result)
} catch let error as BKMExpress.Failure {
showError(error.message)
}
}

8. API Referansı (Özet)

Bu bölümde SDK'nın public API yüzeyi özetlenmektedir. Tüm çağrılar Swift Concurrency (async/await) tabanlıdır.

8.1. BKMExpress

Tekil giriş noktasıdır. initialize(context:) ile API nesnesi elde edilir.

8.1.1. initialize

static func initialize(
context: BKMExpress.InitializationContext
) async throws(BKMExpress.Failure) -> BKMExpress.API
  • context: authToken, merchantID, merchantUserID, gsmNo, currencyCode, mode parametrelerini içerir.
  • Başarılı olduğunda sözleşmeler ve şifreleme anahtarı otomatik olarak hazırlanır.
  • Hata durumunda BKMExpress.Failure fırlatır.

8.2. BKMExpress.API

Tüm metotlar async throws(BKMExpress.Failure) imzasına sahiptir; Swift Concurrency bağlamından çağrılmalıdır.

8.2.1. checkStatus

func checkStatus() async throws(Failure) -> CheckStatusResponse

Cüzdan durumunu sorgular. Dönen CheckStatusResponse:

  • .linked([Card]): Kullanıcının hesabı vardır, bağlıdır ve kart listesi döner.
  • .unlinked: Kullanıcının hesabı vardır ancak bağlama yapılmamıştır.
  • .unregistered: Kullanıcı kayıtlı değildir.

8.2.2. linkAccount

func linkAccount() async throws(Failure) -> LinkAccountResponse

Cüzdanı iş yerine bağlar. Dönen LinkAccountResponse:

  • .recheck: Hesap başarıyla bağlandı; kart listesi için checkStatus() yeniden çağrılmalıdır.
  • .verificationRequired(LinkOTP): OTP doğrulaması gerekiyor; dönen LinkOTP nesnesi üzerinden verify(code:) çağrılmalıdır.

8.2.3. storeCard

func storeCard(
context: StoreCardContext
) async throws(Failure) -> StoreCardResponse

Yeni kart ekler. StoreCardContext şu alanları içerir: number (CardNumber), expiryDate (CardExpiryDate), alias (isteğe bağlı). Dönen StoreCardResponse:

  • .added([Card]): Kart eklendi; güncellenmiş kart listesi döner.
  • .verificationRequired(StoreCardOTP): OTP doğrulaması gerekiyor.

8.2.4. deleteCard

func deleteCard(id: BKMExpress.Card.ID) async throws(Failure) -> DeleteCardResponse

Kayıtlı bir kartı siler. Dönen DeleteCardResponse:

  • .cardDeleted([Card]): Kart silindi; güncellenmiş kart listesi döner.
  • .accountDeleted: Kullanıcının son kartı ve BKM Express hesabı silindi.

8.2.5. register

func register(
context: RegisterContext
) async throws(Failure) -> RegisterResponse

Telefon numarasını kart bilgisiyle "kısmi" kayıt eder. RegisterContext şu alanları içerir: number (CardNumber), expiryDate (CardExpiryDate), alias (isteğe bağlı). Dönen RegisterResponse:

  • .verificationRequired(RegisterOTP): OTP doğrulaması gerekiyor.

8.2.6. startPayment (Kayıtlı Kart ile Ödeme)

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

  • .tds: 3D Secure; yanıtta TDSInfo (htmlForm, tdsURL vb.) beklenir.
  • .otp: OTP doğrulamalı non-3D ödeme.
  • .none: Doğrulama mekanizması olmaksızın ödeme.

Önemli: PaymentSecurity yalnızca istemci tarafı tercihtir. İş kuralı veya banka, tercihinizden bağımsız farklı bir akış döndürebilir. Her zaman yanıttaki case'e göre akış seçilmelidir.

successUrl ve failUrl alanları, ödeme sürecinin tamamlanma durumunu iş yeri backend’inize bildirmek amacıyla kullanılır. SDK bu adresleri mobil uygulama içinden doğrudan çağırmaz; startPayment / startPaymentWithRegisteredCard ile tetiklenen ödeme init isteklerinde BEX backend’ine iletilir. Böylece 3D Secure veya banka tarafı akışı sonunda iş yeri sunucunuz, ödemenin başarılı veya başarısız sonuçlandığını sunucu tarafında öğrenebilir.

func startPayment(
context: StartPaymentContext
) async throws(Failure) -> StartPaymentResponse

StartPaymentContext şu alanları içerir: cardID, security (PaymentSecurity), amount (Decimal), orderID, date, transactionID (UUID), installmentCount (InstallmentCount), successUrl, failUrl.

Dönen StartPaymentResponse:

  • .tds(TDSInfo): 3D Secure doğrulaması gerekiyor.
  • .otp(PaymentOTP): OTP doğrulaması gerekiyor.
  • .control(PaymentToken): Ödeme sonucu doğrulama gerektirmeksizin kontrol edilebilir.

8.2.7. startPaymentWithRegisteredCard (Yeni Kart ile Ödeme)

Kayıtlı olmayan bir kart ile ödeme başlatır ve kartı kullanıcının hesabına kaydeder. successUrl / failUrl davranışı startPayment ile aynıdır. Parametreler ve PaymentSecurity semantiği startPayment ile aynıdır.

func startPaymentWithRegisteredCard(
context: StartPaymentWithRegisteredCardContext
) async throws(Failure) -> StartPaymentResponse

StartPaymentWithRegisteredCardContext şu alanları içerir: card (CardNumber + CardExpiryDate

  • opsiyonel alias), security, amount, currencyCode (CurrencyCode), orderID, date, transactionID, installmentCount, successUrl, failUrl.

8.2.8. controlPayment (İşlem / Ödeme Sonucu Sorgulama)

PaymentToken ile işlemin güncel sonucunu backend'den sorgular. Bu token genellikle startPayment / startPaymentWithRegisteredCard yanıtındaki .control(token) case'inden veya ödeme OTP'si onayı sonrası PaymentOTP.verify(code:) dönüşünden elde edilir. 3D Secure akışında, kullanıcı banka sayfasında işlemi tamamladıktan sonra TDSInfo.paymentToken ile çağrı yapılır.

func controlPayment(
token: PaymentToken
) async throws(Failure) -> ControlPaymentResponse

Dönen ControlPaymentResponse şu başlıca alanları içerir: success, message, code, orderID, successAmount, authCode, hostRefCode, hostRefNum, cardNumber (maskeli), tarih ve terminal bilgileri.

8.2.9. pendingAgreements

func pendingAgreements() -> [Agreement]

Kart ekleme ve kayıt akışlarında kullanıcıya gösterilmesi gereken sözleşmeleri döndürür. Bu metot, initialize çağrısının ardından geçerli hâle gelir.


8.3. Sonuç Tipleri

Tüm API metotları typed throws ile BKMExpress.Failure fırlatır:

  • Başarı: Metodun dönüş değeri doğrudan kullanılır.
  • Hata: catch let error as BKMExpress.Failure ile yakalanır; error.message son kullanıcılara gösterilebilir.

8.4. Veri Modelleri (Özet)

Başlıca veri modelleri:

  • BKMExpress.Card: id, alias, maskedCardNumber, imageURL, bankInformation, bin, createTime
  • BKMExpress.Card.BankInformation: bankShortName, cardType, cardScheme, cardBrand, bankCode
  • BKMExpress.OTPInfo: id, sender, referenceNumber, receiver, durationInSeconds, length, resendTimeInSeconds
  • BKMExpress.TDSInfo: htmlForm, tdsURL, orderID, paymentToken, code, message, success, bankTransactionID
  • BKMExpress.ControlPaymentResponse: success, message, code, orderID, successAmount, authCode, hostRefCode, hostRefNum, cardNumber, bankTransactionID, bankTransactionDate, transactionDate, paymentID, secureType, installment vb.
  • BKMExpress.Agreement: id, code, kind (.agreement / .info), title, content (URL), label, labelHighlight, mandatory
  • BKMExpress.CardExpiryDate: month, year, formatted; tamsayılar, "mm/yyyy" string'i veya Date objesinden oluşturulabilir
  • BKMExpress.CurrencyCode: Geçerli ISO 4217 kodunu temsil eder; statik .TRY, .USD, .EUR sabitleri mevcuttur
  • BKMExpress.InstallmentCount: Pozitif tamsayıdan oluşturulur; 0 ve negatif değerler için nil döner (failable initializer)
  • BKMExpress.PaymentSecurity: .otp, .tds, .none

Örnek kart modeli:

let card: BKMExpress.Card
// card.id.rawValue -> "019d2dad-34bc-7b00-959d-0bef3009afa5"
// card.maskedCardNumber -> "123456******1234"
// card.alias -> "Maaş Kartım"
// card.bin -> "12345678"
// card.imageURL -> URL(string: "https://...default_card.png")
// card.bankInformation.cardType -> "CreditCard"
// card.bankInformation.cardBrand -> "Troy"
// card.bankInformation.bankShortName -> "TESTBANK"

8.5. BKMExpress.Failure

Başlıca hata türleri (Failure.Kind):

  • .session: Oturum hatası
  • .encryption: Şifreleme hatası
  • .server(code: Int): Backend kaynaklı hata; code alanıyla eşleştirme yapılabilir

Son kullanıcılara gösterilecek mesaj için error.message (veya error.localizedDescription) alanı kullanılmalıdır.

catch let error as BKMExpress.Failure {
if case let .server(code) = error.kind, code == 1049 {
// Geçersiz para birimi — kullanıcıya bilgi verin
}
showAlert(error.message)
}

Not: error.message / error.localizedDescription değerleri Türkçe metinler içerir.


9. Hata Yönetimi

9.1. Bilinen API Hata Kodları

Backend belirli iş kuralı ihlallerinde BKMExpress.Failure ile kind == .server(code:) üzerinden hata döner:

KodBaşlıkAçıklama
1049INVALID_CURRENCYGönderilen currencyCode değeri desteklenmiyor. Geçerli bir ISO 4217 kodu kullanın.
36MISSED_MANDATORY_AGREEMENTZorunlu kullanıcı sözleşmesi onaylanmamış.

INVALID_CURRENCY durumu:

Bu hata initialize(context:) çağrısında InitializationContext.currencyCode alanına geçersiz bir değer gönderildiğinde tetiklenir. error.kind == .server(code: 1049) olarak döner; error.message doğrudan kullanıcıya gösterilebilir.

do {
let api = try await BKMExpress.initialize(context: context)
} catch let error as BKMExpress.Failure {
if case let .server(code) = error.kind, code == 1049 {
// Geçersiz para birimi — kullanıcıya bilgi verin veya varsayılana dönün
}
showAlert(error.message)
}

9.2. Kart Numarası Bileşeni Hataları

Bileşenlerden kart numarası elde etmeye çalışırken dönen hatalar BKMExpress.CardNumberFailure tipinde typed throws ile fırlatılır:

  • .empty: Kart numarası alanı boş.
  • .short: Kart numarası gerekenden kısa.
  • .invalidLuhn: Kart numarası Luhn algoritmasına uymuyor.

Uyarı: Bu hatalar özellikle lokalize edilmemiştir. Son kullanıcıya localizedDescription ile gösterim yapılmamalıdır. Her case için kendi belirlediğiniz mesajları, mimarinize uygun hata yönetim mekanizmanızla kullanıcıya göstermeniz gerekmektedir.

do {
let number = try cardNumberField.cardNumber()
// number kullanılabilir
} catch let failure as BKMExpress.CardNumberFailure {
switch failure {
case .empty:
showFieldError("Lütfen kart numarası giriniz.")
case .short:
showFieldError("Kart numarası çok kısa.")
case .invalidLuhn:
showFieldError("Geçersiz kart numarası.")
}
}

9.3. Genel Hata Yönetimi (Uygulama Örneği)

do {
let status = try await api.checkStatus()
handleStatus(status)
} catch let error as BKMExpress.Failure {
showAlert(error.message)
// İsteğe bağlı: error.kind'a göre (session, encryption, server) loglama
}