Nodeflux Central
Alert History

API Reference — Alert History

Endpoint untuk mengambil daftar alert, detail, memperbarui status follow-up, mengekspor data Alert History, dan berlangganan alert real-time lewat WebSocket.

Semua endpoint memerlukan otentikasi. Untuk integrasi, kirim header X-Api-Key: <key> di setiap request tanpa header Authorization. Bearer token (Authorization: Bearer <access_token>, berlaku 30 menit) hanya untuk aplikasi yang menampilkan login Lenz ke penggunanya sendiri dan wajib menyertakan X-Integration-Signature. Basis URL mengikuti variabel lingkungan VITE_API_URL yang dikonfigurasi pada instalasi Lenz. Lihat Otentikasi untuk memilih jalur yang tepat.


Daftar & Detail Alert

Endpoint utama untuk mengambil daftar alert yang telah ter-trigger dan detail satu alert berdasarkan ID-nya.

Daftar Alert History

GET
/api/alert-history

Authorization

bearerAuth
AuthorizationBearer <token>

In: header

Query Parameters

cursor?string

Kursor pagination untuk memuat halaman berikutnya atau sebelumnya. Ambil dari field next_cursor atau prev_cursor di respons sebelumnya. Hilangkan parameter ini untuk halaman pertama.

limit?integer

Jumlah item per halaman. Maksimum: 100.

Default20
Range1 <= value <= 100
include_total?boolean

Jika true, respons akan menyertakan total keseluruhan data yang cocok. Mengaktifkan mode cursor dan membutuhkan query COUNT tambahan.

Defaultfalse
page?integer

Nomor halaman untuk mode offset-based pagination (1-indexed). Digunakan saat mode cursor tidak diaktifkan.

Default1
Range1 <= value
pagination_mode?string

Set ke cursor untuk secara eksplisit menggunakan cursor-based pagination.

Value in"cursor"
sort[created_at]?string

Urutan berdasarkan waktu pembuatan alert.

Default"desc"
Value in"asc" | "desc"
sort[severity]?string

Urutan berdasarkan tingkat keparahan alert.

Value in"asc" | "desc"
search?string

Pencarian teks bebas pada alertable_id, nama Alert Rule, atau nama stream.

filter[created_from]?string

Batas awal rentang waktu dalam format ISO 8601 / RFC 3339.

Formatdate-time
filter[created_to]?string

Batas akhir rentang waktu dalam format ISO 8601 / RFC 3339.

Formatdate-time
filter[severity]?string

Filter tingkat keparahan. Dapat berisi beberapa nilai dipisahkan koma.

filter[follow_up_status]?string

Filter status follow-up. Dapat berisi beberapa nilai dipisahkan koma.

filter[alert_rule_id]?integer

Filter berdasarkan ID Alert Rule tertentu.

filter[stream_id]?string

Filter berdasarkan satu atau beberapa Stream ID, dipisahkan koma.

filter[site_id]?integer

Filter berdasarkan ID site. Akan menampilkan alert dari semua stream yang berada di site tersebut.

filter[alertable_type]?string

Filter berdasarkan tipe sumber alert.

Value in"event" | "manual" | "system" | "scheduled" | "external"
timezone?string

Timezone klien (identifikasi IANA) untuk interpretasi filter tanggal.

Default"UTC"
instance?string

ID instance backend. Digunakan dalam mode Federation untuk mengambil alert dari instance tertentu.

Response Body

application/json

application/json

application/json

application/json

curl -X GET "https://lenz.example.com/api/alert-history"
{  "ok": true,  "message": "successfully get alert history list",  "data": [    {      "id": 1042,      "alertable_id": "event_stream-uuid-xyz_1746000898",      "alertable_type": "event",      "alert_rule_id": 7,      "severity": "critical",      "follow_up_status": "not_followed_up",      "follow_up_notes": null,      "created_at": "2025-04-30T08:15:00Z",      "updated_at": null,      "instance": null,      "alert_rule": {        "id": 7,        "name": "Deteksi Wajah Tidak Dikenal",        "description": "Alert untuk wajah yang tidak terdaftar di enrollment",        "active": true,        "analytic_id": "FR"      },      "event": {        "id": 5801,        "analytic_id": "FR",        "stream_id": "stream-uuid-xyz",        "stream_name": "Pintu Masuk Utama",        "primary_image": "<base64-encoded-image>",        "label": "Unknown",        "result": "unknown",        "event_time": "2025-04-30T08:14:58Z",        "created_at": "2025-04-30T08:14:59Z"      }    }  ],  "pagination": {    "limit": 20,    "has_next": true,    "has_prev": false,    "next_cursor": "eyJ0IjoiMjAyNS0wNC0zMFQwODoxNTowMFoiLCJpZCI6IjEwMzAifQ==",    "prev_cursor": null,    "total": null  }}
{  "ok": false,  "code": "bad-request",  "errors": [    "invalid cursor format"  ],  "message": "Invalid query parameters"}
{  "ok": false,  "code": "unauthorized",  "message": "Authentication required"}
{  "ok": false,  "code": "forbidden",  "message": "Access denied: alert_history permission required"}

Detail Alert

GET
/api/alert-history/{id}

Authorization

bearerAuth
AuthorizationBearer <token>

In: header

Path Parameters

id*integer

ID numerik alert history.

Query Parameters

instance?string

ID instance backend. Digunakan dalam mode Federation.

Response Body

application/json

application/json

curl -X GET "https://lenz.example.com/api/alert-history/1042"
{  "ok": true,  "message": "successfully get alert history detail",  "data": {    "id": 1042,    "alertable_id": "event_stream-uuid-xyz_1746000898",    "alertable_type": "event",    "alert_rule_id": 7,    "severity": "critical",    "follow_up_status": "not_followed_up",    "follow_up_notes": null,    "created_at": "2025-04-30T08:15:00Z",    "updated_at": null,    "instance": null,    "alert_rule": {      "id": 7,      "name": "Deteksi Wajah Tidak Dikenal",      "description": "Alert untuk wajah yang tidak terdaftar di enrollment",      "active": true,      "analytic_id": "FR"    },    "event": {      "id": 5801,      "analytic_id": "FR",      "stream_id": "stream-uuid-xyz",      "stream_name": "Pintu Masuk Utama",      "stream_latitude": -6.2088,      "stream_longitude": 106.8456,      "primary_image": "<base64-encoded-image>",      "secondary_image": null,      "label": "Unknown",      "result": "unknown",      "location": "Lantai 1, Gedung A",      "status": "active",      "logic": "face_recognition",      "event_time": "2025-04-30T08:14:58Z",      "created_at": "2025-04-30T08:14:59Z",      "pipeline_event_id": "event_stream-uuid-xyz_1746000898"    }  }}
{  "ok": false,  "code": "not-found",  "message": "Alert history record not found"}

Detail Alert by Alertable

GET
/api/alert-history/by-alertable/{alertable_type}/{alertable_id}

Authorization

bearerAuth
AuthorizationBearer <token>

In: header

Path Parameters

alertable_type*string

Tipe entitas alertable.

Value in"event" | "manual" | "system" | "scheduled" | "external"
alertable_id*string

ID unik entitas yang memicu alert.

Query Parameters

timezone?string

Timezone klien (identifikasi IANA).

Default"UTC"

Response Body

application/json

application/json

application/json

curl -X GET "https://lenz.example.com/api/alert-history/by-alertable/event/event_stream-uuid-xyz_1746000898"
{  "ok": true,  "message": "successfully get alert history detail by alertable",  "data": {    "id": 1042,    "alertable_id": "event_stream-uuid-xyz_1746000898",    "alertable_type": "event",    "alert_rule_id": 7,    "severity": "critical",    "follow_up_status": "not_followed_up",    "follow_up_notes": null,    "created_at": "2025-04-30T08:15:00Z",    "updated_at": null,    "instance": null,    "alert_rule": {      "id": 7,      "name": "Deteksi Wajah Tidak Dikenal",      "description": "Alert untuk wajah yang tidak terdaftar di enrollment",      "active": true,      "analytic_id": "FR"    },    "event": {      "id": 5801,      "analytic_id": "FR",      "stream_id": "stream-uuid-xyz",      "stream_name": "Pintu Masuk Utama",      "label": "Unknown",      "result": "unknown",      "event_time": "2025-04-30T08:14:58Z",      "created_at": "2025-04-30T08:14:59Z"    }  }}
{  "ok": false,  "code": "bad-request",  "errors": [    "invalid alertable_type"  ],  "message": "Invalid alertable_type. Must be one of: event, manual, system, scheduled, external"}
{  "ok": false,  "code": "not-found",  "message": "Alert history record not found for the specified alertable_id and alertable_type"}

Follow-up

Endpoint untuk memperbarui status follow-up satu alert. Status yang tersedia: not_followed_up (belum ditangani), followed_up (sudah ditangani, umum), match / not_match (hasil verifikasi identitas cocok / tidak cocok), expired (data sudah kedaluwarsa saat diperiksa), dan other (alasan lain — wajib mengisi reason).

Perbarui Status Follow-up

PATCH
/api/alert-history/{id}/follow-up-status

Authorization

bearerAuth
AuthorizationBearer <token>

In: header

Path Parameters

id*integer

ID numerik alert history.

Query Parameters

instance?string

ID instance backend. Digunakan dalam mode Federation.

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

application/json

curl -X PATCH "https://lenz.example.com/api/alert-history/1042/follow-up-status" \  -H "Content-Type: application/json" \  -d '{    "follow_up_status": "followed_up",    "follow_up_notes": "Sudah diperiksa oleh tim keamanan pukul 09.00 WIB"  }'
{  "ok": true,  "message": "follow up status updated successfully"}
{  "ok": false,  "code": "bad-request",  "message": "Invalid follow_up_status value"}
{  "ok": false,  "code": "not-found",  "message": "Alert history record not found"}

Ekspor

Endpoint untuk mengekspor data alert history secara asinkron ke format PDF atau Excel. Alur ekspor:

  1. Panggil Mulai Job Ekspor untuk memulai proses di sisi server. Respons berisi job_id.
  2. Polling Status Job Ekspor menggunakan job_id hingga status bernilai completed.
  3. Panggil Unduh Hasil Ekspor untuk mengunduh file binary.
  4. (Opsional) Panggil Batalkan Job Ekspor untuk membatalkan proses yang masih berjalan.

Ekspor dalam jumlah besar (ribuan alert dengan opsi include_images: true) dapat membutuhkan waktu lebih lama dan menghasilkan file berukuran signifikan. Gunakan filter rentang tanggal untuk membatasi cakupan data sebelum mengekspor.

Mulai Job Ekspor

POST
/api/alert-history/export

Authorization

bearerAuth
AuthorizationBearer <token>

In: header

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

curl -X POST "https://lenz.example.com/api/alert-history/export" \  -H "Content-Type: application/json" \  -d '{    "format": "excel",    "scope": "all",    "timezone": "Asia/Jakarta",    "include_images": false,    "filters": {      "created_from": "2025-04-01T00:00:00Z",      "created_to": "2025-04-30T23:59:59Z",      "severities": [        "critical",        "warning"      ]    }  }'
{  "ok": true,  "message": "Export job started",  "data": {    "job_id": "export-job-uuid-abc123",    "status": "pending",    "estimated_time_seconds": 30,    "total_records": 500  }}

Status Job Ekspor

GET
/api/alert-history/export/status/{job_id}

Authorization

bearerAuth
AuthorizationBearer <token>

In: header

Path Parameters

job_id*string

ID job ekspor yang dikembalikan oleh endpoint Mulai Job Ekspor.

Response Body

application/json

curl -X GET "https://lenz.example.com/api/alert-history/export/status/export-job-uuid-abc123"
{  "ok": true,  "message": "success",  "data": {    "job_id": "export-job-uuid-abc123",    "status": "completed",    "progress": {      "processed": 500,      "total": 500,      "percent": 100    },    "file_ready": true,    "error_message": null,    "created_at": "2025-04-30T08:00:00Z",    "completed_at": "2025-04-30T08:00:45Z"  }}

Unduh Hasil Ekspor

GET
/api/alert-history/export/download/{job_id}

Authorization

bearerAuth
AuthorizationBearer <token>

In: header

Path Parameters

job_id*string

ID job ekspor.

Response Body

application/json

curl -X GET "https://lenz.example.com/api/alert-history/export/download/export-job-uuid-abc123"
"string"
{  "ok": false,  "code": "not-found",  "message": "Export job not found or file not ready"}

Batalkan Job Ekspor

DELETE
/api/alert-history/export/{job_id}

Authorization

bearerAuth
AuthorizationBearer <token>

In: header

Path Parameters

job_id*string

ID job ekspor yang akan dibatalkan.

Response Body

application/json

curl -X DELETE "https://lenz.example.com/api/alert-history/export/export-job-uuid-abc123"
{  "ok": true,  "message": "Export job cancelled"}

Webhook & Streaming

Channel WebSocket untuk menerima alert secara real-time — jalur yang sama yang dipakai Lenz untuk memunculkan toast alert di pojok layar. Berbeda dengan /api/event_channel yang mengalirkan semua deteksi, channel ini hanya mengirim event yang sudah lolos minimal satu Alert Rule aktif, sehingga cocok untuk sistem eksternal yang hanya peduli pada kejadian signifikan (dashboard SOC, notifikasi ke aplikasi chat, alur otomasi).

Endpoint /api/alert_channel menggunakan protokol WebSocket — bukan HTTP biasa. Gunakan ws:// atau wss:// sebagai skema URL, dan kirim kredensial sebagai query parameter (x-api-key=<key> untuk integrasi, atau authorization=<access_token> untuk sesi pengguna) karena browser tidak bisa menyertakan header kustom saat handshake. Lihat Otentikasi WebSocket.

Beberapa perilaku yang perlu diperhatikan sebelum berlangganan:

  • Cakupan mengikuti hak akses akun. Server hanya mengirim alert dari stream yang boleh diakses akun pemilik kredensial. Jika akun tidak punya akses ke stream mana pun, handshake ditolak dengan 403.
  • Filter ditentukan oleh Alert Rule, bukan query parameter. Parameter stream_ids, analytic_id, dan logic milik /api/event_channel diabaikan di sini. Atur Alert Rule untuk memilih stream dan kondisi yang layak menjadi alert.
  • Payload tidak memuat alert_history_id. Record alert history disimpan secara asinkron setelah pesan terkirim. Untuk menautkan pesan ke record REST, gunakan stream_id dan timestamp pada payload sebagai filter filter[stream_id] + filter[created_from]/filter[created_to] di Daftar Alert History.
  • Konsumsi pesan dengan cepat. Server mem-buffer maksimal 256 pesan per koneksi; jika buffer penuh, koneksi ditutup. Pada volume tinggi gunakan disable_base64_image=true dan ambil gambar lewat GET /api/event/image?<primary_image_url> hanya saat dibutuhkan.
  • Federation. Tambahkan is_aggregated=true untuk menerima alert dari instance lokal dan semua remote instance sekaligus. Event dari remote instance membawa field instance, dan primary_image_url-nya sudah menyertakan instance= sehingga bisa langsung dipakai.
  • Reconnect. Koneksi bisa terputus saat server restart atau jaringan bermasalah. Terapkan reconnect otomatis dengan exponential backoff seperti yang dilakukan Lenz (basis 5 detik, maksimum 10 percobaan).
Berlangganan alert_channel (Node.js)
import WebSocket from 'ws';

const params = new URLSearchParams({
  'x-api-key': process.env.LENZ_API_KEY,
  disable_base64_image: 'true',
});

const ws = new WebSocket(`wss://api.contoh.com/api/alert_channel?${params}`);

ws.on('message', (data) => {
  const alert = JSON.parse(data.toString());
  console.log(`[alert_type ${alert.alert_type_id}] ${alert.analytic_id} @ ${alert.stream_id}`);
  // gambar: GET https://api.contoh.com/api/event/image?${alert.primary_image_url}
});

ws.on('close', () => {
  // implementasikan reconnect dengan exponential backoff
});

WebSocket Alert Channel

GET
/api/alert_channel

Query Parameters

x-api-key?string

API key untuk integrasi. Wajib salah satu dari x-api-key atau authorization.

authorization?string

Access token sesi pengguna (berlaku 30 menit), dengan atau tanpa awalan Bearer . Alternatif dari x-api-key.

disable_base64_image?boolean

Set true agar primary_image/secondary_image tidak disertakan; ambil gambar lewat primary_image_url saat dibutuhkan. Sangat disarankan pada volume tinggi.

Defaultfalse
is_aggregated?boolean

Mode Federation: set true untuk menerima alert dari instance lokal dan semua remote instance. Lenz mengaktifkan ini otomatis saat berjalan dalam mode Federation.

Defaultfalse
instance?string

Mode Federation: berlangganan hanya ke satu remote instance tertentu. Kosongkan atau isi core untuk instance lokal.

Response Body

application/json

application/json

curl -X GET "https://lenz.example.com/api/alert_channel?x-api-key=%3Ckey%3E&authorization=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
{  "event_id": "3f1a9c2e-7b4d-4e0a-9c1b-2d5f6a7b8c9d",  "alert_type_id": 2,  "analytic_id": "NFV4-FR",  "stream_id": "eb7022a64d9173a6",  "node_num": 0,  "label": "UNKNOWN",  "location": "Lobby Utama",  "result": "UNKNOWN",  "status": "UNKNOWN",  "logic": "face_recognition",  "timestamp": "2026-04-30T08:23:45+07:00",  "instance": "cabang-bandung",  "primary_image": "string",  "secondary_image": "string",  "primary_image_url": "event_id=3f1a9c2e-7b4d-4e0a-9c1b-2d5f6a7b8c9d&type=primary",  "secondary_image_url": "event_id=3f1a9c2e-7b4d-4e0a-9c1b-2d5f6a7b8c9d&type=secondary",  "pipeline_data": {    "face_id": "118747588341006337",    "similarity": 0.4894,    "status": "UNKNOWN",    "confidence_detection": 0.9988  }}
Empty
{  "ok": false,  "code": "forbidden",  "message": "you don't have access to any streams"}

On this page