Pay2S BankHub Hosted Link là form do Pay2S cung cấp để khách hàng nhập thông tin ngân hàng, đồng ý liên kết và xác thực OTP. Backend đối tác tạo phiên, frontend mở URL bằng SDK hoặc chuyển trang, sau đó backend kiểm tra kết quả qua API và webhook. Mô hình này phù hợp khi doanh nghiệp không muốn thu thập mật khẩu hoặc OTP ngân hàng trong giao diện của mình.
Hosted Link vẫn là một phần của API thanh toán ngân hàng Pay2S, nhưng nó không giống gọi trực tiếp /v1/banks. Đối tác làm việc với session, customer_reference, account_id và event; Pay2S chịu trách nhiệm phần form liên kết. Bài viết trên hoadontudong.com.vn giải thích cách tách frontend, backend, callback và webhook để tránh đánh dấu thành công sai.
Môi trường, quyền và ngân hàng hỗ trợ
Production dùng api-partner.pay2s.vn và SDK merchant.pay2s.vn/sdk/pay2s-bankhub-1.1.0.js. UAT có base URL và SDK riêng, dữ liệu giả lập cùng OTP thử nghiệm. UAT dùng để kiểm tra luồng kỹ thuật, không phải bằng chứng tài khoản ngân hàng thật đã liên kết. Trước khi tạo phiên Production, Merchant cần bật cho phép tạo liên kết ngân hàng, lưu địa chỉ HTTPS quay lại và cấu hình Webhook event trạng thái liên kết.
Hosted Link có danh sách ngân hàng và loại tài khoản được cấu hình theo từng ứng dụng. Tài liệu minh họa ACB, MBBank, BIDV, Vietcombank, Vietinbank và Techcombank với khác biệt OpenAPI hoặc RPA. BIDV không có lựa chọn doanh nghiệp trong Hosted Link theo tài liệu hiện tại. Không nên viết chung rằng mọi ngân hàng có cùng OTP hoặc cùng trường thông tin.
Backend tạo link session

Backend gọi POST /v1/bankhub/link-sessions với Bearer Token. customer_reference là trường bắt buộc, cần gắn với khách đang đăng nhập và không nên tin giá trị tùy ý gửi từ trình duyệt. purpose mặc định là LINK_BANK_ACCOUNT. Nếu nhúng SDK, parent_origin phải là HTTPS origin đã đăng ký và không chứa đường dẫn. Với redirect, return_url phải khớp URL đã lưu và state phải là giá trị ngẫu nhiên để chống nhầm phiên.
Phản hồi có session_id, environment, expires_in và hosted_link_url. Hãy dùng nguyên URL nhận được, không tự ghép token hoặc đổi host. Link có hiệu lực theo expires_in, tài liệu minh họa là 900 giây. Không ghi hosted_link_url đầy đủ vào log hoặc analytics vì nó gắn với phiên và khách hàng. Tạo phiên mới chưa có nghĩa ngân hàng đã nhận yêu cầu; cần mở form và theo dõi trạng thái.
Mở form bằng SDK và xử lý callback

SDK và callback Hosted LinkSDK hỗ trợ modal, newTab, newWindow và redirect; popup là tên tương thích cũ. Với newTab hoặc newWindow, gọi open từ thao tác bấm của người dùng để tránh trình duyệt chặn popup. Đối tác có thể dùng onSuccess, onEvent, onExit, onExpired và onError để cập nhật giao diện, nhưng callback chỉ là tín hiệu phía trình duyệt. Backend vẫn phải xác minh kết quả bằng API hoặc webhook.
hub.close chỉ đóng giao diện và hub.destroy dọn instance cùng listeners; đóng cửa sổ không đồng nghĩa hủy yêu cầu phía server. Khi phiên thành công, SDK 1.1.0 có thể tự đóng form theo autoClose và autoCloseDelayMs. Khi lỗi, sai OTP, hết hạn hoặc uncertain, form không nên tự đóng khiến người dùng nghĩ đã liên kết xong. Đặc biệt, onExit không phải nguồn duy nhất để cập nhật trạng thái tài khoản.
Tra cứu trạng thái session và account
Sau khi form kết thúc, backend gọi GET /v1/bankhub/link-sessions/{session_id}. Trạng thái có thể là created, sending, awaiting_otp, verifying, connected, cancelled, failed, expired, revoked hoặc uncertain. Khi connected, vẫn đọc purpose và unlink_mode để biết đó là liên kết, vô hiệu hóa hay bật lại. Nếu account còn null, hệ thống chưa nên cấp quyền thanh toán cho khách.
GET /v1/bankhub/customer-accounts?customer_reference=… trả danh sách ánh xạ tài khoản của khách trong ứng dụng. account.id là ID ánh xạ BankHub, còn user_bank_id là ID ngân hàng Pay2S dùng cho API giao dịch. Hai ID này không nên gộp. Khi hủy hoặc bật lại, tạo phiên với account_id; không thay account_id bằng user_bank_id. Nếu trạng thái uncertain, đối soát trước và không tạo phiên ngân hàng lặp lại.
Hủy, vô hiệu hóa và bật lại
Hosted Link dùng lại endpoint tạo phiên nhưng đổi purpose. UNLINK_BANK_ACCOUNT với unlink_mode bank có thể hủy liên kết ở ngân hàng trong phạm vi được hỗ trợ; unlink_mode deactivate chỉ vô hiệu hóa tại Pay2S và không xác nhận đã hủy ở ngân hàng. REACTIVATE_BANK_ACCOUNT bật lại tài khoản còn tồn tại đã bị vô hiệu hóa tại Pay2S. Kết quả cần được đọc cùng purpose và unlink_mode, không chỉ nhìn status connected.
Nếu tài khoản đã hủy thật ở ngân hàng, thao tác reactivate tại Pay2S không khôi phục liên kết cũ. Người dùng phải liên kết mới. Khi khách quay lại sau khi link hết hạn, backend tra phiên cũ trước rồi mới tạo phiên mới. Cách này tránh tạo nhiều request ngân hàng cho cùng khách và giúp lịch sử liên kết phản ánh đúng.
Webhook sự kiện và bảo mật form
Webhook trạng thái Hosted Link là kênh bổ sung cho API tra session. Payload có event_id, environment, event và metadata phiên hoặc tài khoản. Webhook token riêng nằm ở header Authorization; chữ ký HMAC dùng timestamp header, event ID header và raw request body. Receiver phải kiểm tra token, timestamp, chữ ký, event ID, môi trường, ứng dụng và khách thuộc hệ thống.
Không chạy nghiệp vụ liên kết ba lần khi Pay2S gửi nhiều event mô tả cùng kết quả. Dùng BANK_ACCOUNT_LINKED để cập nhật kết quả tài khoản, dùng nhóm LINK_SESSION để cập nhật tiến trình. Lưu khóa duy nhất environment, application_id và event_id; chỉ trả 2xx sau khi lưu bền vững. Chi tiết chữ ký, retry và event nằm ở bài webhook BankHub trạng thái liên kết.
Góc nhìn triển khai thực tế
Hosted Link nên được xem là một phiên giao diện có giới hạn thời gian, không phải credential có thể lưu dùng lại. Backend tạo session với customer_reference, purpose, parent_origin, return_url và state; frontend mở đúng hosted URL do API trả về; callback chỉ giúp điều hướng trải nghiệm. State cần gắn với user hoặc customer nội bộ và được kiểm tra khi quay lại để chống nhầm phiên. Sau khi callback, backend đọc trạng thái session và tài khoản từ Pay2S rồi mới cập nhật cơ sở dữ liệu. Nếu URL hết hạn, tạo phiên mới thay vì cố sửa chuỗi cũ hoặc đưa khách đến một URL do người dùng tự nhập.
SDK làm giảm công việc dựng giao diện nhưng không loại bỏ trách nhiệm bảo mật. Chỉ tải SDK từ nguồn tài liệu đã xác nhận, kiểm soát parent origin, tránh nhúng form vào domain không được phép và không truyền Secret Key xuống trình duyệt. Các nút liên kết, hủy, vô hiệu hóa và kích hoạt lại nên phản ánh state thực tế. Nếu cửa sổ bị đóng hoặc mạng chập chờn, sản phẩm cần hiển thị đang kiểm tra và có nút làm mới, không chuyển thẳng sang thành công. Trên hoadontudong.com.vn, bài hướng dẫn nên giúp người đọc hiểu rõ ranh giới frontend, backend và webhook.
Bộ kiểm thử Hosted Link nên bao phủ cả luồng bình thường và luồng gián đoạn: session created, awaiting OTP, verifying, connected, failed, expired, cancelled và uncertain. Hãy kiểm tra người dùng bấm refresh, mở cùng URL ở hai tab, quay lại sau khi hết hạn và gửi callback sai state. Với unlink hoặc deactivate, phải xác nhận mục tiêu là mapping tài khoản nào, sau đó kiểm tra event hoặc status từ API. Khi các trạng thái được lưu như một state machine, đội chăm sóc khách hàng có thể biết nên yêu cầu liên kết lại, chờ đồng bộ hay chuyển sang kiểm tra thủ công.
Kiểm soát chất lượng và vận hành
Một thiết kế an toàn tách dữ liệu phiên Hosted Link thành dữ liệu server và dữ liệu frontend. Server giữ customer_reference, state liên kết với phiên đăng nhập, return_url hợp lệ và session_id; frontend chỉ nhận hosted URL cùng thông tin tối thiểu để mở trải nghiệm. Không lưu URL vào local storage lâu dài, không ghi URL đầy đủ vào analytics và không truyền access token vào query string. Khi redirect về return_url, server kiểm tra state, sau đó lấy status từ Pay2S. Nếu khách mở lại trang, frontend gọi backend của chính sản phẩm để xem trạng thái đã đồng bộ, không tự tin vào tham số trên URL.
Các thao tác unlink, deactivate và reactivate cần có xác nhận riêng vì tác động đến việc nhận giao dịch. Trước khi gọi, hiển thị đúng tài khoản và giải thích ảnh hưởng; sau khi gọi, chờ trạng thái và event đồng bộ. Không coi việc đóng modal là hủy liên kết nếu backend chưa ghi nhận purpose tương ứng. Với session uncertain, giao diện nên nói đang xác minh, có nút thử lại và đường dẫn hỗ trợ. Việc đặt tên purpose và lưu audit trail giúp phân biệt khách chủ động tháo tài khoản với hệ thống tự phát hiện tài khoản mất kết nối.
Kiểm thử trên trình duyệt cần bao gồm CSP, iframe hoặc popup bị chặn, mạng di động chập chờn, reload trong lúc OTP, back button và nhiều tab. SDK nên được tải với phiên bản đã kiểm soát; khi nâng phiên bản, chạy lại các callback và event chính. Nếu tài liệu có ví dụ URL hết hạn sau một khoảng thời gian, đội kỹ thuật phải xem đó là tính chất của session chứ không phải lỗi cần kéo dài vô hạn. Trên hoadontudong.com.vn, nội dung hướng dẫn có thể dùng sơ đồ frontend–backend–Pay2S để người triển khai hiểu vì sao callback và webhook không cùng một vai trò.
Quy trình triển khai API thanh toán ngân hàng Pay2S
- Bật quyền tạo liên kết và đăng ký origin HTTPS trong Merchant.
- Backend tạo session với
customer_referencevà state phù hợp. - Frontend mở nguyên
hosted_link_urlbằngSDKđúng môi trường. - Để khách nhập thông tin và OTP trên form Pay2S.
- Backend kiểm tra session qua API sau callback.
- Nhận và xác thực webhook sự kiện trạng thái liên kết.
- Chỉ cấp quyền tiếp theo khi account và purpose hợp lệ.
- Xử lý uncertain bằng đối soát, không tạo phiên lặp mù.
Câu hỏi thường gặp
Hosted Link có gửi mật khẩu ngân hàng về backend không?
Không nên. Khách nhập thông tin trên form Pay2S; đối tác không thu hộ mật khẩu hoặc OTP ở frontend của mình.
onSuccess có đủ để đánh dấu liên kết thành công không?
Không. Callback SDK chỉ phục vụ giao diện. Backend phải kiểm tra API hoặc webhook đã xác thực.
account.id và user_bank_id có giống nhau không?
Không. account.id là ID ánh xạ BankHub; user_bank_id là ID tài khoản ngân hàng Pay2S dùng cho API giao dịch.
Đóng popup có hủy phiên không?
Không. Đóng giao diện chỉ đóng UI; cần thao tác hủy theo nghiệp vụ nếu muốn hủy phía server.
Có thể dùng UAT để xác nhận ngân hàng thật không?
Không. UAT dùng dữ liệu mô phỏng và OTP thử nghiệm, chỉ phục vụ kiểm thử kỹ thuật.