iClinic Developers

Integration API · v1 · chỉ đọc

Đọc lượt khám của phòng khám chỉ bằng một API key.

Một endpoint, một API key dùng mãi không hết hạn. Đủ để đối chiếu lịch hẹn (Đã đến / Đã huỷ) và lên danh sách gọi chăm sóc sau khám.

Base URL https://iclinic.phongkhamhieploi.vn/api/integration/v1

Thử gọi ngay

Ví dụ
GET /api/integration/v1/encounters
Key chỉ nằm trong trình duyệt này và chỉ gửi tới iclinic.phongkhamhieploi.vn.
Đang hiển thị dữ liệu mẫu. Dán API key của bạn để xem dữ liệu thật.
{
  "requestId": "req_7c1f3a",
  "from": "2026-09-14",
  "to": "2026-09-19",
  "page": 0,
  "pageSize": 200,
  "total": 1,
  "encounters": [
    {
      "id": "BA-000123",
      "encounterUuid": "3f0c9a52-6d1b-4e7a-9b1e-2a4c8d5e7f10",
      "patientName": "Nguyễn Văn A",
      "phone": "0900000001",
      "visitDate": "2026-09-19",
      "checkedInAt": "2026-09-19T02:14:05.000Z",
      "completedAt": null,
      "status": "ONGOING",
      "patientType": "OLD",
      "diagnosis": "Tăng huyết áp",
      "icd10Code": "I10"
    }
  ]
}

Bắt đầu nhanh

Ba bước để có dữ liệu đầu tiên.

  1. Nhờ quản trị viên phòng khám tạo API key

    Vào Quản trị → Kết nối ngoài (API) → Tạo key, đặt một tên gợi nhớ (ví dụ Tele-sale). Key dạng ick_… chỉ hiện đúng một lần — sao chép và lưu vào nơi an toàn ngay lúc đó.

  2. Gọi thử

    Gửi key trong header Authorization: Bearer. Dùng khung “Thử gọi ngay” ở đầu trang, hoặc chạy thẳng lệnh bên cạnh.

  3. Đối chiếu và lưu theo encounterUuid

    Mỗi lượt khám có một encounterUuid cố định, không bao giờ đổi — dùng nó làm khoá chống trùng khi lưu vào hệ thống của bạn.

curl
curl -sS "https://iclinic.phongkhamhieploi.vn/api/integration/v1/encounters?from=2026-09-14&to=2026-09-19&status=all" \
  -H "Authorization: Bearer $ICLINIC_API_KEY"

Xác thực

Mọi yêu cầu cần một API key trong header Authorization, dùng kiểu Bearer. Không cookie, không OAuth — chỉ cần đúng key là đủ.

  • Không tự hết hạn. Key dùng được tới khi quản trị viên thu hồi.
  • Chỉ đọc. Key này không sửa hay xoá được dữ liệu.
  • Theo từng phòng khám. Mỗi key chỉ thấy dữ liệu của phòng khám đã tạo ra nó; tối đa 10 key hoạt động cùng lúc mỗi phòng khám.
  • Chỉ lưu dấu vân tay. iClinic chỉ giữ giá trị băm sha256 của key nên không xem lại được — mất key thì tạo key mới, không khôi phục được key cũ.
Giữ key như mật khẩu. Đặt trong biến môi trường hoặc kho bí mật, đừng đưa vào mã nguồn hay mã chạy ở trình duyệt của khách hàng. Nghi ngờ lộ key: tạo key mới, cập nhật hệ thống của bạn rồi Thu hồi key cũ — có hiệu lực ngay lập tức.

Đổi key không làm gián đoạn dịch vụ

Tạo key mới → cập nhật hệ thống của bạn → thu hồi key cũ. Trong lúc chuyển, cả hai key vẫn hoạt động song song.

Header
Authorization: Bearer ick_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Danh sách lượt khám

GET/api/integration/v1/encounters

Trả về các lượt khám có visitDate trong khoảng [from, to], mới nhất trước.

Mặc định không có lượt khám đã huỷ. Để đánh dấu lịch hẹn “Đã huỷ”, gọi với status=all (mọi trạng thái) hoặc status=CANCELLED.

Tham số truy vấn

Tham sốMô tả
fromstring · datebắt buộc Ngày khám bắt đầu, YYYY-MM-DD, theo giờ phòng khám.
tostring · datetuỳ chọn Ngày khám kết thúc, gồm cả ngày này. Mặc định: hôm nay. Khoảng from–to tối đa 31 ngày.
statusstring · enumtuỳ chọn Bỏ trống: mọi trạng thái trừ CANCELLED. all: tất cả, gồm cả đã huỷ. Hoặc một trong NEW ONGOING FINISHED REOPENED LOCKED CANCELLED. Không phân biệt hoa thường.
pageintegertuỳ chọn Số trang, bắt đầu từ 0. Mặc định 0.
pageSizeintegertuỳ chọn Từ 1 đến 500. Mặc định 200.

Phản hồi 200

Rê chuột hoặc dùng Tab trên một dòng để xem trường đó nằm ở đâu trong JSON.

TrườngÝ nghĩa
requestIdstringMã yêu cầu, trùng header X-Request-Id. Gửi kèm khi cần hỗ trợ.
totalintegerTổng số lượt khám khớp bộ lọc, trên mọi trang.
encountersarrayCác lượt khám của trang hiện tại. Cùng from, to, page, pageSize được trả lại nguyên như đã gửi (sau khi áp mặc định).

Một lượt khám

TrườngÝ nghĩa
encounterUuidstringKhoá chống trùng. Mã ổn định của lượt khám, không bao giờ đổi.
idstringMã hiển thị (mã hồ sơ). Chỉ để tham chiếu; có thể được cấp lại nên đừng dùng làm khoá chống trùng.
patientNamestringTên bệnh nhân.
phonestring | nullSố điện thoại; null nếu phòng khám chưa có số.
visitDatedateNgày khám YYYY-MM-DD theo giờ phòng khám. Hệ thống lưu ngày, không lưu giờ khám.
checkedInAtdate-time | nullThời điểm tiếp nhận (UTC) khi biết được, ngược lại null. Đừng coi null là chưa đến — hãy dựa vào status.
completedAtdate-time | nullThời điểm kết thúc khám (UTC) hoặc null.
statusenum
  • NEW đã đến / tiếp nhận
  • ONGOING đang khám
  • FINISHED đã khám xong
  • REOPENED mở lại
  • LOCKED đã khoá hồ sơ
  • CANCELLED đã huỷ
patientTypeenum
  • NEW khách mới
  • OLD khách cũ
  • RE_EXAMINATION tái khám theo hẹn
diagnosisstringChẩn đoán; chuỗi rỗng nếu chưa có.
icd10CodestringMã ICD-10; chuỗi rỗng nếu chưa có.
curl -sS "https://iclinic.phongkhamhieploi.vn/api/integration/v1/encounters?from=2026-09-14&to=2026-09-19&status=all&page=0&pageSize=200" \
  -H "Authorization: Bearer $ICLINIC_API_KEY"
200 Phản hồi
{
  "requestId": "req_7c1f3a",
  "from": "2026-09-14",
  "to": "2026-09-19",
  "page": 0,
  "pageSize": 200,
  "total": 1,
  "encounters": [
    {
      "id": "BA-000123",
      "encounterUuid": "3f0c9a52-6d1b-4e7a-9b1e-2a4c8d5e7f10",
      "patientName": "Nguyễn Văn A",
      "phone": "0900000001",
      "visitDate": "2026-09-19",
      "checkedInAt": "2026-09-19T02:14:05.000Z",
      "completedAt": null,
      "status": "ONGOING",
      "patientType": "OLD",
      "diagnosis": "Tăng huyết áp",
      "icd10Code": "I10"
    }
  ]
}

Phân trang

Phân trang theo page (từ 0) và pageSize (tối đa 500). Tăng page cho tới khi đã nhận đủ total lượt khám, hoặc gặp một trang rỗng.

Kết quả xếp mới nhất trước. Nếu có lượt khám mới được tạo trong lúc bạn đang duyệt, các trang có thể dịch chuyển — vì vậy hãy khử trùng theo encounterUuid khi gộp kết quả.

Không cần gọi dày. Mỗi 5–15 phút một lần với from là vài ngày gần nhất là đủ cho việc đối chiếu lịch hẹn.
Ví dụ: 2 trang
GET …/encounters?from=2026-09-01&to=2026-09-19&pageSize=200&page=0   → total 340, 200 lượt
GET …/encounters?from=2026-09-01&to=2026-09-19&pageSize=200&page=1   → total 340, 140 lượt  (đủ 340, dừng)

Mã lỗi

Lỗi luôn có dạng { requestId, error: { code, message } }. Xử lý theo code, không theo message — nội dung message dành cho người đọc và có thể được chỉnh lại.

HTTPerror.codeKhi nàoThử lại?
400INVALID_DATEThiếu hoặc sai định dạng from, to.Không — sửa yêu cầu
400INVALID_RANGEto trước from, hoặc khoảng quá 31 ngày.Không — sửa yêu cầu
400INVALID_STATUSstatus không hợp lệ.Không — sửa yêu cầu
400INVALID_PAGEpage hoặc pageSize sai.Không — sửa yêu cầu
401UNAUTHORIZEDThiếu, sai hoặc key đã bị thu hồi; hoặc phòng khám đang bị tạm ngưng.Không — kiểm tra lại key
405METHOD_NOT_ALLOWEDChỉ hỗ trợ GET.Không
429RATE_LIMITEDVượt giới hạn tốc độ hoặc IP đang bị khoá tạm.Có — sau Retry-After
5xx—Lỗi phía máy chủ.Có — chờ tăng dần
400 INVALID_RANGE
{
  "requestId": "req_7c1f3a",
  "error": {
    "code": "INVALID_RANGE",
    "message": "`to` phải sau `from` và khoảng tối đa 31 ngày."
  }
}

Giới hạn tốc độ (rate limit)

60yêu cầu mỗi phút, tính theo từng key
5lần gửi sai key trong 10 phút, từ cùng một IP
15′IP bị khoá tạm thời, dù sau đó gửi đúng key

Cả hai giới hạn trả về 429 RATE_LIMITED kèm header Retry-After (số giây). Hãy chờ đúng khoảng đó rồi thử lại, đừng gọi lặp liên tục.

Đừng để hệ thống tự thử lại khi gửi sai key. Một vòng lặp gửi sai key sẽ khoá IP của bạn 15 phút. Khi gặp 401, dừng lại và báo cho người phụ trách kiểm tra key.
Node.js · chờ theo Retry-After
async function callWithRetry(url, options, attempts = 4) {
  for (let i = 0; i < attempts; i += 1) {
    const res = await fetch(url, options);
    if (res.status === 429) {
      const seconds = Number(res.headers.get('Retry-After')) || 30;
      await new Promise((r) => setTimeout(r, seconds * 1000));
      continue;
    }
    if (res.status >= 500) {
      await new Promise((r) => setTimeout(r, 2 ** i * 1000));
      continue;
    }
    return res; // 2xx, 4xx: không thử lại
  }
  throw new Error('Hết số lần thử');
}

Công thức

Đánh dấu lịch hẹn “Đã đến” / “Đã huỷ”

  1. Lấy lượt khám gần đây với status=all để có cả lượt đã huỷ.
  2. Ghép theo số điện thoại và visitDate trong vòng ±5 ngày so với ngày hẹn. Bỏ qua lượt khám có phone = null.
  3. Có ít nhất một lượt không phải CANCELLED → Đã đến. Chỉ có lượt CANCELLED → Đã huỷ. Không có lượt nào → giữ nguyên.

Danh sách gọi chăm sóc sau khám (ngày 0 / 3 / 6 / 30)

  1. Lấy status=FINISHED với from = hôm nay − 30 ngày (đúng 31 ngày, đủ cho mốc ngày 30).
  2. Tính ngày gọi = visitDate + 0, 3, 6, 30 ngày; lấy các lượt có ngày gọi trùng hôm nay.
  3. Hiển thị patientName, phone, diagnosis. patientType = NEW là khách mới; OLD và RE_EXAMINATION là tái khám.
const DAY = 86_400_000;
const dayOf = (date) => Date.parse(`${date}T00:00:00Z`);

// appointment: { phone, date: 'YYYY-MM-DD' }; encounters: từ status=all
export function appointmentOutcome(appointment, encounters) {
  const near = encounters.filter(
    (e) =>
      e.phone &&
      e.phone === appointment.phone &&
      Math.abs(dayOf(e.visitDate) - dayOf(appointment.date)) <= 5 * DAY,
  );
  if (near.length === 0) return null; // giữ nguyên
  return near.some((e) => e.status !== 'CANCELLED') ? 'Đã đến' : 'Đã huỷ';
}

Ghi chú dữ liệu

  • Ngày, không phải giờ. visitDate là ngày khám theo giờ phòng khám (UTC+7). Mọi thời điểm dạng date-time là UTC.
  • checkedInAt có thể là null. Nó chỉ có khi ngày tiếp nhận trùng visitDate; với hồ sơ nhập ngược ngày thì không có giờ đến thật. Dùng status để biết đã đến hay chưa.
  • Hồ sơ chuyển từ Medi (2026-09-19). Có visitDate đúng ngày khám gốc nhưng không có giờ tiếp nhận thật. Với các ca ngày 2026-09-19 được nhập trong ngày, checkedInAt chỉ là thời điểm nhập — đừng dùng làm giờ đến khám.
  • Không có số điện thoại. Một số bệnh nhân không có SĐT → phone là null.
  • Trường mới không phá vỡ. Hãy bỏ qua các trường bạn chưa biết khi đọc phản hồi.

Phiên bản & thay đổi

Phiên bản nằm trong đường dẫn (/v1). Trong cùng một phiên bản, thay đổi chỉ theo hướng bổ sung: thêm trường trong phản hồi, thêm giá trị enum hoặc tham số tuỳ chọn. Thay đổi làm hỏng tương thích sẽ ra phiên bản mới (/v2).

Vì vậy client nên: bỏ qua trường lạ, và không giả định danh sách giá trị của status là cố định.

Nhật ký thay đổi

1.0.0
Phát hành đầu tiên: GET /encounters xác thực bằng API key cố định, có phân trang và rate limit. Thay thế cho API lượt khám của Medi (đã ngừng hoạt động).
OpenAPI 3.1Tải xuống
https://iclinic.phongkhamhieploi.vn/developers/openapi.json

# Nhập vào Postman, Insomnia hoặc trình sinh mã:
npx @openapitools/openapi-generator-cli generate \
  -i https://iclinic.phongkhamhieploi.vn/developers/openapi.json \
  -g typescript-fetch -o ./iclinic-client

Hỗ trợ

Khi cần hỗ trợ, hãy gửi kèm requestId của yêu cầu lỗi (có trong thân phản hồi và header X-Request-Id), thời điểm gọi và tham số bạn đã dùng. Đừng gửi kèm API key — nếu lỡ gửi, hãy thu hồi key đó ngay.

Liên hệ iClinic →