Your API Token
Dùng token này để xác thực mọi request: Authorization: Bearer <token>.
Token hết hạn sau 24 giờ — đăng xuất và đăng nhập lại để lấy token mới.
—
Lấy token tự động (không cần trình duyệt)
Dùng lệnh POST login để nhận JWT token. Token trả về trong field token.
Dùng token này cho tất cả các request tiếp theo.
curl:
# Bước 1: Đăng nhập và lấy token
RESP=$(curl -s -X POST "http://HOST:1984/api/auth/login" \
-H "Content-Type: application/json" \
-d '{"username":"USER","password":"PASS"}')
# Bước 2: Kiểm tra response (nếu thấy "error" thì sai user/pass)
echo "$RESP"
# Bước 3: Extract token (nếu đăng nhập thành công)
TOKEN=$(echo "$RESP" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('token','ERROR:'+str(d)))")
echo "Token: $TOKEN"
# Bước 4: Dùng token để gọi API
curl -s -H "Authorization: Bearer $TOKEN" \
"http://HOST:1984/api/proxy/streams"
Python:
import requests
resp = requests.post("http://HOST:1984/api/auth/login",
json={"username": "USER", "password": "PASS"})
token = resp.json()["token"]
print("Token:", token)
# Dùng token để lấy danh sách stream
streams = requests.get("http://HOST:1984/api/proxy/streams",
headers={"Authorization": f"Bearer {token}"}).json()
for s in streams:
print(s["id"], "→", s["frame_url"])
Node.js / fetch:
const resp = await fetch("http://HOST:1984/api/auth/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ username: "USER", password: "PASS" })
});
const { token } = await resp.json();
// Lấy danh sách camera
const streams = await fetch("http://HOST:1984/api/proxy/streams", {
headers: { "Authorization": "Bearer " + token }
}).then(r => r.json());
💡 Token hết hạn sau 24 giờ. Trong script tự động, hãy lưu token vào biến/file và đăng nhập lại khi nhận lỗi
401.
Camera IDs của bạn
Mỗi camera có một ID ẩn danh dùng trong tất cả API URL — không lộ tên gốc. Dùng các nút bên phải để sao chép URL nhanh.
| Camera ID | Nhanh chép URL |
|---|---|
| Loading… | |
Endpoint Reference
GET
/api/cameras
Danh sách camera + tọa độ GPS — không kèm stream URL
▶
📌 Endpoint này được thiết kế cho hệ thống bản đồ / GIS bên ngoài.
Không trả về stream URL — chỉ ID, nhãn và tọa độ.
Admin nhận thêm field
Không trả về stream URL — chỉ ID, nhãn và tọa độ.
Admin nhận thêm field
"name" (tên stream gốc).
Query params:
| Param | Mô tả | Mặc định |
|---|---|---|
token | JWT token (thay cho Authorization header) | — |
all=true | Kể cả camera chưa có tọa độ (lat/lon = null) | false |
format=geojson | Trả về GeoJSON FeatureCollection | JSON array |
JSON array (mặc định):
GET /api/cameras
Authorization: Bearer <token>
→ [
{
"id": "a3f9c12d8e4b",
"label": "Ngã tư An Sương",
"lat": 10.823145,
"lon": 106.629732
},
{
"id": "b7e2a1f4c3d9",
"label": "Cầu Bình Lợi",
"lat": 10.834211,
"lon": 106.710445
}
]
# Admin thêm field "name":
→ [
{ "id": "a3f9c12d8e4b", "name": "camera_01", "label": "Ngã tư An Sương", "lat": 10.823145, "lon": 106.629732 }
]
# Kể cả camera chưa cài tọa độ:
GET /api/cameras?all=true
→ [
{ "id": "a3f9c12d8e4b", "label": "Ngã tư An Sương", "lat": 10.823145, "lon": 106.629732 },
{ "id": "c9d3b2e1a4f8", "label": "", "lat": null, "lon": null }
]
GeoJSON FeatureCollection (?format=geojson):
GET /api/cameras?format=geojson
Authorization: Bearer <token>
→ {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [106.629732, 10.823145] ← [lon, lat] theo chuẩn GeoJSON
},
"properties": {
"id": "a3f9c12d8e4b",
"label": "Ngã tư An Sương"
}
}
]
}
Python:
import requests
TOKEN = "eyJ..." # lấy từ /api/auth/login
# Danh sách camera có tọa độ
cameras = requests.get("http://HOST:1984/api/cameras",
headers={"Authorization": f"Bearer {TOKEN}"}).json()
for cam in cameras:
print(f"{cam['id']} {cam.get('label',''):<30} lat={cam['lat']} lon={cam['lon']}")
# GeoJSON — nạp thẳng vào Leaflet / Mapbox / VietMap
geojson = requests.get("http://HOST:1984/api/cameras?format=geojson",
headers={"Authorization": f"Bearer {TOKEN}"}).json()
# Dùng trong Leaflet:
# L.geoJSON(geojson).addTo(map);
curl:
curl -H "Authorization: Bearer TOKEN" http://HOST:1984/api/cameras
curl -H "Authorization: Bearer TOKEN" "http://HOST:1984/api/cameras?all=true"
curl -H "Authorization: Bearer TOKEN" "http://HOST:1984/api/cameras?format=geojson"
# Token trong query string (tiện cho link nhúng):
curl "http://HOST:1984/api/cameras?token=TOKEN"
POST
/api/auth/login
Đăng nhập — nhận JWT token
▶
POST /api/auth/login
Content-Type: application/json
{"username": "user", "password": "pass"}
→ {"token": "eyJ...", "username": "user", "role": "viewer"}
GET
/api/proxy/streams
Danh sách stream + URL đầy đủ (theo quyền user)
▶
GET /api/proxy/streams
Authorization: Bearer <token>
→ [
{
"id": "a3f9c12d8e4b",
"ws_url": "ws://HOST:1984/api/proxy/ws?id=a3f9c12d8e4b&token=...",
"hls_url": "http://HOST:1984/api/proxy/hls?id=a3f9c12d8e4b&token=...",
"frame_url": "http://HOST:1984/api/proxy/frame?id=a3f9c12d8e4b&token=...",
"mp4_url": "http://HOST:1984/api/proxy/mp4?id=a3f9c12d8e4b&token=..."
}
]
GET
/api/proxy/frame?id=CAMERA_ID
Snapshot (1 frame MP4) — tiết kiệm băng thông
▶
GET /api/proxy/frame?id=CAMERA_ID&token=TOKEN
→ video/mp4 (single keyframe)
Dùng thẻ
<video autoplay muted loop> hoặc fetch+createObjectURL để hiển thị thumbnail.
WS
/api/proxy/ws?id=CAMERA_ID
WebSocket — WebRTC / MSE / HLS qua video-stream.js
▶
ws://HOST:1984/api/proxy/ws?id=CAMERA_ID&token=TOKEN
WebSocket không truyền header — token phải đặt trong query param
&token=.
GET
/api/proxy/hls?id=CAMERA_ID
HLS playlist (m3u8)
▶
GET /api/proxy/hls?id=CAMERA_ID&token=TOKEN
→ application/vnd.apple.mpegurl
GET
/api/proxy/mp4?id=CAMERA_ID
MP4 stream liên tục
▶
GET /api/proxy/mp4?id=CAMERA_ID&token=TOKEN
→ video/mp4 (stream)
GET
/api/proxy/rtsp-url?id=CAMERA_ID
Lấy RTSP URL ẩn danh — dùng cho phần mềm CCTV/NVR
▶
GET /api/proxy/rtsp-url?id=CAMERA_ID&token=TOKEN
→ {
"stream_id": "a3f9c12d8e4b",
"rtsp_url": "rtsp://HOST:8554/a3f9c12d8e4b",
"rtsp_port": "8554",
"note": "If RTSP auth configured: rtsp://user:pass@HOST:8554/a3f9c12d8e4b"
}
📡 RTSP URL dùng Camera ID (12 ký tự hex) làm tên stream — tên gốc không bao giờ bị lộ.
Server go2rtc lắng nghe RTSP mặc định tại port
Nếu có cấu hình
Server go2rtc lắng nghe RTSP mặc định tại port
8554.Nếu có cấu hình
rtsp.username/password trong go2rtc, thêm credentials vào URL.
curl -H "Authorization: Bearer TOKEN" \
"http://HOST:1984/api/proxy/rtsp-url?id=CAMERA_ID"
# Kết nối thử bằng ffplay:
ffplay "rtsp://HOST:1984:8554/CAMERA_ID"
# Hoặc bằng VLC (nếu có RTSP auth):
vlc "rtsp://user:pass@HOST:1984:8554/CAMERA_ID"
JS
Embed video-stream player (WebRTC/MSE/HLS auto)
▶
<script type="module" src="http://HOST:1984/video-stream.js"></script>
const player = document.createElement('video-stream');
player.mode = 'webrtc,mse,hls'; // thử theo thứ tự
player.src = 'ws://HOST:1984/api/proxy/ws?id=CAMERA_ID&token=TOKEN';
document.body.appendChild(player);
JS
Thumbnail từ frame.mp4 bằng fetch + createObjectURL
▶
// Dùng fetch thay vì gán src trực tiếp để đưa token vào header
const resp = await fetch(`http://HOST:1984/api/proxy/frame?id=${cameraId}`, {
headers: { Authorization: 'Bearer ' + token }
});
const blob = await resp.blob();
const video = document.createElement('video');
video.autoplay = video.muted = video.loop = true;
video.src = URL.createObjectURL(blob);
document.body.appendChild(video);
curl
Lưu snapshot bằng curl
▶
curl -H "Authorization: Bearer TOKEN" \
"http://HOST:1984/api/proxy/frame?id=CAMERA_ID" \
-o snapshot.mp4
curl
Tích hợp RTSP vào NVR / phần mềm CCTV
▶
📡 Quy trình: Đăng nhập → lấy Camera ID từ
/api/proxy/streams → dùng RTSP URL rtsp://HOST:8554/CAMERA_ID trong NVR/VLC/ffmpeg. Tên gốc của camera không bao giờ xuất hiện.# Bước 1: Lấy token
TOKEN=$(curl -s -X POST http://HOST:1984/api/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"user","password":"pass"}' | jq -r .token)
# Bước 2: Lấy danh sách camera và RTSP URL
curl -s -H "Authorization: Bearer $TOKEN" \
http://HOST:1984/api/proxy/streams | jq '.[] | {id, name, rtsp_url}'
# Kết quả:
# { "id": "a3f9c12d8e4b", "name": "Camera_01", "rtsp_url": "rtsp://HOST:8554/a3f9c12d8e4b" }
# Bước 3: Xem bằng ffplay / VLC
ffplay rtsp://HOST:1984:8554/a3f9c12d8e4b
# Hoặc ghi lại bằng ffmpeg (10 giây):
ffmpeg -i rtsp://HOST:1984:8554/a3f9c12d8e4b -t 10 output.mp4
Python — OpenCV:
import cv2, requests
# Đăng nhập
r = requests.post("http://HOST:1984/api/auth/login",
json={"username": "user", "password": "pass"})
token = r.json()["token"]
# Lấy camera đầu tiên
cams = requests.get("http://HOST:1984/api/proxy/streams",
headers={"Authorization": f"Bearer {token}"}).json()
rtsp_url = cams[0]["rtsp_url"] # e.g. rtsp://HOST:8554/a3f9c12d8e4b
# Mở stream bằng OpenCV
cap = cv2.VideoCapture(rtsp_url)
while cap.isOpened():
ret, frame = cap.read()
if not ret: break
cv2.imshow("Camera", frame)
if cv2.waitKey(1) & 0xFF == ord('q'): break
cap.release(); cv2.destroyAllWindows()