AI Health Clinic API

診所資訊系統串接說明

Clinic API 是提供診所或醫療機構資訊系統讀取已授權檢測紀錄的 read-only API。診所端可透過 API key 取得病患授權清單、檢測紀錄、JSON 或 FHIR 格式資料,並用增量同步維持本地系統更新。

Base URL:https://ai.winefont.net
傳輸:HTTPS only

查看快速串接流程 查看 API Endpoint

v1 支援能力

  • API key 驗證
  • 授權病患清單
  • 檢測紀錄讀取
  • JSON / FHIR response
  • 分頁與增量同步
  • 撤銷授權 reconciliation

快速串接流程

建議診所資訊系統依下列流程串接。第一次同步先取得授權病患與最近 90 天紀錄,之後改用 updatedSince 做增量同步。

1. 取得 API key

由萬灃提供診所專用 API key。API key 只可放在診所資訊系統後端。

2. 讀取授權清單

呼叫 /authorized-patients 取得可同步的 patientHandle

3. 同步檢測紀錄

對每個 patientHandle 呼叫 /records,使用 recordId 做本地 upsert。

4. 增量更新

後續以 updatedSince=<last_success_time> 取得新增、修正、審閱或退回的紀錄。

認證方式

每次 request 需帶入 Authorization header。建議診所資訊系統也提供 X-Request-Id,方便雙方排查請求。

Authorization: Bearer <API_KEY>
X-Request-Id: <your-request-id>

注意:API key 不應放在前端 JavaScript、App、Git repo 或公開 log。

PowerShell 基本範例

$BASE = "https://ai.winefont.net"
$KEY = "<API_KEY>"
$headers = @{
  Authorization = "Bearer $KEY"
  "X-Request-Id" = "clinic-sync-001"
}

API Endpoints

Clinic API v1 主要提供三個 endpoint。所有 endpoint 都是 read-only。

取得目前授權給診所的病患清單。建議第一次同步與每日 reconciliation 使用。

GET /api/clinic/v1/authorized-patients?limit=100

可選參數:

參數說明
limit每頁筆數,1 到 100。
cursor上一頁 response 的 page.nextCursor
includeRevoked是否包含已撤銷授權的病患。
revokedSince只查指定時間後撤銷的授權。

Response 範例

{
  "data": [
    {
      "patientHandle": "pt_exampleHandleABCDEFGH",
      "patientId": null,
      "authorizedScopes": {
        "vitals": true,
        "reports": true,
        "history": true
      },
      "grantId": "grant_example",
      "status": "active"
    }
  ],
  "page": {
    "limit": 100,
    "nextCursor": null
  },
  "requestId": "clinic-sync-001"
}

patientHandle 或診所端病歷號 patientId 讀取檢測紀錄。建議優先使用 patientHandle

GET /api/clinic/v1/records?patientHandle=pt_exampleHandleABCDEFGH&limit=100

常用參數:

參數預設說明
patientHandle建議使用的不透明病患 handle。
patientId診所端病歷號。若授權範圍內無法唯一對應,會回 404。
formatjsonjsonfhir
since最近 90 天檢測時間下限。
until現在檢測時間上限。
updatedSinceupdatedAt 下限,用於增量同步。不可與 sinceuntil 混用。
includeRejectedfalse是否包含退回紀錄。
includePatientNamefalse是否回傳病患姓名;若授權範圍不包含基本資料,會回 null

若診所系統已保存 recordId,可直接回查單筆紀錄。

GET /api/clinic/v1/records/sample-record-001?format=json

紀錄不存在、病患未授權,或紀錄不屬於該診所授權範圍時,都會回 404 not_found。請不要用 404 結果推測紀錄或病患是否存在。

分頁與同步模式

timestamp mode

沒有帶 updatedSince 時使用 timestamp mode。適合第一次同步或查特定檢測日期範圍。

GET /api/clinic/v1/records?patientHandle=pt_example&since=2026-05-01T00:00:00.000Z&until=2026-05-24T00:00:00.000Z

updated mode

updatedSince 時使用 updated mode。適合每日或每小時增量同步,也能抓到舊紀錄在今天被審閱、退回或修正的變更。

GET /api/clinic/v1/records?patientHandle=pt_example&updatedSince=2026-05-23T00:00:00.000Z

PowerShell 分頁範例

$cursor = $null
do {
  $uri = "$BASE/api/clinic/v1/records?patientHandle=$handle&limit=100"
  if ($cursor) {
    $encodedCursor = [uri]::EscapeDataString($cursor)
    $uri = "$uri&cursor=$encodedCursor"
  }

  $page = Invoke-RestMethod -Headers $headers -Uri $uri
  foreach ($record in $page.data) {
    # Upsert into clinic system by $record.recordId
  }
  $cursor = $page.page.nextCursor
} while ($cursor)

Cursor 是 opaque 值,請不要解析或修改。

Response 格式

預設為 JSON。若診所資訊系統支援 FHIR,可指定 format=fhir

{
  "data": [
    {
      "recordId": "sample-record-001",
      "patientId": "TEST-001",
      "patientName": null,
      "deviceType": "urine_analysis",
      "scopeCategory": "reports",
      "timestamp": "2026-05-19T17:19:00.000Z",
      "updatedAt": "2026-05-22T02:54:12.835Z",
      "measurements": [
        { "name": "SG", "value": "1.020", "unit": "" },
        { "name": "pH", "value": "6", "unit": "" },
        { "name": "LEU", "value": "neg", "unit": "" }
      ],
      "reviewStatus": "pending",
      "reviewedAt": null,
      "hisSentStatus": "not_sent",
      "isRejected": false
    }
  ],
  "page": {
    "limit": 100,
    "nextCursor": null
  },
  "requestId": "clinic-sync-001"
}
欄位說明
recordId檢測紀錄唯一鍵。診所系統本地建議用它 upsert。
patientId診所端病歷號;若紀錄沒有病歷號,可能 fallback 為 patientHandle
patientName預設 null。只有指定 includePatientName=true 且授權包含基本資料時才會回傳姓名。
deviceType儀器/資料類型,例如 urine_analysisblood_pressure_monitor
scopeCategory資料分類:vitalsreportshistory
timestamp檢測時間,UTC ISO string。
updatedAt紀錄最後更新時間,UTC ISO string。增量同步請用 updatedSince 對應此欄位。
measurements檢測項目陣列。請用 namevalueunit 解析。
reviewStatus審閱狀態:pendingreviewedrejected
hisSentStatusHIS 傳送狀態。若只使用 Clinic API pull 串接,通常可忽略。
reviewStatusFHIR status意義診所系統建議
pendingpreliminary病患/AI 提交,但醫護尚未確認。顯示為未審閱或暫定資料,不應當作 final 數值。
reviewedfinal醫護已確認。可視為已確認檢測紀錄。
rejectedentered-in-error醫護判定無效或不採用。不應作為臨床判斷依據;建議標記 inactive 並保留處理紀錄。

臨床安全提醒:pending 資料尚未完成醫護確認,診所系統若要顯示給臨床人員,應明確標示為未審閱/暫定資料。

{
  "resourceType": "Bundle",
  "type": "searchset",
  "total": 1,
  "entry": [
    {
      "resource": {
        "resourceType": "Observation",
        "id": "sample-record-001",
        "status": "preliminary",
        "category": [
          {
            "coding": [
              {
                "system": "http://terminology.hl7.org/CodeSystem/observation-category",
                "code": "laboratory",
                "display": "Laboratory"
              }
            ]
          }
        ],
        "code": {
          "coding": [
            {
              "system": "http://loinc.org",
              "code": "24356-8",
              "display": "Urinalysis complete panel"
            }
          ],
          "text": "Urinalysis complete panel"
        },
        "subject": {
          "identifier": {
            "system": "https://ai.winefont.net/fhir/identifier/patient-id",
            "value": "TEST-001"
          }
        },
        "effectiveDateTime": "2026-05-19T17:19:00.000Z",
        "component": [
          {
            "code": { "text": "Specific gravity of Urine by Test strip" },
            "valueQuantity": { "value": 1.02, "unit": "" }
          }
        ]
      }
    }
  ]
}

血壓等生命徵象資料會使用 vital-signs category。一般檢驗報告多為 laboratory category。

常見檢測項目範例

實際欄位會依儀器與 AI OCR 結果略有不同,診所系統請以 response 的 measurements[] 為準。

deviceType儀器/資料類型FHIR category
metabolic_healthRoche cobas b101:HbA1c、血脂等laboratory
urine_analysisRoche Urisys 1100:尿液分析laboratory
coagulation_factorsRoche CoaguChek:凝血數值laboratory
blood_pressure_monitor血壓機vital-signs
blood_glucose_meter血糖機vital-signs
full_report完整報告或多項目檢驗報告laboratory
blood_gasRadiometer ABL9:血液氣體laboratory
hemoglobinHemoCue Hb201:血紅素laboratory
{
  "deviceType": "metabolic_health",
  "scopeCategory": "reports",
  "measurements": [
    { "name": "HbA1c", "value": "6.5", "unit": "%" },
    { "name": "TC", "value": "180", "unit": "mg/dL" },
    { "name": "HDL", "value": "52", "unit": "mg/dL" },
    { "name": "LDL", "value": "105", "unit": "mg/dL" },
    { "name": "TG", "value": "120", "unit": "mg/dL" }
  ]
}
{
  "deviceType": "urine_analysis",
  "scopeCategory": "reports",
  "measurements": [
    { "name": "SG", "value": "1.020", "unit": "" },
    { "name": "pH", "value": "6", "unit": "" },
    { "name": "LEU", "value": "neg", "unit": "" },
    { "name": "NIT", "value": "neg", "unit": "" },
    { "name": "PRO", "value": "neg", "unit": "" },
    { "name": "GLU", "value": "norm", "unit": "" },
    { "name": "KET", "value": "neg", "unit": "" },
    { "name": "UBG", "value": "norm", "unit": "" },
    { "name": "BIL", "value": "neg", "unit": "" },
    { "name": "ERY", "value": "neg", "unit": "" }
  ]
}
{
  "deviceType": "coagulation_factors",
  "scopeCategory": "reports",
  "measurements": [
    { "name": "PT", "value": "12.4", "unit": "sec" },
    { "name": "INR", "value": "1.1", "unit": "" },
    { "name": "aPTT", "value": "31", "unit": "sec" }
  ]
}
{
  "deviceType": "blood_pressure_monitor",
  "scopeCategory": "vitals",
  "measurements": [
    { "name": "SYS", "value": "120", "unit": "mmHg" },
    { "name": "DIA", "value": "80", "unit": "mmHg" },
    { "name": "Pulse", "value": "72", "unit": "bpm" }
  ]
}

FHIR category 會是 vital-signs

{
  "deviceType": "blood_glucose_meter",
  "scopeCategory": "vitals",
  "measurements": [
    { "name": "BG", "value": "110", "unit": "mg/dL" }
  ]
}

full_report 用於完整檢驗報告或多項目報告。v1 API 只回傳結構化數值,不回傳報告圖片或檔案下載連結。

{
  "deviceType": "full_report",
  "scopeCategory": "reports",
  "measurements": [
    { "name": "WBC", "value": "6.2", "unit": "10^3/uL" },
    { "name": "RBC", "value": "4.8", "unit": "10^6/uL" },
    { "name": "Hb", "value": "14.1", "unit": "g/dL" },
    { "name": "PLT", "value": "220", "unit": "10^3/uL" }
  ]
}

錯誤處理

HTTPerror建議處理
400invalid_request參數錯誤。修正 request,不要原樣重試。
401unauthorizedAPI key 缺失、錯誤、過期、被撤銷或功能未啟用。請聯絡萬灃。
404not_foundpatient/record 不存在或不在授權範圍。不要用這個結果推測病患是否存在。
429rate_limited達到速率限制。依 Retry-After 秒數後重試。
500server_error暫時性伺服器錯誤。可用 exponential backoff 重試並保留 X-Request-Id

錯誤 response 範例

{
  "error": "invalid_request",
  "requestId": "clinic-sync-001"
}

Rate limit

  • 每組 API key:60 requests / minute。
  • 每家診所:200 requests / minute。
  • 每次最多回傳 100 筆 records。

若回 429,請讀取 Retry-After header 後再重試。

HTTP/1.1 429 Too Many Requests
Retry-After: 60
Content-Type: application/json

安全注意事項

  • API key 只可放在診所資訊系統後端。
  • 不要把 API key 寫入前端、App、Git repo 或公開 log。
  • 不要把 Authorization header 寫入 application log。
  • 建議每家診所使用獨立 API key。
  • 建議診所系統保留 requestIdrecordId、同步時間與 HTTP status 以便對帳。

v1 限制

  • 不回傳圖片、OCR 原檔或檔案下載連結。
  • 不提供 webhook / push。診所系統需自行 polling。
  • 不支援外部系統寫回、修改、刪除、審閱、退回、送 HIS 或 unsend HIS。
  • 查詢病患請使用 API 回傳的 patientHandle,或使用診所端病歷號 patientId
  • FHIR v1 以 LOINC 為主;部分檢測項目可能使用較通用的 panel/code 或文字欄位。
  • 不保證 patientId 永久不變。診所端主鍵請使用 recordId

需要協助串接?

若串接過程出現錯誤,請提供以下資訊給萬灃窗口:

  • API endpoint
  • X-Request-Id
  • HTTP status code
  • response body 裡的 error
  • request 時間

請不要傳送 API key 原文。