Developer
Thử API trong Playground ↗Trải nghiệm BankHub Hosted Link ↗

Hosted Link & SDK

✧ Mở bằng AI

Sao chép tài liệu, mở AI rồi dán vào cuộc trò chuyện.

ChatGPTClaudePerplexityGrok
≡ Xem Markdown

Hosted Link là trang do Pay2S cung cấp để khách hàng nhập thông tin, đồng ý liên kết và xác thực OTP. Backend đối tác tạo phiên; frontend mở URL trả về bằng SDK hoặc chuyển trang. Danh sách lựa chọn được cấu hình theo từng ứng dụng Partner.

Môi trường và chuẩn bị

Môi trường API base URL SDK 1.1.0
Production https://api-partner.pay2s.vn https://merchant.pay2s.vn/sdk/pay2s-bankhub-1.1.0.js
UAT https://api-partner-uat.pay2s.vn https://merchants-uat.pay2s.vn/sdk/pay2s-bankhub-1.1.0.js

UAT dùng thông tin xác thực riêng, kết quả giả lập và OTP thử nghiệm 123456. Không dùng kết quả UAT để xác nhận liên kết ngân hàng thật. Kiểm tra environment trong kết quả API và webhook.

Trong Merchant → BankHub → Thiết lập, bật Cho phép tạo liên kết ngân hàng, lưu các địa chỉ HTTPS quay lại và cấu hình Webhook event — trạng thái liên kết. UAT quản lý địa chỉ tại URL & Webhook của ứng dụng UAT. Hạn mức production theo gói đang còn hiệu lực; UAT giới hạn 5 tài khoản.

Lấy Bearer Token theo Authentication. Access Key, Secret Key và API token chỉ lưu tại backend.

Ngân hàng được hỗ trợ

Ngân hàng Loại tài khoản Kết nối Thông tin bổ sung
ACB Cá nhân OpenAPI Tên chủ tài khoản, số điện thoại
ACB Doanh nghiệp OpenAPI Tên chủ tài khoản, số điện thoại, username ACB Onebiz
MBBank Cá nhân, doanh nghiệp OpenAPI Tên chủ tài khoản, số điện thoại, email, CCCD/mã số thuế
BIDV Cá nhân, hộ kinh doanh OpenAPI Tên chủ tài khoản, số điện thoại, email, CCCD/mã số thuế, hậu tố tài khoản ảo
Vietcombank Cá nhân, doanh nghiệp RPA Tên đăng nhập, mật khẩu
Vietinbank Cá nhân, doanh nghiệp RPA Tên đăng nhập, mật khẩu
Techcombank Doanh nghiệp RPA Tên đăng nhập, mật khẩu

BIDV không có lựa chọn doanh nghiệp trong Hosted Link. Tài khoản ảo được xác nhận theo kết quả ngân hàng; giữ merchantId và vaNumber để định tuyến giao dịch. Luồng RPA có thể hoàn tất ngay sau đăng nhập hoặc yêu cầu OTP (Vietcombank cá nhân); không giả định mọi ngân hàng đều có cùng bước OTP. Tên chủ tài khoản Techcombank doanh nghiệp có thể chưa có ngay khi kết nối thành công.

Chọn ngân hàng hiển thị

Partner vào BankHub → Thiết lập → Ngân hàng hiển thị trên Hosted Link, bật/tắt từng ngân hàng và loại tài khoản rồi lưu. UAT có lựa chọn riêng tại URL & Webhook. Mặc định khi nâng cấp chỉ bật ACB cá nhân để giữ cấu hình cũ; Partner tự bật thêm loại cần dùng.

Hosted Link chỉ cho bắt đầu với lựa chọn đã bật, backend kiểm tra lại trước khi gọi ngân hàng. Tắt một lựa chọn không ngắt tài khoản đã liên kết và không chặn hoàn tất phiên đã gửi yêu cầu/đang chờ OTP. Nếu tắt tất cả, không thể tạo phiên liên kết mới. Thiết lập này áp dụng riêng cho Hosted Link, không tắt ngân hàng trong các API thêm ngân hàng khác.

Khách nhập thông tin ngân hàng trực tiếp trên trang Pay2S. Không thu hộ mật khẩu/OTP ở frontend của đối tác và không gửi những trường này qua API tạo phiên. Các trường bổ sung được form Hosted Link hiển thị theo lựa chọn. Thông tin đăng nhập không nằm trong callback SDK hoặc webhook đối tác.

1. Backend tạo phiên

POST /v1/bankhub/link-sessions
Authorization: Bearer API_TOKEN
Content-Type: application/json
{
  "customer_reference": "DEV_d33eb1382b55f87313b6840bff80f880_179165997315205323a",
  "purpose": "LINK_BANK_ACCOUNT",
  "parent_origin": "https://developer.example.com"
}
Trường Quy định
customer_reference Bắt buộc, 1–128 ký tự: chữ, số, _ . : @ -. Backend lấy từ khách đã đăng nhập, không tin mã khách tùy ý gửi từ trình duyệt.
purpose Mặc định LINK_BANK_ACCOUNT; các tác vụ khác xem bên dưới.
parent_origin Dùng khi nhúng SDK; origin HTTPS phải khớp origin của một địa chỉ quay lại đã lưu. Không chứa đường dẫn.
return_url Không bắt buộc với modal; nếu truyền phải khớp đầy đủ một URL đã lưu và có state.
state Giá trị ngẫu nhiên gắn với phiên đăng nhập; chữ, số, _, -, tối đa 128 ký tự. Đối tác kiểm tra khi quay lại.
application_id Chọn ứng dụng nếu thông tin xác thực của chủ tài khoản truy cập được nhiều ứng dụng.

Nếu đối tác dùng nhiều website, đăng ký các URL HTTPS tương ứng và truyền đúng parent_origin của website mở SDK cho từng phiên. URL quay lại điều hướng trình duyệt; không phải URL nhận webhook.

Ví dụ phản hồi (URL và mã phiên chỉ minh họa):

{
  "success": true,
  "data": {
    "session_id": "2f78eb564c44b9f3edd3a10d7807426c",
    "environment": "uat",
    "expires_in": 900,
    "hosted_link_url": "https://merchants-uat.pay2s.vn/bankhub/connect#token=YOUR_KEY"
  }
}

Dùng nguyên hosted_link_url nhận được, không tự ghép token hoặc đổi host. Link có hiệu lực 15 phút và chỉ trả về cho đúng khách hàng; không ghi vào log hoặc analytics. Tạo phiên chưa thực hiện thao tác ngân hàng. Giới hạn tạo phiên hiện tại: 10 phiên/phút/ứng dụng.

2. Frontend mở form

Ví dụ dưới đây giả định backend của bạn trả nguyên cấu trúc success/data từ API tạo phiên. Endpoint /my-api/bankhub/link thuộc hệ thống đối tác, cần kiểm tra đăng nhập và CSRF.

<script src="https://merchant.pay2s.vn/sdk/pay2s-bankhub-1.1.0.js" charset="utf-8"></script>
<button id="link-bank">Liên kết ngân hàng</button>
<script>
let hub;
document.querySelector('#link-bank').onclick = async () => {
  const response = await fetch('/my-api/bankhub/link', { method: 'POST' });
  const result = await response.json();
  if (!response.ok || !result.success) throw new Error('Không tạo được phiên');
  if (hub) hub.destroy();
  hub = Pay2SBankHub.create({
    mode: 'modal',
    onSuccess: async () => {
      // Hàm do đối tác triển khai: gọi backend để tra kết quả Pay2S.
      await refreshLinkedAccountsFromYourBackend();
    },
    onEvent: event => { /* Cập nhật tiến trình giao diện */ },
    onExit: event => { /* Chỉ đóng giao diện, không kết luận hủy phiên */ },
    onExpired: event => { /* Cho khách tạo phiên mới */ },
    onError: event => { /* Hiển thị lỗi và cho kiểm tra trạng thái */ }
  });
  hub.initLink(result.data.hosted_link_url, result.data.session_id);
  hub.open();
};
</script>

Các chế độ: modal, newTab, newWindow, redirect; popup là tên tương thích cũ. Với newTab/newWindow, chuẩn bị link trước rồi gọi open() từ thao tác bấm để tránh bị chặn popup. redirect rời trang nên không duy trì callback trên trang cũ; dùng return_url, kiểm tra state và tra kết quả tại backend.

hub.close() đóng giao diện; hub.destroy() dọn instance/listeners. Đóng cửa sổ không hủy yêu cầu ngân hàng. Nút Hủy yêu cầu trong Hosted Link chỉ hủy khi trạng thái cho phép.

Các callback thành công của SDK: FINISHED_BANK_ACCOUNT_LINK, FINISHED_BANK_ACCOUNT_UNLINK, FINISHED_BANK_ACCOUNT_REACTIVATE. Callback chỉ phục vụ giao diện; backend xác minh kết quả bằng API hoặc webhook đã kiểm tra chữ ký.

3. Backend lấy kết quả

GET /v1/bankhub/link-sessions/{session_id}
Authorization: Bearer API_TOKEN

Phản hồi success/data có session_id, customer_reference, purpose, unlink_mode, status, environment, account, account_status, sequence. account có thể là null khi chưa có kết quả tài khoản. Khi cần chọn ứng dụng, thêm query application_id.

GET /v1/bankhub/customer-accounts?customer_reference=CUSTOMER-123
Authorization: Bearer API_TOKEN

API danh sách trả data là mảng các ánh xạ tài khoản của khách trong ứng dụng. Đây có thể bao gồm lịch sử liên kết; không suy ra mọi bản ghi đều đang hoạt động. account.id là ID ánh xạ BankHub; user_bank_id là ID ngân hàng Pay2S dùng cho các API giao dịch.

Trạng thái phiên Ý nghĩa
created Chờ khách mở/nhập thông tin
sending Đang gửi yêu cầu ngân hàng
awaiting_otp Cần khách nhập OTP trên Hosted Link
verifying Đang xác minh
connected Luồng đã hoàn tất; đọc purpose để biết tác vụ
cancelled, failed, expired, revoked Phiên bị hủy, lỗi, hết hạn hoặc thu hồi
uncertain Chưa xác định kết quả ngân hàng; cần đối soát, không tự tạo yêu cầu ngân hàng lặp lại

4. Hủy, vô hiệu hóa và bật lại

Cùng endpoint tạo phiên, thêm account_id lấy từ account.id hoặc API danh sách khách hàng. Không thay bằng user_bank_id. Backend kiểm tra khách đang đăng nhập sở hữu tài khoản cần thao tác.

purpose unlink_mode Hành vi
UNLINK_BANK_ACCOUNT bank Hủy liên kết ACB OpenAPI qua OTP ngân hàng; chưa mở hủy phía ngân hàng cho các loại mới
UNLINK_BANK_ACCOUNT deactivate Vô hiệu hóa tại Pay2S, không xác nhận đã hủy phía ngân hàng
REACTIVATE_BANK_ACCOUNT Không cần truyền Bật lại tài khoản còn tồn tại đã vô hiệu hóa tại Pay2S
{
  "customer_reference": "CUSTOMER-123",
  "purpose": "UNLINK_BANK_ACCOUNT",
  "account_id": 12,
  "unlink_mode": "bank",
  "parent_origin": "https://app.example.com"
}

Tài khoản đã hủy phía ngân hàng cần liên kết mới; bật lại tại Pay2S không khôi phục liên kết ngân hàng đã hủy. Đọc purpose và unlink_mode khi xử lý kết quả, không chỉ đọc status=connected.

5. Nhận thông báo và xử lý lỗi

Xem Webhook sự kiện để nhận tiến trình, kết quả tài khoản, xác thực HMAC và retry. Webhook biến động số dư dùng cấu hình webhook giao dịch riêng.

Nếu không tạo được phiên, kiểm tra quyền ứng dụng, bật liên kết, hạn gói, URL đã đăng ký và đúng môi trường. Khi tài khoản đang có phiên xử lý, tra phiên hiện tại trước khi tạo lại. Nếu khách quay lại sau khi link hết hạn, backend tạo phiên mới sau khi kiểm tra kết quả phiên cũ.

Tự đóng form sau khi hoàn tất

SDK 1.1.0 mặc định tự đóng modal/popup/tab do SDK mở sau khi nhận sự kiện hoàn tất với trạng thái connected. Form hiển thị đếm ngược 3 giây và nút Đóng ngay.

const handle = Pay2SBankHub.open({
  url: response.data.hosted_link_url,
  sessionId: response.data.session_id,
  mode: 'modal',
  autoClose: true,
  autoCloseDelayMs: 3000,
  onSuccess: event => { /* Backend kiểm tra kết quả qua API/webhook. */ },
  onExit: event => { /* reason: completed, cancelled hoặc closed */ }
});

Thay đổi lựa chọn và lỗi liên kết

SDK phát BANK_CHANGED qua onEvent khi người dùng đổi ngân hàng hoặc loại tài khoản. Metadata gồm bank_code, bank_profile, account_type, previous_bank_code, previous_bank_profile và status: created. Đây là sự kiện giao diện trong trình duyệt, không phải webhook và chưa xác nhận ngân hàng đã liên kết. Chọn lại cùng profile không phát thêm sự kiện.

Khi phiên thất bại, Hosted Session API, API kết quả phiên và webhook LINK_SESSION_FAILED có thông tin lỗi an toàn:

{"error":{"code":"BANK_LOGIN_REJECTED","message":"Ngân hàng không chấp nhận thông tin đăng nhập. Kiểm tra tên đăng nhập, mật khẩu và trạng thái tài khoản trước khi tạo phiên mới."}}

Trong webhook và callback SDK, đọc metadata.error; trong kết quả API đọc data.error. SDK onError nhận sự kiện FAILED/UNCERTAIN; form giữ mở để người dùng đọc thông báo.

Mã lỗi: BANK_REJECTED (ngân hàng từ chối), BANK_LOGIN_REJECTED (thông tin đăng nhập bị từ chối), OTP_ATTEMPTS_EXCEEDED (hết lượt OTP), BANK_RESULT_UNKNOWN (chưa rõ kết quả). LINK_FAILED dành cho phiên cũ không lưu chi tiết. Không suy luận mọi lỗi đều do mật khẩu và không gửi phản hồi thô chứa thông tin nhạy cảm của ngân hàng. Lỗi HTTP/validation vẫn trả theo error envelope của API.

Request và response đối chiếu ngày 11/10/2026

Các mẫu dưới đây giữ cấu trúc trường và kiểu dữ liệu. Khóa, chữ ký, URL phiên đã được thay bằng placeholder; danh sách chỉ giữ tối đa hai phần tử và dữ liệu ảnh/PDF/XML dài được rút gọn. Không sao chép placeholder để gọi API thật.

Đã gọi API demo/UAT.

POST /v1/bankhub/link-sessions

Body:

{
  "customer_reference": "DEV_d33eb1382b55f87313b6840bff80f880_179165997315205323a",
  "purpose": "LINK_BANK_ACCOUNT",
  "parent_origin": "https://developer.example.com"
}

HTTP 201. Response:

{
  "success": true,
  "data": {
    "session_id": "2f78eb564c44b9f3edd3a10d7807426c",
    "environment": "uat",
    "expires_in": 900,
    "hosted_link_url": "https://merchants-uat.pay2s.vn/bankhub/connect#token=<REDACTED>"
  }
}

Tra cứu phiên liên kết

Đã gọi API demo/UAT.

GET /v1/bankhub/link-sessions/{session_id}

Tham số path/query (không gửi JSON body):

{
  "session_id": "LAST_SESSION"
}

HTTP 200. Response:

{
  "success": true,
  "data": {
    "session_id": "2f78eb564c44b9f3edd3a10d7807426c",
    "purpose": "LINK_BANK_ACCOUNT",
    "unlink_mode": "bank",
    "customer_reference": "DEV_d33eb1382b55f87313b6840bff80f880_179165997315205323a",
    "status": "created",
    "error": null,
    "environment": "uat",
    "account": null,
    "account_status": null,
    "sequence": 344
  }
}

Tài khoản của khách hàng

Đã gọi API demo/UAT.

GET /v1/bankhub/customer-accounts

Tham số path/query (không gửi JSON body):

{
  "customer_reference": "CUSTOMER-DEMO"
}

HTTP 200. Response:

{
  "success": true,
  "data": []
}
Tìm trong 57 trang tài liệu · Esc để đóng