bex Lite SDK — Entegrasyon Kılavuzu
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:
- SDK'nın başlatılması:
BKMExpress.initialize(context:)ile oturum, iş yeri ve işlem parametrelerinin (transactionType,installmentCountdahil) tanımlanmasıyla birAPInesnesi elde edilmesi - Backend ile ilk senkronizasyon:
initializeçağrısı başarılı olduğunda sözleşmeler ve şifreleme anahtarı otomatik olarak hazırlanır - Cüzdan durumu:
checkStatus()ile kullanıcının mevcut durumunun sorgulanması - Cüzdan / kart akışı: Cüzdan bağlama, OTP doğrulama, kart ekleme/silme ve kart seçimi
- Ödeme ve sonuç:
startPayment(veyastartPaymentWithRegisteredCard), gerekirse 3D / ödeme OTP akışı; ardındanpaymentTokenilecontrolPaymentç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:
Package.swiftdosyanızdakidependenciesparametresine bağımlılığı ekleyin:
.package(url: "https://github.com/BKMExpress/iOS-Lite-SDK.git", branch: "main")
- Bağımlılığı kullanmak istediğiniz target'in
dependencieskı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ı
- gsmNo: Kullanıcının GSM numarası (
BKMExpress.GSMNOstruct'ı olarak; örn."5XXXXXXXXX") - merchantUserID: İş yerinizdeki kullanıcı kimliği
- transactionID: Oturumu/işlemi temsil eden benzersiz tanımlayıcı (
UUID) - successUrl / failUrl: Ödeme sürecinin başarılı ya da başarısız sonuçlandığını iş yeri
backend'inize bildirmek için kullanılan adresler (bkz. Bölüm 7.5).
startPayment/startPaymentWithRegisteredCardçağrılarında da ayrıca belirtilir. - currencyCode: Ödeme para birimi kodu (büyük harf ISO 4217 formatında bir
String; örn."TRY","USD","EUR"). Desteklenmeyen bir değer gönderilirse backendINVALID_CURRENCYhatası döner (bkz. Bölüm 9.1). - installmentCount: Oturum için geçerli taksit sayısı (
BKMExpress.InstallmentCount;0ve negatif değerler kabul edilmez, bkz. Bölüm 8.4) - transactionType: İşlem türü (
BKMExpress.TransactionType:.sale,.preAuth,.recurring). Başlatma anında belirtilir ve SDK bu bilgiyi backend'e iletir. - mode: API sunucu ortamı (
BKMExpress.Mode:.test,.preprod,.production)
Örnek:
let context = BKMExpress.InitializationContext(
authToken: "backend_initial_token",
merchantID: "MERCHANT_ID",
gsmNo: try .init("5XXXXXXXXX"),
merchantUserID: "merchant_user_id",
transactionID: UUID(),
successUrl: "https://example.com/payment/success",
failUrl: "https://example.com/payment/fail",
currencyCode: "TRY", // ISO 4217 para birimi kodu
installmentCount: .init(1)!, // 1 ve üzeri bir tamsayı
transactionType: .sale, // .sale, .preAuth, .recurring
mode: .test // veya .preprod, .production
)
BKMExpress.GSMNOstruct'ı kendi doğrulama kurallarını işletir: 10 haneli, yalnızca rakamlardan oluşan ve 5 ile başlayan bir numara beklenir. Aksi hâldeGSMNO.InitializationErrorfı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
APInesnesini 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ı:
.unregistered: Kullanıcı hiç kayıtlı değildir. Kayıt akışı (register) veya kart ekleme ekranı gösterilmelidir..unlinked: Kullanıcı kayıtlıdır ancak iş yeriyle eşleştirme yapmamıştır. "Cüzdan bağlama" ekranı gösterilmeli velinkAccount()bu ekrandan tetiklenmelidir..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:
BKMExpress.initialize(context:)ile oturum başlatma veAPInesnesini almacheckStatus()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ı (BKMExpress.Agreement.ID)code: Sözleşme kodu (örn."TERMS_OF_USE","KVKK")kind: Sözleşme türü (.agreementveya.info)title: Sözleşmenin metninin gösterildiği ekranın başlığıcontent: Sözleşme içeriğinin kaynağı;BKMExpress.Agreement.WebContenttüründedir ve.url(URL)(harici bir sayfaya link) veya.html(String)(doğrudan HTML içerik) olabilir — UI'ınızda hangi case geldiğine göre birWKWebView'a URL yükleyebilir ya da HTML string'ini render edebilirsiniz.label: Checkbox yanında gösterilecek metinlabelHighlight: Label içinde vurgulanacak metinmandatory: Onayın zorunlu olup olmadığı
Notlar:
kind == .agreementolan kayıtlar için UI'da checkbox gösterilmelidir (metin:label, highlight:labelHighlight).kind == .infoolan kayıtlar için checkbox gösterilmez (örn. KVKK).- SDK, backend'e onay gönderirken tüm
pendingAgreementskayı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.
cardNumberbinding'i yalnızca SDK'nın type-safeBKMExpress.CardNumberwrapper'ı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
bkmExpressDelegateatamasını koddan yapmalısınız.
Bu bileşende:
textveattributedTextö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.CardNumbernesnesidir.
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; bu çağrı, backend'e
sonucu kaç kez sorgulayacağınızı belirten bir maxAttempts parametresi de alı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,
transactionType: .sale,
amount: 100.00,
orderID: "ORDER_123",
installmentCount: .init(1)!,
successUrl: "https://example.com/payment/success",
failUrl: "https://example.com/payment/fail"
)
)
switch response {
case let .control(token):
let result = try await api.controlPayment(token: token, maxAttempts: 3)
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, maxAttempts: 3)
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, maxAttempts: 3)
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,gsmNo,merchantUserID,transactionID,successUrl,failUrl,currencyCode,installmentCount,transactionType,modeparametrelerini içerir. - Başarılı olduğunda sözleşmeler ve şifreleme anahtarı otomatik olarak hazırlanır.
- Hata durumunda
BKMExpress.Failurefı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çincheckStatus()yeniden çağrılmalıdır..verificationRequired(LinkOTP): OTP doğrulaması gerekiyor; dönenLinkOTPnesnesi üzerindenverify(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ıttaTDSInfo(htmlForm, tdsURL vb.) beklenir..otp: OTP doğrulamalı non-3D ödeme..none: Doğrulama mekanizması olmaksızın ödeme.
Önemli:
PaymentSecurityyalnı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),
transactionType (TransactionType), amount (Decimal), orderID, date (varsayılan:
Date()), transactionID (UUID, varsayılan: yeni bir UUID()), installmentCount
(InstallmentCount), successUrl, failUrl. successUrl ve failUrl zorunludur, varsayılan
değerleri yoktur.
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. 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 (PaymentSecurity), transactionType
(TransactionType), amount, currencyCode (String, ISO 4217), 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,
maxAttempts: Int
) async throws(Failure) -> ControlPaymentResponse
- token: Sorgulanacak ödeme işlemini temsil eden
PaymentToken. - maxAttempts: Backend'in nihai sonucu döndürmesi beklenirken SDK'nın içeride yapacağı
tekrar deneme sayısının üst sınırı. İşlemin banka tarafında henüz sonuçlanmamış olabileceği
durumlar için kullanılır; iş yerinizin toleransına göre makul bir değer (örn.
3) belirlemeniz önerilir.
Dönen ControlPaymentResponse şu başlıca alanları içerir: success, message, code,
orderID, successAmount, authCode, hostRefCode, hostRefNum, cardNumber (maskeli),
tarih ve terminal bilgileri (bkz. Bölüm 8.4).
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.2.10. currencySymbol
func currencySymbol() -> String
initialize çağrısında belirtilen currencyCode için backend'in döndürdüğü, kullanıcıya
gösterilebilecek para birimi sembolünü döndürür (örn. "TRY" için "₺"). 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.Failureile yakalanır;error.messageson 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,hostRefCode,bankTransactionID,code,bankTransactionDate,authCode,successAmount,hostRefNum,secureType,procReturnCode,cardBrand,cardType,transactionType,posResponseMessage,message,installment,transactionDate,paymentID,terminalInformation,cardNumber(maskeli),orderID - BKMExpress.Agreement:
id(Agreement.ID),code,kind(.agreement/.info),title,content(Agreement.WebContent:.url(URL)veya.html(String)),label,labelHighlight,mandatory - BKMExpress.CardExpiryDate:
month,year,formatted; pozitif ay/yıl tamsayılarından,"mm/yyyy"formatlı bir string'den veya ay/yıl bilgisi içeren birDateobjesinden oluşturulabilir; geçersiz girdilerdeCardExpiryDate.InitializationErrorfırlatır - BKMExpress.TransactionType: İşlem türünü belirtir;
.sale,.preAuth,.recurringcase'lerine sahiptir veCaseIterable'dır - BKMExpress.InstallmentCount: Pozitif tamsayıdan oluşturulur;
0ve negatif değerler içinnildöner (failable initializer) - BKMExpress.PaymentSecurity:
.otp,.tds,.none;CaseIterable'dır currencyCodeparametreleri (ör.InitializationContext.currencyCode,StartPaymentWithRegisteredCardContext.currencyCode) ayrı bir tip değil, büyük harf ISO 4217 formatında birString'dir (örn."TRY","USD","EUR"). Backend'in bu koda karşılık gelen gösterim sembolü,initializesonrasındaAPI.currencySymbol()ile alınabilir.
Ö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ı.cancelled: İşlem kullanıcı tarafından iptal edildi.encryption: Şifreleme hatası.server(code: Int): Backend kaynaklı hata;codealanıyla eşleştirme yapılabilir
Kolaylık sağlaması için Failure üzerinde şu ek alanlar da bulunur:
isCancelled:kind == .cancelledolup olmadığını döndürenBooldeğer;switchilekind'ı ayrıştırmadan iptal durumunu kontrol etmek için kullanılabilir.code:kind == .server(code:)durumunda ilgiliIntkodu, aksi hâldenildöndüren kısayol.
Son kullanıcılara gösterilecek mesaj için error.message (veya error.localizedDescription,
Failure LocalizedError'a uyar) alanı kullanılmalıdır.
catch let error as BKMExpress.Failure {
if error.code == 1049 {
// Geçersiz para birimi — kullanıcıya bilgi verin
}
if error.isCancelled {
// Kullanıcı işlemi iptal etti; genelde hata gösterilmez
return
}
showAlert(error.message)
}
Not:
error.message/error.localizedDescriptiondeğ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:
| Kod | Başlık | Açıklama |
|---|---|---|
| 1049 | INVALID_CURRENCY | Gönderilen currencyCode değeri desteklenmiyor. Geçerli bir ISO 4217 kodu kullanın. |
| 36 | MISSED_MANDATORY_AGREEMENT | Zorunlu 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) (kısayol: error.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 error.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
localizedDescriptionile 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, cancelled, encryption, server) loglama
}