SFI External API — Hồ sơ chuyên gia

Hồ sơ giới thiệu của nhân sự SFI dành 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.

Không có API đăng ký chuyên gia, data chuyên gia sẽ được SFI thiết lập riêng. Các API dưới đây chỉ đọc.
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), chỉ rút gọn phần nội dung dài.

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
2 · Hồ sơ chuyên gia GET ?cmd=expert_profile_fields Bảng nhãn khoá động, dùng chung cho mọi hồ sơ — gọi một lần rồi cache X-Api-Key
2 · Hồ sơ chuyên gia GET ?cmd=expert_profiles Danh sách chuyên gia (nhân sự SFI), có phân trang và sắp xếp X-Api-Key
2 · Hồ sơ chuyên gia GET ?cmd=expert_profile&id=… Chi tiết hồ sơ một chuyên gia theo mã nhân sự X-Api-Key

Danh mục này là nguồn tra cứu nhanh của nhóm Hồ sơ chuyên gia — 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.

Hồ sơ chuyên gia

Hồ sơ giới thiệu của nhân sự SFI (môi giới, cộng tác viên, đại lý, nhân sự đối tác) — ảnh, chức danh, giới thiệu, triết lý đầu tư, dịch vụ cung cấp, thông tin nổi bật và hồ sơ kinh nghiệm. Nhân sự tự điền trên cổng AMG, bộ phận CSKH của SFI duyệt trước khi công khai.

Chỉ hồ sơ đã duyệt và đang hiển thị: API chỉ trả hồ sơ đã được CSKH duyệt, không bị ẩn, của nhân sự đang hoạt động. Bản nhân sự vừa gửi và đang chờ duyệt không bao giờ xuất hiện ở đây. Vì vậy danh sách có thể thay đổi giữa hai lần gọi khi SFI duyệt thêm hoặc ẩn bớt hồ sơ.

1 · Bảng nhãn khoá động

GET X-API-KEY

?cmd=expert_profile_fields

Hai nhóm highlights / experience trong hồ sơ dùng khoá động do SFI khai: khoá có thể được thêm, đổi nhãn hoặc ẩn bất cứ lúc nào. Bảng nhãn này giống nhau cho mọi hồ sơ nên nằm ở endpoint riêng — gọi một lần, cache lại, rồi dùng cho toàn bộ danh sách và chi tiết. Hai API hồ sơ ở dưới chỉ trả value, không lặp lại bảng nhãn.

Request

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

Response

{
  "success": true,
  "message": "Thành công!",
  "data": {
    "HIGHLIGHT": [
      { "key": "years_experience", "label": "Số năm kinh nghiệm", "icon": "briefcase", "inputType": "TEXT" },
      { "key": "clients_served",   "label": "Số nhà đầu tư đồng hành", "icon": "users", "inputType": "TEXT" }
    ],
    "EXPERIENCE": [
      { "key": "aum",    "label": "Tổng tài sản đang quản lý", "icon": "", "inputType": "TEXT" },
      { "key": "awards", "label": "Vinh danh - Giải thưởng",   "icon": "", "inputType": "MULTILINE" }
    ]
  },
  "svr": "srv-01"
}
TrườngKiểuMô tả
HIGHLIGHTarrayNhóm Thông tin nổi bật — các ô số lớn
EXPERIENCEarrayNhóm Hồ sơ kinh nghiệm
[].keystringKhoá tra value trong highlights / experience của hồ sơ
[].labelstringNhãn hiển thị
[].iconstringMã icon Lucide kebab-case. Chỉ nhóm HIGHLIGHT có, nhóm còn lại thường rỗng
[].inputTypestringMULTILINE → value là array<string>; TEXT / TEXTAREA / NUMBER → value là string
Cách dùng đúng: lặp theo mảng của từng nhóm rồi tra key trong hồ sơ — đừng hardcode danh sách khoá. Thứ tự mảng chính là thứ tự hiển thị SFI mong muốn, không cần sắp lại. Danh sách chỉ gồm khoá đang bật; số lượng và thứ tự có thể đổi giữa hai lần gọi, nên nếu cache thì đặt TTL (ví dụ 1 giờ) thay vì cache vĩnh viễn. Khoá SFI đang ẩn và khoá nhân sự chưa điền không xuất hiện trong hồ sơ trả ra.

Thử ngay — ?cmd=expert_profile_fields

Không có tham số.

chưa gọi

2 · Danh sách chuyên gia

GET X-API-KEY

?cmd=expert_profiles

Trả về danh sách chuyên gia theo trang, kèm toàn bộ nội dung hồ sơ của từng người — không cần gọi thêm API chi tiết để dựng danh sách hay trang giới thiệu.

Tham số truy vấn

Tham sốKiểuBắt buộcMặc địnhMô tả
qstringKhông (rỗng) Tìm theo tên hoặc số điện thoại nhân sự (khớp một trong hai, chứa chuỗi).
Tên: không phân biệt hoa thường và không phân biệt dấu — nguyen van khớp Nguyễn Văn.
SĐT: chỉ dò khi q chỉ gồm chữ số (cho phép khoảng trắng, + . - ( )) và có ≥ 3 chữ số; ký tự phân cách bị bỏ qua, đầu +84 được quy về 0.
Tối đa 100 ký tự, dài hơn: lỗi success: false. Lọc trước khi sắp xếp/phân trang, nên paging.total là tổng số kết quả tìm được.
pageintKhông 1 Trang, bắt đầu từ 1. Giá trị < 1 được đưa về 1.
sizeintKhông 20 Số bản ghi mỗi trang, tối đa 100. Giá trị lớn hơn bị giới hạn về 100.
sortstringKhông volume volume — khối lượng giao dịch lớn nhất
clients — nhiều khách hàng nhất
Giá trị khác: lỗi success: false. Xem Sắp xếp theo số liệu tháng.
orderstringKhông desc desc (cao → thấp) hoặc asc. Giá trị khác được coi là desc.
Phân trang: khác nhóm 1, API này trả về data.paging có total và totalPages nên đối tác biết trước tổng số bản ghi. Khi bằng điểm sắp xếp, thứ tự được chốt theo tên rồi mã nhân sự — nhờ vậy phân trang không bị lặp hoặc mất bản ghi.

Request

# Trang 1, 20 chuyên gia, khối lượng giao dịch lớn nhất trước
curl 'https://a.sfi.com.vn/ekyc/ex_api?cmd=expert_profiles&page=1&size=20&sort=volume' \
  -H 'X-Api-Key: YOUR_API_KEY'

# Nhiều khách hàng nhất
curl 'https://a.sfi.com.vn/ekyc/ex_api?cmd=expert_profiles&sort=clients' \
  -H 'X-Api-Key: YOUR_API_KEY'

# Tìm theo tên (không dấu) hoặc số điện thoại — nhớ URL-encode q
curl 'https://a.sfi.com.vn/ekyc/ex_api?cmd=expert_profiles&q=nguyen%20van' \
  -H 'X-Api-Key: YOUR_API_KEY'
curl 'https://a.sfi.com.vn/ekyc/ex_api?cmd=expert_profiles&q=0901234' \
  -H 'X-Api-Key: YOUR_API_KEY'

Response

{
  "success": true,
  "message": "Thành công!",
  "data": {
    "items": [
      {
        "id": "MG0123",
        "name": "Nguyễn Văn An",
        "phone": "0901234567",
        "branch": "Chi nhánh Hồ Chí Minh",
        "avatar": "https://img.saigonfutures.com/uploads/ab12-portrait.jpg",
        "age": 32,
        "jobTitle": "Chuyên viên tư vấn đầu tư hàng hóa cấp cao",
        "intro": "Xin chào Quý Nhà đầu tư,\n\nTôi là…",
        "philosophy": "Kỷ luật - Quản trị rủi ro - Tăng trưởng bền vững",
        "styles": [
          { "icon": "shield-check", "title": "Kỷ luật", "subtitle": "Đặt nguyên tắc lên hàng đầu" }
        ],
        "services": [
          "Xây dựng kế hoạch đầu tư phù hợp với mục tiêu và khẩu vị rủi ro của khách hàng."
        ],
        "highlights":   { "years_experience": "8+", "clients_served": "650+" },
        "experience":   { "aum": "Đến 100 tỷ", "awards": ["Top 1 - Bảng vàng 2025"] },
        "stats": { "month": "08-2026", "volume": 1284, "clients": 37 },
        "publishedAt": "2026-08-12 14:05:22"
      }
    ],
    "paging": { "page": 1, "size": 20, "total": 57, "totalPages": 3 },
    "q": "",
    "sort": "volume",
    "order": "desc",
    "statsMonth": "08-2026"
  },
  "svr": "srv-01"
}
Nhãn của hai nhóm highlights / experience không nằm ở đây — lấy từ cmd=expert_profile_fields (mục 2.1) và cache lại, vì bảng nhãn dùng chung cho mọi hồ sơ.

Thử ngay — ?cmd=expert_profiles

chưa gọi

3 · Chi tiết một chuyên gia

GET X-API-KEY

?cmd=expert_profile&id={mã nhân sự}

Trả về hồ sơ của đúng một chuyên gia. Nội dung giống hoàn toàn một phần tử trong items của API danh sách (mục 2.2) — API này chỉ tiện khi đối tác đã có mã nhân sự (ví dụ mã môi giới phụ trách một khách hàng) và không muốn tải cả danh sách.

Tham số truy vấn

Tham sốKiểuBắt buộcMô tả
idstringCó Mã nhân sự, đúng giá trị id ở API danh sách. Phải là mã chính — mã phụ không có hồ sơ riêng.

Request

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

Response

{
  "success": true,
  "message": "Thành công!",
  "data": {
    "expert": { "...": "cùng cấu trúc với một phần tử items ở mục 2.2" },
    "statsMonth": "08-2026"
  },
  "svr": "srv-01"
}

Thử ngay — ?cmd=expert_profile

chưa gọi

4 · Sắp xếp theo số liệu tháng

Hai tiêu chí sắp xếp đều là số liệu giao dịch của tháng hiện tại (tháng ghi ở statsMonth, định dạng MM-YYYY), tính lại ở mỗi lần gọi:

sortÝ nghĩaTrường tương ứng
volume Khối lượng giao dịch lớn nhất — tổng số lot của mọi giao dịch gắn mã nhân sự trong tháng stats.volume
clients Nhiều khách hàng nhất — số tài khoản giao dịch khác nhau gắn mã nhân sự trong tháng stats.clients
Lưu ý khi hiển thị số liệu:
  • Số liệu chỉ tính tháng hiện tại, không phải luỹ kế — đầu tháng gần như mọi chuyên gia sẽ về 0.
  • Nhân sự chưa có giao dịch trong tháng vẫn xuất hiện trong danh sách với volume = 0, clients = 0. API không loại họ ra.
  • Một nhân sự có thể có nhiều mã (mã phụ, mã cũ); SFI đã gộp hết về mã chính, và một khách hàng giao dịch dưới hai mã của cùng nhân sự chỉ được tính một lần trong clients.
  • Con số phản ánh hoạt động kinh doanh nội bộ của SFI. Nếu dùng để xếp hạng công khai, đối tác nên thống nhất trước với SFI về cách diễn giải.

5 · Trường dữ liệu chuyên gia

TrườngKiểuMô tả
idstringMã nhân sự (dùng cho API chi tiết)
namestringHọ tên
phonestringSố điện thoại liên hệ
branchstringChi nhánh
avatarstring (URL)Ảnh đại diện, URL đầy đủ và không hết hạn. Rỗng nếu chưa có ảnh
ageint / nullTuổi. SFI không trả ngày sinh; null khi nhân sự chưa điền
jobTitlestringChức danh nghề nghiệp
introstringGiới thiệu bản thân, nhiều dòng (\n), thuần văn bản — không phải HTML
philosophystringTriết lý đầu tư, một dòng ngắn
stylesarrayTriết lý & phong cách, tối đa 4 mục: icon, title, subtitle
styles[].iconstringMã icon Lucide dạng kebab-case, ví dụ shield-check. Không phải emoji, không phải URL ảnh
servicesarray<string>Dịch vụ cung cấp, tối đa 10 dòng
highlightsobjectThông tin nổi bật — khoá động, tra nhãn ở HIGHLIGHT của mục 2.1
experienceobjectHồ sơ kinh nghiệm — khoá động, tra nhãn ở EXPERIENCE của mục 2.1
stats.monthstring MM-YYYYTháng của số liệu giao dịch
stats.volumeintTổng số lot trong tháng
stats.clientsintSố tài khoản giao dịch khác nhau trong tháng
publishedAtstring Y-m-d H:i:sLần hồ sơ chính thức thay đổi gần nhất — dùng để cache
Giá trị của khoá động là string, riêng khoá có inputType: "MULTILINE" (ví dụ Vinh danh - Giải thưởng) là array<string>. Luôn kiểm kiểu theo inputType ở mục 2.1 thay vì giả định.

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

HTTPmessageNguyên nhân
404Không tìm thấy hồ sơ chuyên gia của mã nhân sự này.Mã không tồn tại, là mã phụ, nhân sự đã ngừng hoạt động, hoặc hồ sơ chưa duyệt / đang bị ẩn
200Thiếu tham số id (mã nhân sự).Gọi cmd=expert_profile mà không truyền id
200Tham số sort không hợp lệ, chỉ nhận: volume, clientssort ngoài hai giá trị cho phép

Khuyến nghị 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;
}

// Bảng nhãn khoá động — gọi một lần rồi cache
const fields = await call({ cmd: 'expert_profile_fields' });

// Danh sách + chi tiết hồ sơ
const experts = await call({ cmd: 'expert_profiles', page: 1, size: 20, sort: 'volume', order: 'desc' });
const profile = await call({ cmd: 'expert_profile', id: experts.items[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'];
}

$experts = sfiCall(['cmd' => 'expert_profiles', 'page' => 1, 'size' => 20, 'sort' => 'volume']);
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