Skip to main content

Documentation Index

Fetch the complete documentation index at: https://developers.fhsc.com.vn/llms.txt

Use this file to discover all available pages before exploring further.

API chia 2 tier theo mức độ nhạy cảm của dữ liệu. Tier 1 là mặc định cho dữ liệu thị trường công khai; Tier 2 áp dụng cho các endpoint user-scoped (đánh dấu riêng trong API Reference).

Tier 1 — Chỉ cần API key

Chỉ cần gửi header X-FH-APIKEY trên mọi request. Áp dụng cho các endpoint dữ liệu thị trường công khai:
  • Toàn bộ GET /market/**
  • GET /trading/market/**
curl -H "X-FH-APIKEY: $FINHAY_API_KEY" \
  "https://open-api.fhsc.com.vn/market/stock-realtime?symbol=VNM"

Tier 2 — HMAC signing đầy đủ

Áp dụng cho các endpoint liên quan đến thông tin user / tài khoản / lệnh giao dịch / lãi-lỗ. Mỗi request cần đủ 4 header (cộng X-FH-BODYHASH khi request có body):
HeaderKhi nàoGiá trị
X-FH-APIKEYLuôn luônClient API key (dài hạn)
X-FH-TIMESTAMPTier 2Unix time hiện tại, đơn vị mili-giây
X-FH-NONCETier 2UUIDv4, duy nhất per request
X-FH-SIGNATURETier 2HMAC_SHA256(secret, payload) — hex lowercase
X-FH-BODYHASHTier 2 có bodySHA256(body) — hex lowercase
Endpoint Tier 2 hiện có:
  • GET /users/v1/users/me
  • GET /users/v1/users/{userId}/sub-accounts
  • GET /users/v4/users/{userId}/assets/summary
  • GET /trading/accounts/{subAccountId}/summary
  • GET /trading/v1/accounts/{subAccountId}/order-book
  • GET /trading/v1/accounts/{subAccountId}/order-book/{orderId}
  • GET /trading/v2/sub-accounts/{subAccountId}/portfolio
  • GET /trading/v5/account/{subAccountId}/user-rights
  • GET /trading/pnl-today/{userId}

Signing payload

Payload đầu vào cho HMAC được build theo template dưới (mỗi field nối bằng \n):
{TIMESTAMP}\n{METHOD}\n{PATH}[?{QUERY}]\n{BODYHASH}
1

TIMESTAMP

Unix mili-giây, chuỗi số thập phân (ví dụ "1714464000123"). Server chấp nhận lệch tối đa ±30 giây so với giờ thực — đảm bảo client đồng bộ NTP.
2

METHOD

HTTP method viết hoa: GET, POST, PUT, DELETE.
3

PATH [?QUERY]

Path của request, ví dụ /trading/accounts/0001234567/summary. Nếu request có query string, nối thêm với prefix ? (ví dụ /market/stock-realtime?symbol=VNM). Bỏ hoàn toàn segment ? nếu không có query.
4

BODYHASH

SHA256(body) ở dạng hex lowercase. Là chuỗi rỗng khi body rỗng. Nối thẳng sau \n cuối cùng — không thêm newline riêng sau BODYHASH.
Replay protection: server nhớ cặp (apiKey, nonce) trong 5 phút. Nonce reused trong window đó sẽ bị từ chối với mã AUTH_NONCE_REUSED (HTTP 401). Mỗi request phải sinh nonce mới — recommend UUIDv4.
Toàn bộ metadata signing (algorithm, tên header, replay window, …) được expose qua OpenAPI extension x-finhay-signing ở root spec, để các tool codegen tự sinh signing layer.

Signing middleware

OpenAPI generator thường sinh 5 setter độc lập (setApiKey, setTimestamp, setNonce, setSignature, setBodyHash) — chỉ API key được set bằng tay. 4 setter còn lại cần được tính per-request bởi middleware chạy ngay trước HTTP call. Tích hợp đoạn code dưới vào client (hoặc tương đương) và bỏ qua các setter còn lại.
import axios from "axios";
import crypto from "node:crypto";

const API_KEY    = process.env.FINHAY_API_KEY!;
const API_SECRET = process.env.FINHAY_API_SECRET!;
const BASE_URL   = process.env.FINHAY_BASE_URL ?? "https://open-api.fhsc.com.vn";

const API_KEY_ONLY: RegExp[] = [
  /^\/market\/.*$/,
  /^\/trading\/market\/.*$/,
];

const isApiKeyOnly = (method: string, path: string): boolean =>
  method === "GET" && API_KEY_ONLY.some((re) => re.test(path));

export const client = axios.create({ baseURL: BASE_URL });

client.interceptors.request.use((config) => {
  const method = (config.method ?? "get").toUpperCase();
  const url    = new URL(config.url ?? "", BASE_URL);
  const path   = url.pathname;

  // Luôn gửi API key.
  config.headers.set("X-FH-APIKEY", API_KEY);

  // Tier 1: market read — dừng ở đây.
  if (isApiKeyOnly(method, path)) return config;

  // Tier 2: HMAC sign request.
  const timestamp = Date.now().toString();
  const nonce     = crypto.randomUUID();
  const query     = url.search.slice(1); // bỏ leading '?'
  const body      = typeof config.data === "string"
    ? config.data
    : config.data != null
      ? JSON.stringify(config.data)
      : "";
  const bodyHash  = body
    ? crypto.createHash("sha256").update(body).digest("hex")
    : "";

  let payload = `${timestamp}\n${method}\n${path}`;
  if (query)    payload += `?${query}`;
  payload += "\n";
  if (bodyHash) payload += bodyHash;

  const signature = crypto
    .createHmac("sha256", API_SECRET)
    .update(payload)
    .digest("hex");

  config.headers.set("X-FH-TIMESTAMP", timestamp);
  config.headers.set("X-FH-NONCE",     nonce);
  config.headers.set("X-FH-SIGNATURE", signature);
  if (bodyHash) config.headers.set("X-FH-BODYHASH", bodyHash);
  return config;
});
Lưu ý về form “Try It”: form gọi thử endpoint tích hợp trong tab API Reference KHÔNG tự tính HMAC signature. Để test endpoint Tier 2, hãy dùng Postman (setup pre-request script để sign), hoặc tự tính signature rồi paste vào header tương ứng.