Dokumentasi / CCTV Beta

CCTV API

Host https://cctv.larika.id. Kirim API key di header Authorization: Bearer atau x-api-key. Deskripsi endpoint masih berbahasa Inggris.

Node

GET/v1/nodesNodes

The nodes (locations) of the key’s client (the management key: every node) — business hours, camera count, whether it is online.

Contoh
curl -X GET 'https://cctv.larika.id/v1/nodes' \
  -H 'Authorization: Bearer $LARIKA_KEY'
Jawaban
200
[
  {
    "id": "cmuwaprz30002kniwevk87652",
    "name": "Kantor Depati",
    "timezone": "Asia/Jakarta",
    "openTime": "08:00",
    "closeTime": "17:00",
    "clientId": "cmuwcl0001",
    "cameras": 2,
    "online": true
  }
]

Cameras

GET/v1/camerasList cameras

Cameras of the key’s nodes (nodeId = one node) with status (ONLINE · OFFLINE · UNKNOWN = node offline), recording, detection settings, zones and lines.

Contoh
curl -X GET 'https://cctv.larika.id/v1/cameras' \
  -H 'Authorization: Bearer $LARIKA_KEY'
Jawaban
200
[
  {
    "id": "cmuwarje90004kniwsvv67q1u",
    "nodeId": "cmuwaprz30002kniwevk87652",
    "name": "Ruang tamu",
    "status": "ONLINE",
    "error": null,
    "ptz": true,
    "hasSub": true,
    "manufacturer": "macro-video-soft",
    "model": "IPCamera",
    "recordMode": "MOTION",
    "retentionDays": 7,
    "motionEnabled": true,
    "motionThreshold": 0.003,
    "detect": {
      "tamper": true,
      "frozen": true,
      "lights": true,
      "sound": false,
      "soundDb": -10,
      "cameraEvents": true,
      "person": true,
      "vehicle": false,
      "aiScore": 0.45,
      "face": false,
      "faceScore": 0.7,
      "soundAi": false,
      "soundAiScore": 0.35
    },
    "zones": [
      {
        "id": "pintu",
        "name": "Pintu masuk",
        "points": [
          [
            0.25,
            0
          ],
          [
            0.85,
            0
          ],
          [
            0.85,
            0.55
          ],
          [
            0.25,
            0.55
          ]
        ],
        "schedule": "always",
        "dwellSec": 120
      }
    ],
    "lines": [
      {
        "id": "pintu",
        "name": "Pintu",
        "points": [
          [
            0.45,
            0.15
          ],
          [
            0.95,
            0.15
          ]
        ]
      }
    ],
    "lastMotionAt": "2026-10-06T07:04:20.000Z",
    "createdAt": "2026-10-06T07:04:20.000Z"
  }
]
GET/v1/cameras/{camera}One camera

One camera, same shape as in the list.

ParameterDiTipeKeterangan
id *pathstringCamera id (List cameras).
Contoh
curl -X GET 'https://cctv.larika.id/v1/cameras/{camera}' \
  -H 'Authorization: Bearer $LARIKA_KEY'
Jawaban
200
{
  "id": "cmuwarje90004kniwsvv67q1u",
  "nodeId": "cmuwaprz30002kniwevk87652",
  "name": "Ruang tamu",
  "status": "ONLINE",
  "error": null,
  "ptz": true,
  "hasSub": true,
  "manufacturer": "macro-video-soft",
  "model": "IPCamera",
  "recordMode": "MOTION",
  "retentionDays": 7,
  "motionEnabled": true,
  "motionThreshold": 0.003,
  "detect": {
    "tamper": true,
    "frozen": true,
    "lights": true,
    "sound": false,
    "soundDb": -10,
    "cameraEvents": true,
    "person": true,
    "vehicle": false,
    "aiScore": 0.45,
    "face": false,
    "faceScore": 0.7,
    "soundAi": false,
    "soundAiScore": 0.35
  },
  "zones": [
    {
      "id": "pintu",
      "name": "Pintu masuk",
      "points": [
        [
          0.25,
          0
        ],
        [
          0.85,
          0
        ],
        [
          0.85,
          0.55
        ],
        [
          0.25,
          0.55
        ]
      ],
      "schedule": "always",
      "dwellSec": 120
    }
  ],
  "lines": [
    {
      "id": "pintu",
      "name": "Pintu",
      "points": [
        [
          0.45,
          0.15
        ],
        [
          0.95,
          0.15
        ]
      ]
    }
  ],
  "lastMotionAt": "2026-10-06T07:04:20.000Z",
  "createdAt": "2026-10-06T07:04:20.000Z"
}
PATCH/v1/cameras/{camera}Settings & detectors

Name, recording (OFF · MOTION = minutes around events, with pre-roll · CONTINUOUS), retention, motion sensitivity, and the detectors. detect is merged: send only the switches you change. The node applies it at once.

ParameterDiTipeKeterangan
id *pathstringCamera id (List cameras).
recordModebodystringOFF · MOTION · CONTINUOUS
retentionDaysbodynumberRecordings older than this are deleted on the node.
motionThresholdbodynumberFraction of pixels changed that counts as motion (default 0.003).
detectbodyobjecttamper frozen lights sound soundDb cameraEvents · AI: person vehicle aiScore face faceScore soundAi soundAiScore
Contoh
curl -X PATCH 'https://cctv.larika.id/v1/cameras/{camera}' \
  -H 'Authorization: Bearer $LARIKA_KEY' \
  -H 'content-type: application/json' \
  -d '{"detect":{"person":true,"vehicle":false}}'
Jawaban
200
{
  "id": "cmuwarje90004kniwsvv67q1u",
  "nodeId": "cmuwaprz30002kniwevk87652",
  "name": "Ruang tamu",
  "status": "ONLINE",
  "error": null,
  "ptz": true,
  "hasSub": true,
  "manufacturer": "macro-video-soft",
  "model": "IPCamera",
  "recordMode": "MOTION",
  "retentionDays": 7,
  "motionEnabled": true,
  "motionThreshold": 0.003,
  "detect": {
    "tamper": true,
    "frozen": true,
    "lights": true,
    "sound": false,
    "soundDb": -10,
    "cameraEvents": true,
    "person": true,
    "vehicle": false,
    "aiScore": 0.45,
    "face": false,
    "faceScore": 0.7,
    "soundAi": false,
    "soundAiScore": 0.35
  },
  "zones": [
    {
      "id": "pintu",
      "name": "Pintu masuk",
      "points": [
        [
          0.25,
          0
        ],
        [
          0.85,
          0
        ],
        [
          0.85,
          0.55
        ],
        [
          0.25,
          0.55
        ]
      ],
      "schedule": "always",
      "dwellSec": 120
    }
  ],
  "lines": [
    {
      "id": "pintu",
      "name": "Pintu",
      "points": [
        [
          0.45,
          0.15
        ],
        [
          0.95,
          0.15
        ]
      ]
    }
  ],
  "lastMotionAt": "2026-10-06T07:04:20.000Z",
  "createdAt": "2026-10-06T07:04:20.000Z"
}
PUT/v1/cameras/{camera}/zonesZones

All zones of the camera (replaced). Points in 0–1 of the picture (0,0 top left). Zone events: zone.motion.* (pixels), zone.enter / zone.exit / dwell.long (AI). schedule: always · open (business hours only) · closed (outside them).

ParameterDiTipeKeterangan
id *pathstringCamera id (List cameras).
Contoh
curl -X PUT 'https://cctv.larika.id/v1/cameras/{camera}/zones' \
  -H 'Authorization: Bearer $LARIKA_KEY' \
  -H 'content-type: application/json' \
  -d '[{"id":"kasir","name":"Kasir","points":[[0,0.5],[0.4,0.5],[0.4,1],[0,1]],"schedule":"always","dwellSec":120}]'
Jawaban
200
[
  {
    "id": "pintu",
    "name": "Pintu masuk",
    "points": [
      [
        0.25,
        0
      ],
      [
        0.85,
        0
      ],
      [
        0.85,
        0.55
      ],
      [
        0.25,
        0.55
      ]
    ],
    "schedule": "always",
    "dwellSec": 120
  }
]
PUT/v1/cameras/{camera}/linesCounting lines

All lines of the camera (replaced): line.crossed with direction in / out. in = crossing in the direction of point 1 → 2 turned 90° clockwise on the picture (a line drawn left → right: top → bottom is in).

ParameterDiTipeKeterangan
id *pathstringCamera id (List cameras).
Contoh
curl -X PUT 'https://cctv.larika.id/v1/cameras/{camera}/lines' \
  -H 'Authorization: Bearer $LARIKA_KEY' \
  -H 'content-type: application/json' \
  -d '[{"id":"pintu","name":"Pintu","points":[[0.45,0.15],[0.95,0.15]]}]'
Jawaban
200
[
  {
    "id": "pintu",
    "name": "Pintu",
    "points": [
      [
        0.45,
        0.15
      ],
      [
        0.95,
        0.15
      ]
    ]
  }
]

Watch

GET/v1/cameras/{camera}/snapshotSnapshot

The current frame (JPEG), from the node. Logged in the access log.

ParameterDiTipeKeterangan
id *pathstringCamera id (List cameras).
Contoh
curl -X GET 'https://cctv.larika.id/v1/cameras/{camera}/snapshot' \
  -H 'Authorization: Bearer $LARIKA_KEY'
Jawaban
200 image/jpeg
POST/v1/cameras/{camera}/liveLive view ticket

A one-time WebSocket URL (60 s to open, one viewer) for go2rtc’s player at /player/video-rtc.js, MSE mode. Get a new one for every (re)connect. Logged in the access log.

ParameterDiTipeKeterangan
id *pathstringCamera id (List cameras).
qualitybodystringmain (default) or sub (smaller, for grids).
Contoh
curl -X POST 'https://cctv.larika.id/v1/cameras/{camera}/live' \
  -H 'Authorization: Bearer $LARIKA_KEY' \
  -H 'content-type: application/json' \
  -d '{"quality":"sub"}'
Jawaban
200
{
  "url": "wss://cctv.example.com/live/9xQ…",
  "expiresAt": "2026-10-06T07:04:20.000Z"
}
POST/v1/cameras/{camera}/ptzPTZ move / stop

Move at a speed (−1…1) until you send all 0 (stop). Hold-to-move: a move on press, a stop on release. 409 camera_has_no_ptz on fixed cameras.

ParameterDiTipeKeterangan
id *pathstringCamera id (List cameras).
Contoh
curl -X POST 'https://cctv.larika.id/v1/cameras/{camera}/ptz' \
  -H 'Authorization: Bearer $LARIKA_KEY' \
  -H 'content-type: application/json' \
  -d '{"x":0,"y":0,"zoom":0}'
Jawaban
200
{
  "ok": true
}

Footage

GET/v1/cameras/{camera}/recordingsRecordings

Files on the node, newest first (1-minute MP4s). recording: true = the minute being written. from / to: epoch ms or ISO.

ParameterDiTipeKeterangan
id *pathstringCamera id (List cameras).
fromqueryms | ISOStart of the range.
toqueryms | ISOEnd of the range.
Contoh
curl -X GET 'https://cctv.larika.id/v1/cameras/{camera}/recordings' \
  -H 'Authorization: Bearer $LARIKA_KEY'
Jawaban
200
[
  {
    "file": "20261006-140400.mp4",
    "startedAt": 1791271440000,
    "endedAt": 1791271500000,
    "bytes": 1843200,
    "recording": false
  }
]
GET/v1/cameras/{camera}/recordings/{file}Download a recording

One file, streamed from the node (fragmented MP4: a minute still being written plays as far as it got). Logged in the access log.

ParameterDiTipeKeterangan
id *pathstringCamera id (List cameras).
file *pathstringfile from Recordings.
Contoh
curl -X GET 'https://cctv.larika.id/v1/cameras/{camera}/recordings/{file}' \
  -H 'Authorization: Bearer $LARIKA_KEY'
Jawaban
200 video/mp4
GET/v1/eventsEvents

Stored events, newest first. before = the at of the last one seen (cursor). clipPath = its video. Kept EVENT_RETENTION_DAYS (90).

ParameterDiTipeKeterangan
typequerystringe.g. person.detected
cameraIdquerystring
beforequeryms | ISO
limitquerynumber1–200, default 50
Contoh
curl -X GET 'https://cctv.larika.id/v1/events' \
  -H 'Authorization: Bearer $LARIKA_KEY'
Jawaban
200
[
  {
    "id": "cmuxe0001",
    "nodeId": "cmuwaprz30002kniwevk87652",
    "cameraId": "cmuwarje90004kniwsvv67q1u",
    "type": "person.detected",
    "at": "2026-10-06T07:04:20.000Z",
    "clipPath": "/v1/events/cmuxe0001/clip",
    "data": {
      "state": "start",
      "count": 1,
      "boxes": [
        [
          0.12,
          0.3,
          0.25,
          0.71
        ]
      ],
      "confidence": 0.81,
      "source": "node",
      "cameraName": "Ruang tamu",
      "snapshotId": "WC5Xq4jc7c1y",
      "snapshotUrl": "https://cctv.example.com/s/WC5Xq4jc7c1y.jpg"
    }
  }
]
GET/v1/events/{event}/clipEvent clip

The video of one event (MP4), cut from the recordings: pre s before it until post s after it — or after its end (motion.end, state: end) for things that last; ≤ 10 min. Needs the camera recording (MOTION keeps the minutes around events). Logged in the access log.

ParameterDiTipeKeterangan
id *pathstringEvent id (eventId in webhooks).
prequerysecondsdefault 10
postquerysecondsdefault 15
Contoh
curl -X GET 'https://cctv.larika.id/v1/events/{event}/clip' \
  -H 'Authorization: Bearer $LARIKA_KEY'
Jawaban
200 video/mp4

Webhook

Satu webhook per klien untuk semua node. Setiap permintaan membawa x-larika-event dan x-larika-webhook-key; cocokkan yang kedua dengan kunci webhook Anda.

KejadianKeterangan
motion.start / motion.end · motion.afterhoursPixel motion (whole picture); after-hours copy outside business hours.
zone.motion.start / endPixel motion inside a zone.
person.detected · vehicle.detected · face.detectedAI: `state` start (count, boxes) / end.
zone.enter · zone.exit · dwell.long · line.crossedAI: zones and counting lines.
sound.loud · sound.classifiedLoudness / what the sound is (glass, alarm, scream, …).
camera.tamper · lights.on / offCovered, blurred, moved; room lights.
intrusion · input.alarm · camera.motion · camera.eventThe camera’s own (ONVIF) events.
camera.online / offline · stream.frozen · stream.degraded · recording.gapCamera / video health.
camera.ip.changed · camera.clock.drift · camera.weak_password · camera.ptz.movedCamera health and security.
node.online / offline · node.clock.drift · disk.low · device.newThe node and its LAN.
{
  "id": "cmuwh0001",
  "event": "person.detected",
  "nodeId": "cmuwaprz30002kniwevk87652",
  "ts": 1791271460000,
  "data": {
    "state": "start",
    "count": 1,
    "boxes": [
      [
        0.12,
        0.3,
        0.25,
        0.71
      ]
    ],
    "confidence": 0.81,
    "source": "node",
    "cameraName": "Ruang tamu",
    "snapshotId": "WC5Xq4jc7c1y",
    "snapshotUrl": "https://cctv.example.com/s/WC5Xq4jc7c1y.jpg",
    "cameraId": "cmuwarje90004kniwsvv67q1u",
    "at": "2026-10-06T07:04:20.000Z",
    "eventId": "cmuxe0001",
    "clipPath": "/v1/events/cmuxe0001/clip",
    "afterHours": true
  }
}