Skip to content

Bắt đầu ​

Tích hợp thanh toán thẻ và xác thực 3DS vào ứng dụng của bạn chỉ trong vài phút. Mới làm quen với Bahn? Hãy đọc Tổng quan Web SDK trước để hiểu các thành phần kết hợp với nhau thế nào và nên chọn luồng nào.

Điều kiện tiên quyết ​

Bạn cần một publishable key (pk) từ Cake Digital Bank. Liên hệ account manager của bạn để lấy key này. Xem Onboarding để biết Bahn cấp cho bạn những gì.

Thông tinMô tả
Publishable Key (pk)Được gửi dưới dạng header X-Bn-Publishable-Key trên mọi lệnh gọi API. Nhận diện tài khoản merchant của bạn.
Môi trường"sandbox" để kiểm thử, "production" cho thanh toán thật.

Cài đặt ​

Tải SDK bằng thẻ script từ CDN của Cake. Không cần bundler, không cần import — Bahn sẽ có sẵn dưới dạng biến toàn cục ngay khi script được tải.

Mỗi bản phát hành được publish tại một đường dẫn riêng gắn theo phiên bản (/bn-sdk/v<version>/index.js), vì vậy file tại một URL nhất định sẽ không bao giờ thay đổi — hãy pin một phiên bản và thêm thuộc tính integrity để trình duyệt xác minh bundle không bị can thiệp. Chỉ có một URL script duy nhất cho cả sandbox và production — tùy chọn environment bạn truyền vào new Bahn() mới là thứ kiểm soát domain API/iframe nào được sử dụng, không phải script bạn tải:

html
<script
  src="https://bn.cake.vn/bn-sdk/v2.4.0/index.js"
  integrity="sha384-jBbonUZLgKU82F+X/ITqcmeInXYYwZYdmCDoPFX8wkWL9dCkeUHyi0Fs1EUnkeDS"
  crossorigin="anonymous"
></script>

<script>
  const bahn = new Bahn({ pk: "pk_test_...", environment: "sandbox" });
</script>

Hash tương ứng cho mỗi bản phát hành được publish kèm theo bundle tại .../v<version>/index.js.sha384 — ví dụ https://bn.cake.vn/bn-sdk/v2.4.0/index.js.sha384.

Xem Môi trường để biết đầy đủ ánh xạ domain và chi tiết phiên bản.

Khởi tạo SDK ​

Class Bahn là một singleton. Gọi new Bahn() một lần — các lần gọi sau sẽ trả về cùng một instance.

typescript
// Bahn là biến toàn cục sau khi script SDK được tải — không cần import
const bahn = new Bahn({
  pk: "pk_live_...",                 // Publishable key của bạn
  environment: "sandbox",             // hoặc "production"
  appId: "your-app-id",               // tùy chọn — cho định tuyến 3DS tenant
  teamId: "your-team-id",             // tùy chọn — cho định tuyến 3DS tenant
});

Form thanh toán hoàn chỉnh với ô nhập thẻ và nút thanh toán

Bắt đầu nhanh: thanh toán thẻ ​

Một luồng thanh toán thẻ tối giản có ba bước:

1. Gắn (mount) ô nhập thẻ ​

typescript
const card = bahn.mountCard("#card-container", {
  fields: {
    number: { label: "Card Number" },
    expiry: { label: "Expiry" },
    cvc: { label: "CVC" },
  },
});

card.on("ready", () => console.log("Card input ready"));
card.on("complete", () => console.log("All fields valid"));

2. Tạo payment intent ở backend của bạn ​

confirmPayment xác nhận một payment intent đã tồn tại. Backend của bạn phải tạo một payment intent trước và trả về client_secret:

typescript
// Backend của bạn: POST /api/create-payment-intent
// → trả về { client_secret: "pi_xxx_secret_yyy" }
const { client_secret } = await fetch("/api/create-payment-intent", {
  method: "POST",
  body: JSON.stringify({ amount: 100000, currency: "vnd" }),
}).then(r => r.json());

3. Xác nhận thanh toán ​

typescript
try {
  const { payment_intent, three_ds_payload } = await bahn.confirmPayment({
    client_secret,
  });

  // Nếu cần 3DS, three_ds_payload sẽ có mặt
  if (three_ds_payload) {
    bahn.mount3DS(three_ds_payload.id, {
      onSuccess: () => console.log("3DS passed"),
      onFailure: (err) => console.error("3DS failed", err),
    });
  }
} catch (err) {
  console.error("Payment failed:", err);
}

4. Xử lý 3DS (nếu được kích hoạt) ​

Sau khi thử thách 3DS thành công, poll trạng thái thanh toán cuối cùng bằng pollPaymentIntentStatus(client_secret, callbacks). Xem Xác nhận thanh toán để biết chi tiết.

Cách hoạt động ​

sequenceDiagram
    participant App as Your App
    participant SDK as Bahn SDK
    participant Iframe as Card Iframe
    participant API as Cake API

    App->>SDK: new Bahn({ pk, environment })
    SDK-->>App: Singleton instance

    App->>SDK: mountCard
    SDK->>Iframe: Load 3 iframes (number, expiry, CVC)
    Iframe-->>SDK: Validity state (boolean only)
    SDK-->>App: CardComponent

    App->>SDK: confirmPayment(payload)
    SDK->>Iframe: Delegate API call (card data merged inside)
    Iframe->>API: POST /bn/sdk/payment_intents/confirm
    API-->>Iframe: PaymentIntent + optional 3DS payload
    Iframe-->>SDK: Result (card values never exposed)
    SDK-->>App: { payment_intent, three_ds_payload }

    App->>SDK: mount3DS(sessionId, callbacks)
    SDK->>SDK: Render 3DS challenge in iframe
    SDK-->>App: callbacks.onSuccess() / onFailure()

Bước tiếp theo ​

Developers