Sentinel API v1

從第一個 API 呼叫到正式環境

五分鐘快速開始

從乾淨節點到第一則圖片事件

這條黃金路徑不需要攝影機或雲端帳號。先使用 deterministic mock provider 驗證 API key、持久化資源、JPEG、Event、Webhook 簽章與證據下載,再換成真實 RTSP 與模型。

會收到什麼?事件輸出與欄位

Watch 會以 HTTP POST 將事件 JSON 送到你設定的 Webhook URL。以下是異常事件的精簡範例(只列常用欄位,ID、時間與內容為示意)。

{
  "id": "evt_example",
  "schema": "sentinel.event.v1",
  "type": "monitor.alert.raised",
  "severity": "critical",
  "state": "raised",
  "created_at": "2026-09-07T12:00:00Z",
  "source_id": "src_camera03",
  "monitor_id": "mon_restricted_area",
  "title": "有人進入管制區域",
  "summary": "攝影機 03 偵測到有人進入指定區域。",
  "evidence": {
    "image_url": "/v1/events/evt_example/image"
  }
}
欄位用途
id事件 ID。同一事件的狀態更新可沿用此 ID。
type發生什麼事,例如 monitor.alert.raised(監看告警)。
severity嚴重程度:safe、suspicious、critical。
state事件狀態:raised(發生)、updated(更新)、cleared(解除)。
created_at事件建立時間(ISO 8601)。
source_id / monitor_id對應的攝影機來源與監看任務;部分系統事件可為 null。
title / summary提供人閱讀的標題與說明,不要用文字解析來判斷告警。
evidence.image_url事件圖片位置;可能無圖片。下載需 events:read API key。

常見事件:monitor.alert.raised(告警發生)、monitor.alert.updated(告警更新)、monitor.alert.cleared(告警解除)、source.disconnected(攝影機斷線)、inference.failed(推論失敗)。實際接收哪些事件,由 Webhook 篩選設定決定;只勾 critical 與 raised 時,不會收到所有更新或解除通知。

接收端先驗證簽章、保存事件,再回覆 2xx。重送請依 HTTP header 的 X-Sentinel-Delivery-ID 去重,不要只用事件 id。Webhook 不會逐筆傳送普通推論。

完整事件格式 · 簽章與接收方式

5–10 min

本機 wiring 驗證

0

不需要攝影機

1 command

節點保持運行

Docker 是這套自架 API 與封裝模型推理路徑的必要條件,不是選配。若尚未安裝,請先完成下方對應作業系統的官方安裝並啟動 Linux-container engine;一鍵 Quickstart 不會替你變更虛擬化或安裝 Docker。

0. 取得 Source Kit

以下指令要從 Sentinel Monitor Source Kit 的 checkout 執行。目前尚未發布可匿名下載的映像或公開原始碼;評估套件會包含 Runtime、Compose、範例與這份文件。

你不需要把 API key 再貼回 Sentinel。Quickstart 會在 deploy/api/.env 產生本機 bootstrap API key,並自行用它完成第一則 Event。只有當 Postman、你的後端或第三方整合要呼叫 /v1 時,才從該 server 的 .env/secret manager 取得 key,放在 Authorization: Bearer header。它不能用來登入網站或啟用桌面 App。
申請評估套件 後再繼續;這可避免把不存在或未授權的下載步驟當成可用產品。

執行前:安裝並啟動必要工具

Docker 提供隔離的 API Runtime、mock provider 與持久化 volumes;Quickstart 不會啟動選用 UI。macOS/Linux 路徑另外需要 curl 與 Python 3,因為腳本會做 readiness、第一則 Event 與證據雜湊驗證。

docker version
docker compose version
docker info --format '{{.OSType}}'
curl --version
python3 --version
docker version 必須同時顯示 Client 與 Server,OSType 必須是 linux,Compose 必須是 v2。若任一指令失敗,先完成對應官方安裝、non-root/rootless 設定或啟動 Docker Engine;不要以 root 執行 Quickstart 或關閉安全功能來掩蓋錯誤。

一個指令,取得第一則事件

macOS、Linux 或 Ubuntu/WSL

./deploy/api/quickstart.sh

Windows PowerShell

powershell.exe -NoProfile -ExecutionPolicy Bypass -File .\deploy\api\quickstart.ps1

在 Source Kit 根目錄執行其中一條指令。Quickstart 會自行找到部署檔案、在需要時建立私密金鑰、啟動 API-only Runtime 與 deterministic mock provider、等待 readiness、執行完整的第一則 Event 範例,最後保留節點運行。它們不會啟動選用 UI。Windows 的 ExecutionPolicy 只套用到該驗證過 kit 的子程序,不會變更使用者或機器政策。

先完成 Windows 11 首次安裝 並核對 kit 的 SHA-256/revision;企業 Group Policy 封鎖時請停止並找管理員核准。

進階:手動走一次相同路徑

1. 啟動 API-only Runtime

cd Sentinel-Monitor/deploy/api
# If .env already exists, keep it; bootstrap refuses to overwrite secrets.
./bootstrap.sh mock
docker compose up -d --build

export SENTINEL_API_KEY="$(python3 ../../docs/api/examples/read_dotenv.py   .env SENTINEL_API_KEY)"
export SENTINEL_BASE_URL=http://localhost:8000

curl --fail "$SENTINEL_BASE_URL/readyz"
curl --fail "$SENTINEL_BASE_URL/v1/system" \
  -H "Authorization: Bearer $SENTINEL_API_KEY"
如果已經跑過 bootstrap.sh,跳過該行;它刻意不覆寫既有 .env。read_dotenv.py 只把 .env 當資料讀取;絕對不要 source Compose dotenv。預設 API 只綁定 127.0.0.1,且預設 Compose 沒有 UI。

2. 建立測試 Source

SOURCE_JSON="$(curl --fail -X POST "$SENTINEL_BASE_URL/v1/sources" \
  -H "Authorization: Bearer $SENTINEL_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: quickstart-source-1" \
  -d '{
    "name": "Quickstart JPEG",
    "input": {"type": "frame"}
  }')"
export SOURCE_ID="$(printf '%s' "$SOURCE_JSON" |
  python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])')"
printf 'Created %s\n' "$SOURCE_ID"

3. 建立 Monitor

MONITOR_JSON="$(python3 -c 'import json,os
print(json.dumps({
  "name": "After-hours loading dock",
  "source_id": os.environ["SOURCE_ID"],
  "prompt": "Notify when a person enters the loading area after hours.",
  "enabled": True,
}))' |
  curl --fail -X POST "$SENTINEL_BASE_URL/v1/monitors" \
    -H "Authorization: Bearer $SENTINEL_API_KEY" \
    -H "Content-Type: application/json" \
    -H "Idempotency-Key: quickstart-monitor-1" \
    --data-binary @-)"
export MONITOR_ID="$(printf '%s' "$MONITOR_JSON" |
  python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])')"
printf 'Created %s\n' "$MONITOR_ID"

4. 選用:註冊並測試 Webhook

: "${SENTINEL_WEBHOOK_URL:?Export a reachable HTTPS receiver URL first}"

WEBHOOK_JSON="$(python3 -c 'import json,os
print(json.dumps({
  "name": "My receiver",
  "url": os.environ["SENTINEL_WEBHOOK_URL"],
  "secret_env": "SENTINEL_WEBHOOK_SIGNING_SECRET",
  "enabled": True,
  "filters": {"event_types": ["sdk.test"]},
}))' |
  curl --fail -X POST "$SENTINEL_BASE_URL/v1/webhook-endpoints" \
    -H "Authorization: Bearer $SENTINEL_API_KEY" \
    -H "Content-Type: application/json" \
    -H "Idempotency-Key: quickstart-webhook-1" \
    --data-binary @-)"
export WEBHOOK_ID="$(printf '%s' "$WEBHOOK_JSON" |
  python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])')"

curl --fail -X POST \
  "$SENTINEL_BASE_URL/v1/webhook-endpoints/$WEBHOOK_ID/test" \
  -H "Authorization: Bearer $SENTINEL_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: quickstart-webhook-test-1" \
  -d '{
    "severity": "suspicious",
    "title": "Sentinel webhook test",
    "summary": "Verify receipt and signature."
  }'

自動 smoke 已用本機 receiver 驗證 exact-body HMAC;只有在你已有可連線的 receiver 時才需要手動執行此步驟。若要接收下一則 sdk.test Event,請保持 receiver 運作。

5. 傳入真正的 JPEG bytes

export TEST_JPEG="${TMPDIR:-/tmp}/sentinel-quickstart-frame.jpg"

python3 -c 'import base64,pathlib,sys
pathlib.Path(sys.argv[2]).write_bytes(base64.b64decode(pathlib.Path(sys.argv[1]).read_text()))' \
  ../../docs/api/assets/sample-frame.jpg.b64 "$TEST_JPEG"

curl --fail -X POST "$SENTINEL_BASE_URL/v1/sources/$SOURCE_ID/frames" \
  -H "Authorization: Bearer $SENTINEL_API_KEY" \
  -H "Content-Type: image/jpeg" \
  -H "Idempotency-Key: quickstart-frame-1" \
  --data-binary "@$TEST_JPEG"

frames 是有限的測試/自訂 ingest 路徑,不是影片儲存 API。Runtime 會在推理前驗證 content type、解碼尺寸與大小上限。

6. 建立含圖片的 deterministic 測試 Event

EVENT_JSON="$(python3 -c 'import base64,json,os,pathlib
print(json.dumps({
  "source_id": os.environ["SOURCE_ID"],
  "monitor_id": os.environ["MONITOR_ID"],
  "type": "sdk.test",
  "severity": "suspicious",
  "summary": "Quickstart evidence event",
  "image_base64": base64.b64encode(pathlib.Path(os.environ["TEST_JPEG"]).read_bytes()).decode(),
}))' |
  curl --fail -X POST "$SENTINEL_BASE_URL/v1/events/test" \
    -H "Authorization: Bearer $SENTINEL_API_KEY" \
    -H "Content-Type: application/json" \
    -H "Idempotency-Key: quickstart-event-1" \
    --data-binary @-)"
export EVENT_ID="$(printf '%s' "$EVENT_JSON" |
  python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])')"
printf 'Created %s\n' "$EVENT_ID"

image_base64 只存在於受控的 test-event endpoint,方便沒有攝影機時驗證證據路徑。正式 Event 與 Webhook 預設都回傳 image_url,不把 Base64 內嵌在 JSON。

7. 查詢 Event 並下載 JPEG

curl --fail "$SENTINEL_BASE_URL/v1/events/$EVENT_ID" \
  -H "Authorization: Bearer $SENTINEL_API_KEY"

curl --fail "$SENTINEL_BASE_URL/v1/events/$EVENT_ID/image" \
  -H "Authorization: Bearer $SENTINEL_API_KEY" \
  --output event.jpg

file event.jpg

普通推論文字與即時預覽

curl --no-buffer --fail \
  "$SENTINEL_BASE_URL/v1/analyses/stream?monitor_id=$MONITOR_ID" \
  -H "Authorization: Bearer $SENTINEL_API_KEY" \
  -H "Accept: text/event-stream"

curl --fail \
  "$SENTINEL_BASE_URL/v1/sources/$SOURCE_ID/stream?max_fps=15&max_height=720" \
  -H "Authorization: Bearer $SENTINEL_API_KEY" \
  --output preview.mjpeg

第一個串流會送出每一次完成的普通推論文字(包含安全結果);第二個是受限制的 MJPEG 預覽。事件/警告/錯誤請用 /v1/events、/v1/events/stream 或 signed Webhook;關閉桌面視窗不會停止這些 API 輸出。

Python:執行同一套已測試流程

Source kit 內附只使用 Python 3 標準函式庫的完整範例;它會建立 Source 與 Monitor、傳入 JPEG、建立測試 Event,並驗證下載證據的 SHA-256。

cd deploy/api
export SENTINEL_BASE_URL=http://127.0.0.1:8000
export SENTINEL_API_KEY="<your-server-side-key>"
python3 ../../docs/api/examples/first_event.py

JavaScript:查詢與二進位圖片

import { writeFile } from "node:fs/promises";

const base = "http://localhost:8000";
const headers = { Authorization: `Bearer ${process.env.SENTINEL_API_KEY}` };

const events = await fetch(`${base}/v1/events?limit=10`, { headers })
  .then(async (response) => {
    if (!response.ok) throw await response.json();
    return response.json();
  });

const event = events.data[0];
if (!event) throw new Error("No events returned");
const image = await fetch(new URL(event.evidence.image_url, base), { headers });
if (!image.ok) throw new Error(`image download failed: ${image.status}`);
await writeFile("event.jpg", Buffer.from(await image.arrayBuffer()));

換成真實環境

Mock quickstart 已建立 deploy/api/.env。不要再執行 bootstrap 覆寫它;保留既有 API/Webhook secrets,只依 provider 文件替換 provider 設定並驗證 Compose。
  1. 依模型指南改用 local_* 或 private_openai_compatible;cloud_gemini 必須通過文件列出的 release gate 才能使用。
  2. 先設定精確 RTSP host/host:port 或 CIDR allowlist,再建立 input.type=rtsp 的 Source。
  3. 呼叫 Source test,確認可解碼影格與 sanitized failure code。
  4. 為新的 RTSP Source 建立新的 Monitor,再用代表性影像觸發真實推理;mock Monitor 仍連到原本的 frame Source。

下一步:Source 完整指南 →

完成標準:你能用 Bearer key 查到 Event,以受保護 URL 下載可解碼 JPEG,且自動 smoke 已驗證簽署 Webhook。