Chuyển tới nội dung chính

Bảo mật Request (Request Security)

Trang này hướng dẫn cách xác thực và ký (sign) các request khi tích hợp API của Simplize.


1. Tổng quan

Mỗi endpoint API có một loại bảo mật (security type) xác định phương thức xác thực cần thiết.

Security TypeMô tả
NONEDữ liệu công khai, dữ liệu tài chính datafeed - chỉ yêu cầu API Key
SIGNEDYêu cầu API Key và chữ ký số (signature)
Lưu ý quan trọng
  • API KeySecret Key là thông tin bảo mật cực kỳ nhạy cảm. KHÔNG BAO GIỜ chia sẻ với bất kỳ ai.
  • Nếu phát hiện hoạt động bất thường trên tài khoản, hãy thu hồi tất cả API Key ngay lập tức.

2. API Key Authentication

Với các endpoint có security type là NONE, bạn chỉ cần gửi API Key trong header.

Header bắt buộc

HeaderMô tả
X-Api-KeyAPI Key được cấp bởi Simplize

Ví dụ: Lấy thông tin cổ phiếu

Node.js

const apiKey = "YOUR_API_KEY";
const ticker = "VNM";

const response = await fetch(
`https://api.simplize.vn/api/company/v1/partner/summary/${ticker}`,
{
method: "GET",
headers: {
"X-Api-Key": apiKey,
},
}
);

const data = await response.json();
console.log(data);

Python

import requests

api_key = "YOUR_API_KEY"
ticker = "VNM"

response = requests.get(
f"https://api.simplize.vn/api/company/v1/partner/summary/{ticker}",
headers={"X-Api-Key": api_key}
)

print(response.json())

3. SIGNED Endpoint Security

Các endpoint có security type là SIGNED yêu cầu gửi kèm signature trong query string.

Header và Parameter bắt buộc

TênVị tríBắt buộcMô tả
X-Api-KeyHeaderAPI Key được cấp bởi Simplize
timestampQueryUnix timestamp (milliseconds)
signatureQueryChữ ký HMAC-SHA256 (hex)
recvWindowQueryKhôngThời gian request hợp lệ (ms), mặc định 5000

Đặc điểm Signature

Signature được tạo bằng thuật toán HMAC-SHA256 có các đặc điểm sau:

  • Không phân biệt chữ hoa/thường: Signature có thể được xác thực bất kể cách viết hoa hay thường.
  • Định dạng hex: Kết quả là chuỗi hex 64 ký tự (lowercase).

Cách gửi Parameters

Parameters có thể được gửi theo một trong các cách sau:

Phương thứcContent-TypeMô tả
Query String-Gửi parameters trên URL: ?param1=value1&param2=value2
Request Bodyapplication/x-www-form-urlencodedGửi parameters trong body request
JSON Bodyapplication/jsonChỉ sử dụng khi tài liệu API yêu cầu
Lưu ý
  • Nếu tài liệu API endpoint yêu cầu JSON body, bạn PHẢI sử dụng JSON.
  • Các trường hợp khác, bạn có thể tự do lựa chọn gửi qua Query String hoặc Request Body.
  • Không được trộn lẫn Query String và Request Body cho cùng một parameter.

4. Hướng dẫn Tạo Signature

Bước 1: Chuẩn bị thông tin xác thực

Bạn cần có API KeySecret Key được cấp bởi Simplize:

KeyVí dụ
API KeyABC123_xyzSecretApiKeyHere...
Secret KeyKhqStmdSJYdKjVHj.......

Bước 2: Xây dựng Signature Payload

Cấu trúc Payload

payload = METHOD + REQUEST_PATH + QUERY_STRING + BODY
Thành phầnMô tảVí dụ
METHODHTTP method (uppercase)POST, GET, PUT, DELETE
REQUEST_PATHĐường dẫn API (không bao gồm domain và query string)/api/general/v1/partner/users/register
QUERY_STRINGParameters dạng key=value nối bằng &externalUserId=USER001&timestamp=123
BODYJSON body (minified, không có whitespace){"qty":10}

Quy tắc quan trọng

  1. Nối trực tiếp tất cả các phần - KHÔNG có ký tự phân cách (separator) giữa method, path, query string và body.
  2. Giữ nguyên thứ tự parameters - KHÔNG sắp xếp theo thứ tự bảng chữ cái (alphabetical).
  3. Percent-encode tất cả các key và value trong query string.
  4. Ký tự non-ASCII PHẢI được percent-encode trước khi ký.

Ví dụ 1: Đăng ký tài khoản người dùng (Query Parameters)

Thông tin request:

Thuộc tínhGiá trị
MethodPOST
Path/api/general/v1/partner/users/register
externalUserIdUSER001
recvWindow5000
timestamp1734567890123

Bước 2.1: Xác định Method và Path

POST/api/general/v1/partner/users/register

Bước 2.2: Format query parameters thành chuỗi key=value phân cách bằng &

externalUserId=USER001&recvWindow=5000&timestamp=1734567890123

Bước 2.3: Nối tất cả thành payload hoàn chỉnh

POST/api/general/v1/partner/users/registerexternalUserId=USER001&recvWindow=5000&timestamp=1734567890123

Ví dụ 2: Request có ký tự non-ASCII (tiếng Việt)

Thông tin request:

Thuộc tínhGiá trị
MethodGET
Path/api/company/v1/partner/search
nameViệt Nam
timestamp1734567890123

Sau khi percent-encode và nối:

GET/api/company/v1/partner/searchname=Vi%E1%BB%87t%20Nam&timestamp=1734567890123

Ví dụ 3: Đồng bộ danh mục đầu tư (JSON Body)

Thông tin request:

Thuộc tínhGiá trị
MethodPOST
Path/api/personalize/v1/partner/sync/portfolio/instant
recvWindow5000
timestamp1734567890123

JSON Body (stringify, không có whitespace):

{
"holding": [
{
"code": "FPT",
"totalQty": 100
}
],
"cash": {
"cashValue": 10000000
}
}

Signature Payload (nối trực tiếp, KHÔNG có ký tự xuống dòng \n):

POST/api/personalize/v1/partner/sync/portfolio/instantrecvWindow=5000&timestamp=1734567890123{"holding":[{"code":"FPT","totalQty":100}],"cash":{"cashValue":10000000}}

Bước 3: Tính toán Signature

  1. Sử dụng Secret Key làm khóa ký cho thuật toán HMAC-SHA256.
  2. Ký payload đã xây dựng ở Bước 2.
  3. Chuyển đổi kết quả HMAC-SHA256 thành chuỗi hex (lowercase).

Ví dụ sử dụng command line:

echo -n "POST/api/general/v1/partner/users/registerexternalUserId=USER001&recvWindow=5000&timestamp=1734567890123" | \
openssl dgst -sha256 -hmac "YOUR_SECRET_KEY"

Kết quả:

a1b2c3d4e5f6789... (chuỗi hex 64 ký tự)

Bước 4: Gửi Request

Thêm parameter signature vào query string và gửi request:

curl -H "X-API-KEY: YOUR_API_KEY" \
-X POST "https://api.simplize.vn/api/general/v1/partner/users/register?externalUserId=USER001&recvWindow=5000&timestamp=1734567890123&signature=a1b2c3d4..."

5. Code Examples

5.1. Request với Query Parameters

API đăng ký tài khoản người dùng mới.

Node.js

var crypto = require("crypto");

// Thông tin xác thực
var apiKey = "YOUR_API_KEY";
var secretKey = "YOUR_SECRET_KEY";

// Tạo timestamp (milliseconds)
var timestamp = Date.now();

// Thông tin request
var method = "POST";
var requestPath = "/api/general/v1/partner/users/register";
var externalUserId = "USER001";
var recvWindow = 5000;

// Xây dựng query string (giữ nguyên thứ tự parameters)
var queryString =
"externalUserId=" +
externalUserId +
"&recvWindow=" +
recvWindow +
"&timestamp=" +
timestamp;

// Xây dựng payload: method + path + queryString
var payload = method + requestPath + queryString;

// Tạo HMAC-SHA256 signature
var signature = crypto
.createHmac("sha256", secretKey)
.update(payload)
.digest("hex");

// Gửi request
var url =
"https://api.simplize.vn" +
requestPath +
"?" +
queryString +
"&signature=" +
signature;

fetch(url, {
method: method,
headers: {
"X-Api-Key": apiKey,
"Content-Type": "application/json",
},
})
.then((res) => res.json())
.then((data) => console.log(data));

Python

import hmac
import hashlib
import time
import requests

# Thông tin xác thực
api_key = "YOUR_API_KEY"
secret_key = "YOUR_SECRET_KEY"

# Tạo timestamp (milliseconds)
timestamp = int(time.time() * 1000)

# Thông tin request
method = "POST"
request_path = "/api/general/v1/partner/users/register"
external_user_id = "USER001"
recv_window = 5000

# Xây dựng query string (giữ nguyên thứ tự parameters)
query_string = f"externalUserId={external_user_id}&recvWindow={recv_window}&timestamp={timestamp}"

# Xây dựng payload: method + path + queryString
payload = method + request_path + query_string

# Tạo HMAC-SHA256 signature
signature = hmac.new(
secret_key.encode("utf-8"),
payload.encode("utf-8"),
hashlib.sha256
).hexdigest()

# Gửi request
url = f"https://api.simplize.vn{request_path}?{query_string}&signature={signature}"

response = requests.post(
url,
headers={
"X-Api-Key": api_key,
"Content-Type": "application/json"
}
)

print(response.json())

5.2. Request với JSON Body

API đồng bộ danh mục đầu tư. Payload = method + path + queryString + body.

Node.js

var crypto = require("crypto");

// Thông tin xác thực
var apiKey = "YOUR_API_KEY";
var secretKey = "YOUR_SECRET_KEY";

// Tạo timestamp (milliseconds)
var timestamp = Date.now();
var recvWindow = 5000;

// Thông tin request
var method = "POST";
var requestPath = "/api/personalize/v1/partner/sync/portfolio/instant";

// JSON body (phải minify - không có whitespace)
var body = JSON.stringify({
holding: [
{
transDate: "2024-01-15",
code: "FPT",
totalQty: 100,
tradableQty: 100,
t0PendingSettlementBuyQty: 0,
t1PendingSettlementBuyQty: 0,
t2PendingSettlementBuyQty: 0,
pendingEntitlementQty: 0,
costPrice: 95000,
marketPrice: 98000,
},
],
cash: {
cashValue: 10000000,
marketValue: 25400000,
stockMain: 0,
},
});

// Xây dựng payload: method + path + queryString + body (nối trực tiếp)
var queryString = "recvWindow=" + recvWindow + "&timestamp=" + timestamp;
var payload = method + requestPath + queryString + body;

// Tạo HMAC-SHA256 signature
var signature = crypto
.createHmac("sha256", secretKey)
.update(payload)
.digest("hex");

// Gửi request
var url =
"https://api.simplize.vn" +
requestPath +
"?" +
queryString +
"&signature=" +
signature;

fetch(url, {
method: method,
headers: {
"X-Api-Key": apiKey,
"Content-Type": "application/json",
},
body: body,
})
.then((res) => res.json())
.then((data) => console.log(data));

Python

import hmac
import hashlib
import time
import json
import requests

# Thông tin xác thực
api_key = "YOUR_API_KEY"
secret_key = "YOUR_SECRET_KEY"

# Tạo timestamp (milliseconds)
timestamp = int(time.time() * 1000)
recv_window = 5000

# Thông tin request
method = "POST"
request_path = "/api/personalize/v1/partner/sync/portfolio/instant"

# JSON body
body_dict = {
"holding": [
{
"transDate": "2024-01-15",
"code": "FPT",
"totalQty": 100,
"tradableQty": 100,
"t0PendingSettlementBuyQty": 0,
"t1PendingSettlementBuyQty": 0,
"t2PendingSettlementBuyQty": 0,
"pendingEntitlementQty": 0,
"costPrice": 95000,
"marketPrice": 98000
}
],
"cash": {
"cashValue": 10000000,
"marketValue": 25400000,
"stockMain": 0
}
}

# Minify JSON (không có whitespace)
body = json.dumps(body_dict, separators=(",", ":"))

# Xây dựng payload: method + path + queryString + body (nối trực tiếp)
query_string = f"recvWindow={recv_window}&timestamp={timestamp}"
payload = method + request_path + query_string + body

# Tạo HMAC-SHA256 signature
signature = hmac.new(
secret_key.encode("utf-8"),
payload.encode("utf-8"),
hashlib.sha256
).hexdigest()

# Gửi request
url = f"https://api.simplize.vn{request_path}?{query_string}&signature={signature}"

response = requests.post(
url,
headers={
"X-Api-Key": api_key,
"Content-Type": "application/json"
},
data=body
)

print(response.json())

6. Timing Security

Mỗi request SIGNED yêu cầu parameter timestamp là Unix timestamp hiện tại tính bằng milliseconds.

Parameter recvWindow

Thuộc tínhGiá trị
Mặc định5000ms (5 giây)
Tối đa60000ms (60 giây)
Khuyến nghị5000ms hoặc nhỏ hơn

Request sẽ bị từ chối nếu:

  • timestamp vượt quá thời gian server + 1 giây
  • Request đã quá recvWindow kể từ timestamp

7. Mã Lỗi Thường Gặp

HTTP StatusLỗiMô tả
400Invalid timestamp or recvWindow formatKhông phải số hợp lệ
403Timestamp is ahead of server timeTimestamp vượt quá server time + 1 giây
403Request expiredRequest đã hết hạn
403Invalid signatureChữ ký không hợp lệ
403Missing signatureThiếu parameter signature
403API Key validation failedAPI Key không hợp lệ

8. Hỗ Trợ

Nếu bạn gặp khó khăn trong quá trình tích hợp, vui lòng liên hệ: