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 Type | Mô tả |
|---|---|
| NONE | Dữ liệu công khai, dữ liệu tài chính datafeed - chỉ yêu cầu API Key |
| SIGNED | Yêu cầu API Key và chữ ký số (signature) |
- API Key và Secret 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
| Header | Mô tả |
|---|---|
X-Api-Key | API 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ên | Vị trí | Bắt buộc | Mô tả |
|---|---|---|---|
X-Api-Key | Header | Có | API Key được cấp bởi Simplize |
timestamp | Query | Có | Unix timestamp (milliseconds) |
signature | Query | Có | Chữ ký HMAC-SHA256 (hex) |
recvWindow | Query | Không | Thờ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ức | Content-Type | Mô tả |
|---|---|---|
| Query String | - | Gửi parameters trên URL: ?param1=value1¶m2=value2 |
| Request Body | application/x-www-form-urlencoded | Gửi parameters trong body request |
| JSON Body | application/json | Chỉ sử dụng khi tài liệu API yêu cầ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 Key và Secret Key được cấp bởi Simplize:
| Key | Ví dụ |
|---|---|
| API Key | ABC123_xyzSecretApiKeyHere... |
| Secret Key | KhqStmdSJYdKjVHj....... |
Bước 2: Xây dựng Signature Payload
Cấu trúc Payload
payload = METHOD + REQUEST_PATH + QUERY_STRING + BODY
| Thành phần | Mô tả | Ví dụ |
|---|---|---|
| METHOD | HTTP 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_STRING | Parameters dạng key=value nối bằng & | externalUserId=USER001×tamp=123 |
| BODY | JSON body (minified, không có whitespace) | {"qty":10} |
Quy tắc quan trọng
- 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.
- Giữ nguyên thứ tự parameters - KHÔNG sắp xếp theo thứ tự bảng chữ cái (alphabetical).
- Percent-encode tất cả các key và value trong query string.
- 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ính | Giá trị |
|---|---|
| Method | POST |
| Path | /api/general/v1/partner/users/register |
| externalUserId | USER001 |
| recvWindow | 5000 |
| timestamp | 1734567890123 |
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×tamp=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×tamp=1734567890123
Ví dụ 2: Request có ký tự non-ASCII (tiếng Việt)
Thông tin request:
| Thuộc tính | Giá trị |
|---|---|
| Method | GET |
| Path | /api/company/v1/partner/search |
| name | Việt Nam |
| timestamp | 1734567890123 |
Sau khi percent-encode và nối:
GET/api/company/v1/partner/searchname=Vi%E1%BB%87t%20Nam×tamp=1734567890123
Ví dụ 3: Đồng bộ danh mục đầu tư (JSON Body)
Thông tin request:
| Thuộc tính | Giá trị |
|---|---|
| Method | POST |
| Path | /api/personalize/v1/partner/sync/portfolio/instant |
| recvWindow | 5000 |
| timestamp | 1734567890123 |
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×tamp=1734567890123{"holding":[{"code":"FPT","totalQty":100}],"cash":{"cashValue":10000000}}
Bước 3: Tính toán Signature
- Sử dụng
Secret Keylàm khóa ký cho thuật toán HMAC-SHA256. - Ký payload đã xây dựng ở Bước 2.
- 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×tamp=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×tamp=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 +
"×tamp=" +
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}×tamp={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 + "×tamp=" + 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}×tamp={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ính | Giá trị |
|---|---|
| Mặc định | 5000ms (5 giây) |
| Tối đa | 60000ms (60 giây) |
| Khuyến nghị | 5000ms hoặc nhỏ hơn |
Request sẽ bị từ chối nếu:
timestampvượt quá thời gian server + 1 giây- Request đã quá
recvWindowkể từtimestamp
7. Mã Lỗi Thường Gặp
| HTTP Status | Lỗi | Mô tả |
|---|---|---|
| 400 | Invalid timestamp or recvWindow format | Không phải số hợp lệ |
| 403 | Timestamp is ahead of server time | Timestamp vượt quá server time + 1 giây |
| 403 | Request expired | Request đã hết hạn |
| 403 | Invalid signature | Chữ ký không hợp lệ |
| 403 | Missing signature | Thiếu parameter signature |
| 403 | API Key validation failed | API 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ệ:
- Facebook: Simplize Fanpage
- Email:
info@simplize.vn