SFI External API — Báo cáo phân tích

Danh mục báo cáo, danh mục sản phẩm, danh sách và chi tiết báo cáo phân tích cho ứng dụng đối tác — không cần đăng nhập khách hàng, chỉ xác thực bằng X-Api-Key.

https://a.sfi.com.vn/ekyc/ex_apiChính
https://b.sfi.com.vn/ekyc/ex_apiDự phòng

Tổng quan

Toàn bộ endpoint trong tài liệu này nằm trong entry point /ekyc/ex_api, dùng chung quy ước ?cmd={tên_lệnh} và chung khung phản hồi JSON. Khác với nhóm API giao dịch (open_position, account_status…), các API ở đây không cần JWT và không gắn với tài khoản khách hàng nào.

Toàn bộ ví dụ request / response trong tài liệu này được lấy từ dữ liệu thật trên môi trường production (kiểm chứng ngày 18/08/2026), đã rút gọn phần nội dung dài và biên tập lại một số tiêu đề.

Phần Tổng quan → Mã lỗi chung dùng chung cho mọi nhóm API công khai của /ekyc/ex_api; phần riêng của nhóm này (tham số, cấu trúc dữ liệu, lưu ý nghiệp vụ) nằm ở khối bên dưới.

Danh mục endpoint

NhómEndpointMô tảXác thực
1 · Báo cáo phân tích GET ?cmd=news_categories Danh mục báo cáo + số báo cáo, dùng dựng bộ lọc cate X-Api-Key
1 · Báo cáo phân tích GET ?cmd=news_products Danh mục sản phẩm, dùng dựng bộ lọc productslug X-Api-Key
1 · Báo cáo phân tích GET ?cmd=news Danh sách báo cáo, lọc theo danh mục / sản phẩm / tháng X-Api-Key
1 · Báo cáo phân tích GET ?cmd=news&id=… Chi tiết một báo cáo (kèm content HTML) X-Api-Key

Danh mục này là nguồn tra cứu nhanh của nhóm Báo cáo phân tích — mỗi endpoint có một mục mô tả chi tiết bên dưới.

Xác thực bằng API Key

Mọi request phải gửi kèm header:

X-Api-Key: {api_key_được_SFI_cấp}

Nếu thiếu hoặc sai key, server trả về HTTP 401 với body {"success": false, "message": "Unauthorized."}. Key được cấp riêng cho từng ứng dụng đối tác; vui lòng lưu ở phía server, không nhúng vào ứng dụng client.

Cùng một X-Api-Key dùng chung cho tất cả nhóm API trong tài liệu này, và cũng chính là key dùng cho guestcmd=login_request ở luồng OOB Auth.

Định dạng phản hồi

Toàn bộ API dùng chung khung phản hồi JSON của hệ thống SFI:

{
  "success": true,
  "message": "Thành công!",
  "data": [ ... ],
  "svr": "srv-01"
}
TrườngKiểuMô tả
successbooleanKết quả xử lý
messagestringThông điệp (tiếng Việt)
dataarray / objectDữ liệu trả về. Rỗng ([]) khi lỗi; vắng mặt ở phản hồi lỗi xác thực JWT — xem Mã lỗi chung
svrstringĐịnh danh máy chủ xử lý (dùng khi báo lỗi)

Mã lỗi chung

HTTPmessageNguyên nhân
401Unauthorized.Thiếu header X-Api-Key hoặc key không hợp lệ
200[IAH] Phiên làm việc đã hết hạn. Vui lòng đăng nhập lại!cmd không thuộc nhóm API công khai, hoặc gọi bằng phương thức khác GET — request rơi vào nhánh yêu cầu JWT. Phản hồi này không có khóa data.
200(tuỳ nghiệp vụ)Lỗi nghiệp vụ — xem success: false và message
Theo quy ước chung của hệ thống SFI, phần lớn lỗi nghiệp vụ vẫn trả HTTP 200 với success: false. Client luôn phải kiểm tra trường success, không chỉ dựa vào HTTP status. Mã lỗi riêng của nhóm này được liệt kê ở cuối khối bên dưới.

Báo cáo phân tích

Danh mục báo cáo, danh mục sản phẩm, danh sách và chi tiết báo cáo phân tích. Nguồn dữ liệu là kho báo cáo của SFI, đồng bộ tự động từ website.

Lưu ý về nội dung: trong ứng dụng khách hàng, một số báo cáo bị che nếu giá trị ký quỹ của khách dưới ngưỡng quy định. Với API đối tác (đã có API Key) không áp dụng giới hạn này — luôn trả về nội dung đầy đủ. Đối tác chịu trách nhiệm kiểm soát việc hiển thị ở phía mình.

1 · Danh mục báo cáo

GET X-API-KEY

?cmd=news_categories

Trả về mọi danh mục đang có báo cáo, kèm số báo cáo, sắp xếp theo tên. Dùng để dựng danh sách chọn cho bộ lọc cate. Danh mục chưa gắn với báo cáo nào sẽ không xuất hiện.

Không có tham số.

Request

curl 'https://a.sfi.com.vn/ekyc/ex_api?cmd=news_categories' \
  -H 'X-Api-Key: YOUR_API_KEY'

Response

{
  "success": true,
  "message": "Thành công",
  "data": [
    { "id": 71, "slug": "duong",               "name": "Đường",                "count": 128 },
    { "id": 88, "slug": "kim-loai-quy",        "name": "Kim loại quý",         "count": 54  },
    { "id": 63, "slug": "phan-tich-chuyen-sau","name": "Phân tích chuyên sâu", "count": 316 }
  ],
  "svr": "srv-01"
}
TrườngKiểuMô tả
idintMã danh mục
slugstringGiá trị truyền cho tham số cate
namestringTên hiển thị
countintSố báo cáo thuộc danh mục
Nên cache. Danh mục hầu như không đổi trong ngày — gọi một lần lúc mở app / khởi động tiến trình rồi dùng lại, đừng gọi kèm mỗi lần lật trang danh sách báo cáo.

Thử ngay — ?cmd=news_categories

chưa gọi

Khóa categories trong mỗi báo cáo

Mỗi báo cáo được gán vào một hoặc nhiều danh mục trên hệ thống nội dung của SFI (ví dụ Phân tích chuyên sâu, Vĩ mô, Đường, Kim loại quý). Danh sách này trả về ở khóa categories của cả API danh sách lẫn API chi tiết, theo đúng thứ tự đã cấu hình:

"categories": [
  { "id": 63, "slug": "phan-tich-chuyen-sau", "name": "Phân tích chuyên sâu" },
  { "id": 71, "slug": "duong",                "name": "Đường" }
]
TrườngKiểuMô tả
idintMã danh mục. Ổn định, không đổi khi đổi tên.
slugstringGiá trị dùng cho tham số cate. Có thể rỗng trong trường hợp hiếm (danh mục vừa tạo, chưa đồng bộ được tên) — khi đó lọc theo slug sẽ không khớp báo cáo đó.
namestringTên hiển thị tiếng Việt.

Lọc theo danh mục

Tham số cate nhận một hoặc nhiều slug ngăn cách bằng dấu phẩy. Nhiều slug hiểu theo HOẶC:

# một danh mục
?cmd=news&cate=vi-mo

# hai danh mục — báo cáo thuộc BẤT KỲ danh mục nào trong hai
?cmd=news&cate=phan-tich-chuyen-sau,vi-mo

# kết hợp với các bộ lọc khác: giữa các THAM SỐ là VÀ
?cmd=news&cate=kim-loai-quy&productslug=bac&modified=08-2026

Nói cách khác: trong cate là HOẶC, giữa cate với productslug / modified là VÀ. Hiện chưa hỗ trợ yêu cầu "báo cáo phải thuộc đủ nhiều danh mục" (VÀ trong cùng cate) — cần thì báo SFI.

Phân trang sâu: khi lọc theo cate, hệ thống xét 20.000 báo cáo mới nhất của các danh mục đó. Với size tối đa 100 thì tương đương 200 trang — quá mốc này kết quả sẽ rỗng. Cần lấy toàn bộ kho lịch sử của một danh mục thì hãy thu hẹp thêm bằng modified theo từng tháng.

2 · Danh sách sản phẩm (bộ lọc)

GET X-API-KEY

?cmd=news_products

Trả về bản đồ sản phẩm SFI dùng để gắn sản phẩm cho báo cáo. Kết quả dùng để dựng danh sách chọn cho tham số productslug ở API danh sách báo cáo.

Request

curl 'https://a.sfi.com.vn/ekyc/ex_api?cmd=news_products' \
  -H 'X-Api-Key: YOUR_API_KEY'

Response

{
  "success": true,
  "message": "Thành công",
  "data": [
    {
      "name": "Kim loại",
      "subs": [
        { "slug": "bac", "name": "Bạc" },
        { "slug": "bach-kim", "name": "Bạch kim" },
        { "slug": "dong-lme", "name": "Đồng LME" }
      ]
    },
    {
      "name": "Năng lượng",
      "subs": [
        { "slug": "dau-brent", "name": "Dầu Brent" }
      ]
    }
  ],
  "svr": "srv-01"
}
TrườngKiểuMô tả
namestringTên nhóm sản phẩm — trùng với productgroup của báo cáo
subsarrayDanh sách sản phẩm trong nhóm
subs[].namestringTên sản phẩm — trùng với product của báo cáo
subs[].slugstringGiá trị dùng cho tham số productslug ở API danh sách báo cáo
Dữ liệu thực tế (08/2026): 4 nhóm — Kim loại (18 sản phẩm), Năng lượng (9), Nguyên liệu công nghiệp (9), Nông sản (10). Ví dụ trên đã được rút gọn.

Thử ngay — ?cmd=news_products

Không có tham số.

chưa gọi

3 · Danh sách báo cáo

GET X-API-KEY

?cmd=news

Trả về danh sách báo cáo theo trang, sắp xếp mới nhất trước. Trường content không có trong danh sách — gọi API chi tiết để lấy nội dung.

Tham số truy vấn

Tham sốKiểuBắt buộcMặc địnhMô tả
productslugstringKhông — Lọc theo sản phẩm, lấy từ cmd=news_products. Chỉ khớp báo cáo có gắn sản phẩm.
catestringKhông — Lọc theo danh mục của báo cáo — xem mục 1. Một slug (cate=phan-tich-chuyen-sau) hoặc nhiều slug ngăn cách bằng dấu phẩy (cate=phan-tich-chuyen-sau,vi-mo). Nhiều giá trị hiểu theo HOẶC: báo cáo thuộc bất kỳ danh mục nào trong danh sách đều được trả về. Tối đa 20 slug mỗi lần gọi, phần dư bị bỏ. Slug không tồn tại thì đơn giản là không khớp báo cáo nào (không phải lỗi).
modifiedstring MM-YYYYKhông — Lọc theo tháng đăng, ví dụ 08-2026. Hệ thống đối chiếu theo ngày tạo báo cáo.
pageintKhông 1 Trang, bắt đầu từ 1. Giá trị < 1 được đưa về 1.
sizeintKhông 10 Số bản ghi mỗi trang, tối đa 100. Giá trị lớn hơn bị giới hạn về 100.
Phân trang: API không trả về tổng số bản ghi. Hết dữ liệu khi data rỗng, hoặc số phần tử trả về nhỏ hơn size.

Request

# Mới nhất, trang 1, 20 bản ghi
curl 'https://a.sfi.com.vn/ekyc/ex_api?cmd=news&page=1&size=20' \
  -H 'X-Api-Key: YOUR_API_KEY'

# Sản phẩm "bac" trong tháng 08/2026
curl 'https://a.sfi.com.vn/ekyc/ex_api?cmd=news&productslug=bac&modified=08-2026' \
  -H 'X-Api-Key: YOUR_API_KEY'

# Báo cáo thuộc danh mục "phan-tich-chuyen-sau" HOẶC "vi-mo"
curl 'https://a.sfi.com.vn/ekyc/ex_api?cmd=news&cate=phan-tich-chuyen-sau,vi-mo&size=20' \
  -H 'X-Api-Key: YOUR_API_KEY'

Response — báo cáo không gắn sản phẩm

{
  "success": true,
  "message": "Thành công!",
  "data": [
    {
      "id": 60730,
      "title": "LƯỢNG MÍA NGHIỀN CUỐI THÁNG 7 TẠI BRAZIL SUY GIẢM",
      "thumb": "https://img.saigonfutures.com/2026/08/ava-chiu-1808.jpg",
      "excerpt": "I. ĐƯỜNG 1. Diễn biến thị trường phiên giao dịch ngày 17/08/2026 ...",
      "created": "2026-08-18T11:23:17",
      "modified": "18/08/2026 11:23",
      "categories": [
        { "id": 63, "slug": "phan-tich-chuyen-sau", "name": "Phân tích chuyên sâu" },
        { "id": 71, "slug": "duong", "name": "Đường" }
      ]
    }
  ],
  "svr": "srv-01"
}

Response — báo cáo gắn sản phẩm

{
  "success": true,
  "message": "Thành công!",
  "data": [
    {
      "id": 60727,
      "title": "PHÂN TÍCH HỢP ĐỒNG TƯƠNG LAI BẠCH KIM KỲ HẠN THÁNG 5/2026",
      "thumb": "https://img.saigonfutures.com/2026/08/pl188.png",
      "excerpt": "NHẬN ĐỊNH XU HƯỚNG: Xu hướng Trung hạn: Tăng. ...",
      "created": "2026-08-18T09:59:13",
      "modified": "18/08/2026 09:59",
      "product": "Bạch kim",
      "productslug": "bach-kim",
      "productcode": "PLEV26",
      "productgroup": "Kim loại",
      "categories": [
        { "id": 88, "slug": "kim-loai-quy", "name": "Kim loại quý" }
      ]
    }
  ],
  "svr": "srv-01"
}

Thử ngay — ?cmd=news

chưa gọi

4 · Chi tiết báo cáo

GET X-API-KEY

?cmd=news&id={id}

Cùng cmd=news; khi có tham số id khác rỗng, API chuyển sang chế độ chi tiết và bỏ qua mọi tham số lọc / phân trang. Gửi id= rỗng thì API vẫn trả về danh sách như bình thường.

Tham sốKiểuBắt buộcMô tả
idintCó Mã báo cáo, lấy từ trường id của API danh sách.

Request

curl 'https://a.sfi.com.vn/ekyc/ex_api?cmd=news&id=40231' \
  -H 'X-Api-Key: YOUR_API_KEY'

Response

{
  "success": true,
  "message": "Thành công!",
  "data": {
    "id": 60730,
    "title": "LƯỢNG MÍA NGHIỀN CUỐI THÁNG 7 TẠI BRAZIL SUY GIẢM",
    "thumb": "https://img.saigonfutures.com/2026/08/ava-chiu-1808.jpg",
    "content": "<h2><span><strong>I. ĐƯỜNG</strong></span></h2> <p>1. Diễn biến thị trường ...</p> ...",
    "excerpt": "I. ĐƯỜNG 1. Diễn biến thị trường phiên giao dịch ngày 17/08/2026 ...",
    "created": "2026-08-18T11:23:17",
    "modified": "18/08/2026 11:23",
    "product": "",
    "productslug": "",
    "productcode": "",
    "productgroup": "",
    "categories": [
      { "id": 63, "slug": "phan-tich-chuyen-sau", "name": "Phân tích chuyên sâu" },
      { "id": 71, "slug": "duong", "name": "Đường" }
    ]
  },
  "svr": "srv-01"
}

Thử ngay — ?cmd=news

Cùng cmd=news, chỉ khác là truyền id.

chưa gọi

5 · Trường dữ liệu báo cáo

TrườngKiểuCó ở danh sáchMô tả
idintCóMã báo cáo (dùng cho API chi tiết)
titlestringCóTiêu đề đã lược bỏ tiền tố phân loại
excerptstringCóTóm tắt, thuần văn bản. Thường kết thúc bằng ...
contentstring (HTML)KhôngNội dung đầy đủ — chỉ có ở API chi tiết. HTML thuần: đã gỡ mọi thuộc tính và thẻ bọc bố cục, riêng <img> giữ lại src
thumbstring (URL)CóẢnh đại diện
createdstring Y-m-d\TH:i:sCóThời điểm đăng (giờ Việt Nam)
productcodestringCó (nếu gắn sản phẩm)Mã hợp đồng, ví dụ PLEV26
productstringCó (nếu gắn sản phẩm)Tên sản phẩm
productgroupstringCó (nếu gắn sản phẩm)Nhóm sản phẩm
productslugstringCó (nếu gắn sản phẩm)Slug dùng cho tham số lọc
categoriesarrayCóDanh mục báo cáo được gán trên hệ thống nội dung — xem mục 1. Luôn có mặt; báo cáo chưa gán danh mục nào thì là mảng rỗng []
Khóa có / không có tùy báo cáo (đã kiểm chứng trên dữ liệu thật):
  • Danh sách · báo cáo không gắn sản phẩm: id, title, thumb, excerpt, created, modified, categories — không có nhóm trường sản phẩm.
  • Danh sách · báo cáo gắn sản phẩm: như trên, có thêm product, productslug, productcode, productgroup.
  • Chi tiết: luôn có đủ nhóm trường sản phẩm (giá trị rỗng nếu báo cáo không gắn sản phẩm) và thêm content.
  • categories có ở mọi báo cáo và ở cả danh sách lẫn chi tiết; báo cáo chưa gán danh mục nào thì là [].
Client nên truy cập mọi khóa một cách an toàn thay vì giả định luôn tồn tại. Response có thể chứa thêm khóa không được mô tả trong tài liệu này — hãy bỏ qua chúng. Thứ tự khóa trong JSON không được bảo đảm.

Mã lỗi riêng của nhóm

HTTPmessageNguyên nhân
404Không tìm thấy báo cáo.id không tồn tại (kèm data: [])

Lưu ý tích hợp

Ví dụ code

Hàm gọi chung dưới đây dùng được cho mọi endpoint công khai của /ekyc/ex_api — chỉ thay cmd và tham số.

JavaScript (server-side / Node.js)

const BASE = 'https://a.sfi.com.vn/ekyc/ex_api';
const HEADERS = { 'X-Api-Key': process.env.SFI_API_KEY };

async function call(params) {
  const qs  = new URLSearchParams(params);
  const res = await fetch(`${BASE}?${qs}`, { headers: HEADERS });
  const body = await res.json();
  if (!body.success) throw new Error(body.message);
  return body.data;
}

// Danh mục sản phẩm (cache lại, ít thay đổi)
const products = await call({ cmd: 'news_products' });

// Danh sách báo cáo + chi tiết
const list   = await call({ cmd: 'news', cate: 'kim-loai-quy', page: 1, size: 20 });
const detail = await call({ cmd: 'news', id: list[0].id });

PHP

function sfiCall(array $params) {
    $url = 'https://a.sfi.com.vn/ekyc/ex_api?' . http_build_query($params);

    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER     => ['X-Api-Key: ' . getenv('SFI_API_KEY')],
        CURLOPT_TIMEOUT        => 10,
    ]);
    $body = json_decode(curl_exec($ch), true);
    curl_close($ch);

    if (empty($body['success'])) {
        throw new RuntimeException($body['message'] ?? 'SFI API error');
    }
    return $body['data'];
}

$news = sfiCall(['cmd' => 'news', 'cate' => 'phan-tich-chuyen-sau', 'page' => 1, 'size' => 10]);
Thử ngay trên trình duyệt: mỗi endpoint trong trang này có một khối Thử ngay — nhập API Key một lần ở Cấu hình test rồi bấm Gửi yêu cầu. Request phát đi trực tiếp từ trình duyệt của bạn.
⚡ Test ngay trong trang