WEB SDK Vanilla - Entegrasyon Klavuzu
Bu doküman, BEX Ödeme WEB SDK’nın Vanilla HTML-JS-CSS 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:
- Merchant HTML sayfasına sdk javascripti eklenir.:
<script src="_URL_/sdk.umd.js"></script> - Merchant backendi üzerinden token alınır:
${API_BASE_URL}/merchant/generateTokenendpointi ile - İletilen token ile SDK gerekli parametler verilerek başlatılır
- checkStatus fonksiyonu ile kullanıcının cüzdandaki durumu kontrol edilir.
- Kayıtlı Kartlar / Linkleme / Kayıt olma: checkStatus fonksiyonunu sonucuna göre Kayıtlı Kartların Gelmesi, Cüzdan bağlama veya Kart Ekleyerek Kayıt olma adımları
- Ödeme akışları
Tüm servis çağrımları SDK üzerinden yürütülür ve UI tarafı ve state yönetimi tamamen işyeri kontrolündedir.
2. Başlangıç
Merchant HTML sayfasına sdk javascripti eklenir. Bu js dosyası bir URL üzerinden dağıtılacaktır, işyeri dilerse ilgili javascripti kendi sunucularına alarak kullanabilir.
Merchant backendi üzerinden API_BASE_URL/merchant/generateToken endpointine erişerek token almalıdır. Bu token ile SDKClient'ı başlatmalıdır.
generateToken servisi dışarıya açık bir servis değildir, öncesinde backend sunucularının IP tanımı yapılması gerekmektedir.
SDKClient initialize edilirken merchant tarafından şu bilgilerin sağlanması gerekmektedir:
- API_BASE_URL/merchant/generateToken servisinden elde ettiği token
- Bex tarafında kayıtlı merchantId
- İlgili kullanıcı için ürettiği unique merchantUserId
- Kullanıcının telefon numarası gsmNo
- Entegrasyon ortamı için parametre (test - production)
const SDKClient = SDK.SDKClient;
window.MerchantDemo.state.client = new SDKClient({
environment: 'test', //'https://trcuzdan-dev.bkmtest.com.tr', // Proxy server URL
initToken: window.MerchantDemo.state.token,
merchantId: window.MerchantDemo.state.merch_params.merchantId,
merchantUserId: window.MerchantDemo.state.merch_params.merchantUserId,
gsmNo: phoneNumber
});
Bu bilgiler in-memory olarak tutularak sayfa yenilenene kadar diğer çağrımlarda kullanılacaktır. Sonrasında init fonksiyonu çağırılmalıdır.
const initResponse = await client.init();
initResponse.data.token
initResponse.data.encKey
initResponse.data.pendingAgreements
Bu fonksiyon dönüşünde token, encKey değerlerine erişilebilir. Ancak SDK içerisinde bu değerler sonraki servis çağrımlarda kullanılmak üzere saklanır, merchant tarafından tutulmasına gerek yoktur.
3. Cüzdan Kontrolü
Bir sonraki adımda checkStatus fonksiyonu çağırılır.
const checkStatusResponse = await client.checkStatus();
3.1. User BEX'e kayıtlı değilse:
resultCode: 1001, errorTitle: "USER_NOT_FOUND", screen: PartialRegisterScreen döner.
{
"data": {
"token": "eyJhbGciOiJIUzI1NiJ9.eyJDb21pbmdUeXBlI...",
"resultCode": 1001,
"resultMessage": "Kullanıcı Bulunamadı.",
"errorTitle": "USER_NOT_FOUND",
"screen": "PartialRegisterScreen"
}
}
Merchant bu durumda kart ekleyerek kaydolmak için aksiyon alabilir. SDK tarafında bulunan register fonksiyonunu kullanır:
Eğer işyeri PCI-DSS kapsamına dahil değilse Secure Field yapısını kullanması gerekmektedir. Secure Field içeren formu aşağıdaki gibi tasarımınıza ekleyebilirsiniz:
<div id = "card-field-register"></div>
Eklenen div alanı render olurken mount işlemi yapılabilmesi için aşağıdaki fonksiyonlar çağırılır.
const field_register = window.MerchantDemo.state.client.createCardField()
field_register.mount("#card-field-register");
Kayıt işlemi bitirilirken, sözleşmeler alanı da eklenerek register fonksiyonu çağırılır, checkbox işaretlenmeden register fonksiyonu çalışmaz:
<div id = "agreement-field"></div>
const field_agreement = window.MerchantDemo.state.client.createAgreementsField()
field_agreement.mount("#agreement-field");
Eğer #agreement-field alanında farklı bir tema isteniyorsa mount fonksiyonu örnek olarak aşağıdaki gibi çağrılabilir:
sdk.mount("#agreement-field", {
"brand-color": "#5b21b6",
"text-color": "#1f2937",
"font-family": "'Poppins', sans-serif",
"font-url": "https://fonts.googleapis.com/css2?family=Poppins:wght@400;500&display=swap",
"border-radius": "12px"
});
registerSecure fonksiyonundan screen alanı 'EnterOtpScreen' döndüğünde OTP ekranına yönlendirilerek verifyOTP fonksiyonu çağırılmalıdır, aksi halde kart eklenmez.
await client.verifyOTP($otpValue);
3.2. User BEX'e kayıtlı ama linkli değilse:
resultCode: 1002 errorTitle: "USER_NOT_LINKED" screen: LinkScreen döner.
{
"data":
{
"token": "eyJhbGciOiJIUzI1NiJ9.eyJDb21pbmdUeXBlIjoiTWVyY2hhbnQiLCJpZGVudGlmaWVyIjoiNTU1NTY1NzU1NSIsIlVJRCI6IjExMTExMTExLTExMTEtMTExMS0xMTExLTExMTExMTExMTExMiIsInByb2Nlc3NJZCI6IjI4MzhjOGViLWU0ODktNDYxZS04NGQwLTExNDllZDNkYTdkMSIsImNsaWVudEluZm8iOnsiYXBwVmVyc2lvbiI6IjEuMC4wIiwib3NWZXJzaW9uIjoiTkEiLCJvc1R5cGUiOiJpT1MiLCJpcEFkZHJlc3MiOiIxNzIuMzAuMC4xMzUiLCJkZXZpY2VNb2RlbCI6IlVua25vd24gQnJvd3NlciJ9LCJSdWxlIjoiVW5saW5rZWRNZXJjaGFudEFjY291bnQiLCJtZXJjaGFudFVzZXJJZCI6IllCWF81NTU1NjU3NTU1IiwiZXhwIjoxNzc4MDEzODEwLCJpYXQiOjE3NzIwMTM4NzAsInVzZXJJZCI6IjAxOWMxZTUxLTU2ODAtN2VkMS1hNmNmLTllYmM5MGJhOTE3YSJ9.1Yht_H_77j16hjLK7f2HofdA5nhAVnr-6tFknRwGqpo",
"merchantUserId": null,
"resultCode": 1002,
"resultMessage": "User Merchant ile linkli değil",
"errorTitle": "USER_NOT_LINKED",
"screen": "LinkScreen"
}
}
Bu durumda linkAccount fonksiyonu çağırılır. Bu fonksiyon sonucunda OTP istenebilir. ("screen": "EnterOtpScreen") verifyOTP fonksiyonu ile otp doğrulama gerçekleşir ve linkleme gerçekleşir. Eğer otp girmek için geçerli süre dolduysa resendOTP fonksiyonu çağırılır.
const linkWalletResponse = await client.linkAccount();
const verifyOTPResponse = await client.verifyOTP($otpValue);
const verifyOTPResponse = await client.resendOTP($otpValue); //Yeniden OTP çağırmak için
3.3 User Linkli ise:
Kart bilgileri döner data.cards ile kart bilgilerine ulaşılabilir.
4. Kart İşlemleri
4.1. Kart Ekleme
Merchant iframein yerleşeceği bir alan oluşturmalıdır ve sdk client'ından field oluşturup mount etmelidir, bu sayede kart numarası ve son kullanma tarihi için inputlar bu div içerisine yerleşir:
<div id = "card-field"></div>
İlgili HTML render edilirken aşağıdaki fonksiyonlar çağırılmalıdır:
const field = client.createCardField()
field.mount("#card-field")
Sonrasında merchant bir alias alanı ile birlikte kart ekleme işlemini tamamlarken aşağıdaki fonksiyonu çağırmalıdır. Kart ekleme işlemi öncesinde sözleşmeler eklenmiş olmalıdır, checkbox seçili olmadığı durumda kart ekleme çalışmaz.
<div id = "agreement-field"></div>
const field_agreement = window.MerchantDemo.state.client.createAgreementsField()
field_agreement.mount("#agreement-field");
Eğer #agreement-field alanında farklı bir tema isteniyorsa mount fonksiyonu örnek olarak aşağıdaki gibi çağrılabilir:
sdk.mount("#agreement-field", {
"brand-color": "#5b21b6",
"text-color": "#1f2937",
"font-family": "'Poppins', sans-serif",
"font-url": "https://fonts.googleapis.com/css2?family=Poppins:wght@400;500&display=swap",
"border-radius": "12px"
});
storeCard fonksiyonundan screen alanı 'EnterOtpScreen' döndüğünde OTP ekranına yönlendirilerek verifyOTP fonksiyonu çağırılmalıdır, aksi halde kart eklenmez.
await client.verifyOTP($otpValue);
4.2. Kart Silme
Aşağıdaki fonksiyon kullanılarak cards listesinde dönen ilgili kartın id'si ile kart silme fonksiyonu çağırılır.
Kart silme ile ilgili karar mekanizmaları Akış Diyagramları bölümünde DeleteCard (Kart Silme) kısmında anlatılmıştır.
await client.cardDelete(cardId)
5. Ödeme Akışları
5.1 startPayment - Kayıtlı Kart İle Ödeme Başlatma
startPayment fonksiyonu ile ödeme başlatılır. Beklenen alanlar aşağıdaki gibidir.
startPayment(
cardId:string, //Ödeme yapılacak kartın ID'si
amount: Number, //Ödeme tutarı örnek format: 20.75
transactionDate: string, //ISO 8601 formatı
currency:string , //TRY için 949 kodu
installmentCount: Number, //Tek çekim işlemler için 1 olmalıdır)
orderId: string, //Üreteceğiniz herhangi bir tekil değer (OPTIONAL)
transactionId: string, //UUID formatında tekil değer
paymentSecurity: string // "NONE", "OTP", "3D" değerlerinden biri olmalıdır.
)
const d = new Date();
const transactionDate = d.toISOString()
.replace('Z', '+03:00')
.replace(/\.(\d{3})/, (_, ms) => '.' + (ms + '00').slice(0, 5));
const transactionId = crypto.randomUUID();
const orderId = crypto.randomUUID();
const resp = await client.startPayment(
this._cards[idx].cardId, new Number("50.00"), transactionDate, "949", 1, orderId, transactionId, "3D"
);
5.2 startPaymentWithRegisteredCard - Kart Kaydederek Ödeme Başlatma:
Kart numarası ile ödeme başlatıp kartı kaydeden bir akıştır.
<div id = "card-field-register-and-pay"></div>
Eklenen div alanı render olurken mount işlemi yapılabilmesi için aşağıdaki fonksiyonlar çağırılır.
const field_register_and_pay = window.MerchantDemo.state.client.createCardField()
field_register_and_pay.mount("#card-field-register-and-pay");
İşlemi tamamlamak için startPaymentWithRegisteredCard fonksiyonu çağırılır. Input parametleri cardId hariç yukarıdaki fonksiyon ile aynıdır.
startPaymentWithRegisteredCard(
amount: Number,
transactionDate: string,
currency:string ,
installmentCount: Number,
orderId: string,
transactionId: string,
paymentSecurity: string
)