Bắt đầu nhanh

Hướng dẫn tích hợp Bank Hub vào ứng dụng của bạn trong vài bước đơn giản - từ tạo token, tạo link token đến nhúng iframe webview và nhận thông báo biến động số dư


  • Lấy access_token từ API /v1/token
  • Sử dụng access_token để tạo link token
  • Nhúng hosted_link_url vào iframe trên website
Trước khi bắt đầu

Đảm bảo bạn đã có:

  • client_idclient_secret do SePay cấp
  • company_xid (UUID của công ty đã được tạo trong hệ thống Bank Hub) - API tạo công ty
  • Backend server để gọi API (không gọi từ client-side vì lý do bảo mật)

Bước 1: Lấy Access Token

  • Đầu tiên, bạn cần lấy access_token để xác thực cho các API tiếp theo. API này sử dụng Basic Authentication với client_idclient_secret.
Bảo mật

KHÔNG gọi API này từ client-side (browser, mobile app). API yêu cầu client_secret - thông tin này phải được bảo mật tuyệt đối trên server. Chỉ gọi API này từ backend server của bạn.

  • API Endpoint
POST
https://bankhub-api-sandbox.sepay.vn/v1/token
Authorization: Basic {base64(client_id:client_secret)}
Content-Type: application/x-www-form-urlencoded
  • Code mẫu
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?php
// File: app/Services/BankHubService.php
 
namespace App\Services;
 
use Illuminate\Support\Facades\Http;
 
class BankHubService
{
private $clientId;
private $clientSecret;
private $baseUrl;
 
public function __construct()
{
$this->clientId = config('bankhub.client_id');
$this->clientSecret = config('bankhub.client_secret');
$this->baseUrl = config('bankhub.base_url', 'https://bankhub-api-sandbox.sepay.vn');
}
 
/**
* Lấy access token từ Bank Hub
*/
public function getAccessToken(): ?string
{
$response = Http::withBasicAuth($this->clientId, $this->clientSecret)
->post($this->baseUrl . '/v1/token');
 
if ($response->successful()) {
$data = $response->json();
return $data['access_token'] ?? null;
}
 
throw new \Exception('Failed to get access token: ' . $response->body());
}
}
 
  • Response
RESPONSE 201 - Thành công
{
  "code": 201,
  "access_token": "36483db493b10304eb3abc143b3593fa1473eb9b",
  "ttl": 60000
}
Lưu trữ Token
  • Lưu access_token vào cache (Redis, Memcached) hoặc session
  • Token có thời gian hiệu lực (ttl), nên implement cơ chế refresh tự động
  • Khi nhận lỗi 401 Unauthorized, tự động lấy token mới

Sau khi có access_token, sử dụng nó để tạo link token. Link token sẽ cung cấp hosted_link_url - đây là URL bạn sẽ nhúng vào iframe.

  • API Endpoint
POST
https://bankhub-api-sandbox.sepay.vn/v1/link-token/create
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json
  • Code mẫu
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
<?php
// File: app/Services/BankHubService.php (tiếp)
 
namespace App\Services;
 
use Illuminate\Support\Facades\Http;
 
class BankHubService
{
// ... (code getAccessToken ở trên)
 
/**
* Tạo link token để liên kết tài khoản ngân hàng
*/
public function createLinkToken(
string $companyXid,
string $purpose = 'LINK_BANK_ACCOUNT',
?string $redirectUri = null
): array {
$accessToken = $this->getAccessToken();
 
$payload = [
'company_xid' => $companyXid,
'purpose' => $purpose,
];
 
if ($redirectUri) {
$payload['completion_redirect_uri'] = $redirectUri;
}
 
$response = Http::withToken($accessToken)
->post($this->baseUrl . '/v1/link-token/create', $payload);
 
if ($response->successful()) {
return $response->json();
}
 
throw new \Exception('Failed to create link token: ' . $response->body());
}
}
 
// Sử dụng trong Controller:
// File: app/Http/Controllers/BankHubController.php
 
namespace App\Http\Controllers;
 
use App\Services\BankHubService;
use Illuminate\Http\Request;
 
class BankHubController extends Controller
{
private $bankHub;
 
public function __construct(BankHubService $bankHub)
{
$this->bankHub = $bankHub;
}
 
public function getLinkUrl(Request $request)
{
$companyXid = $request->user()->company_xid; // Lấy từ user đã đăng nhập
$redirectUri = route('bankhub.callback'); // URL callback của bạn
 
$result = $this->bankHub->createLinkToken(
$companyXid,
'LINK_BANK_ACCOUNT',
$redirectUri
);
 
return response()->json([
'hosted_link_url' => $result['hosted_link_url'],
'expires_at' => $result['expires_at']
]);
}
}
 
Note

Code mẫu trên chỉ ví dụ cho trường hợp tạo link token cho luồng liên kết tài khoản, nếu bạn cần tạo luồng huỷ liên kết thì nên truyền purposeUNLINK_BANK_ACCOUNT và truyền thêm bank_account_xid

  • Response
RESPONSE 201 - Tạo thành công
{
  "xid": "850e8400-e29b-41d4-a716-446655440000",
  "hosted_link_url": "https://bankhub.sepay.vn/link/850e8400-e29b-41d4-a716-446655440000",
  "link_token": "950e8400-e29b-41d4-a716-446655440000",
  "expires_at": "2024-01-17 10:30:00"
}

Bước 3: Nhúng Iframe vào Website

Sau khi có hosted_link_url từ bước 2, bạn có thể nhúng nó vào website thông qua iframe.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
<!DOCTYPE html>
<html>
<head>
<title>Liên kết tài khoản ngân hàng</title>
<style>
.bankhub-container {
width: 100%;
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
 
.bankhub-iframe {
width: 100%;
height: 600px;
border: 1px solid #e5e7eb;
border-radius: 8px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
</style>
</head>
<body>
<div class="bankhub-container">
<h1>Liên kết tài khoản ngân hàng</h1>
<iframe
id="bankhub-iframe"
class="bankhub-iframe"
src=""
frameborder="0"
allow="clipboard-write"
></iframe>
</div>
 
<script>
// Gọi API backend để lấy hosted_link_url
async function loadBankHubLink() {
try {
const response = await fetch('/api/bankhub/get-link-url', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${userToken}`
}
});
 
const data = await response.json();
document.getElementById('bankhub-iframe').src = data.hosted_link_url;
} catch (error) {
console.error('Error loading Bank Hub link:', error);
alert('Không thể tải giao diện liên kết ngân hàng. Vui lòng thử lại.');
}
}
 
loadBankHubLink();
 
// Lắng nghe sự kiện từ iframe (postMessage)
window.addEventListener('message', function(event) {
if (event.origin !== 'https://bankhub.sepay.vn') return;
 
const { event: eventType, metadata, timestamp } = event.data;
 
switch(eventType) {
case 'FINISHED_BANK_ACCOUNT_LINK':
console.log('Tài khoản đã được liên kết:', metadata);
alert(`Liên kết thành công: ${metadata.account_number}`);
window.location.href = '/dashboard';
break;
case 'FINISHED_BANK_ACCOUNT_UNLINK':
console.log('Tài khoản đã được hủy liên kết');
alert('Hủy liên kết thành công!');
window.location.href = '/dashboard';
break;
case 'BANKHUB_CLOSE_LINK':
console.log('Người dùng đóng flow liên kết');
break;
case 'BANKHUB_TOKEN_EXPIRED':
console.warn('Token đã hết hạn');
alert('Phiên làm việc đã hết hạn. Vui lòng thử lại.');
break;
case 'BANKHUB_SESSION_EXPIRED':
console.warn('Session đã hết hạn');
alert('Phiên làm việc đã hết hạn. Vui lòng thử lại.');
break;
}
});
</script>
</body>
</html>
Thông tin

Nếu bạn đã cung cấp completion_redirect_uri khi tạo link token, bạn sẽ được redirect về URL đã cung cấp


PostMessage Events

Iframe sẽ gửi các sự kiện qua window.postMessage với format:

event format
{
  "event": "FINISHED_BANK_ACCOUNT_LINK | FINISHED_BANK_ACCOUNT_UNLINK | BANKHUB_CLOSE_LINK | BANKHUB_TOKEN_EXPIRED | BANKHUB_SESSION_EXPIRED",
  "metadata": {
    "account_number": "string",
    "account_type": "individual | enterprise"
  },
  "timestamp": "string"
}

Các loại events:

FINISHED_BANK_ACCOUNT_LINK

Tài khoản ngân hàng đã được liên kết thành công. Metadata chứa thông tin tài khoản.

FINISHED_BANK_ACCOUNT_UNLINK

Tài khoản ngân hàng đã được hủy liên kết thành công.

BANKHUB_CLOSE_LINK

Người dùng đóng/hủy bỏ flow liên kết.

BANKHUB_TOKEN_EXPIRED

Link token đã hết hạn, cần tạo token mới.

BANKHUB_SESSION_EXPIRED

Phiên làm việc đã hết hạn, cần khởi tạo lại.


Cấu hình nhận thông báo biến động số dư (IPN)

➤ Bạn có thể xem chi tiết tại đây


Bước tiếp theo

Sau khi hoàn thành các bước tích hợp cơ bản, bạn có thể:

  1. Cấu hình nhận thông báo biến động số dư - Thiết lập IPN webhook để nhận thông báo giao dịch realtime
  2. Webhook Events - Nhận thông báo các sự kiện liên kết/hủy liên kết tài khoản
  3. SDK JavaScript - Sử dụng SDK để kiểm soát vòng đời phiên tốt hơn
  4. API Reference - Xem đầy đủ các API có sẵn
Lưu ý

Đảm bảo bạn đã test kỹ trong môi trường Sandbox với tài khoản test trước khi chuyển sang Production.