Watch 0.39 API v1

Read Watch events and connect your system

Desktop event delivery

Send Watch notifications to another system

Configure a receiver in Watch, then confirm delivery with a test event. The operator chooses the system to notify; an integrator prepares the receiver and signing secret.

1. Prepare the receiver

Ask the receiving system’s maintainer for a URL reachable from the Watch host. Both sides need the same signing secret. Have the administrator configure it in Watch’s launch environment and supply its environment variable name, such as SENTINEL_CONNECTOR_SECRET. Keep the secret out of URLs and chat.

2. Create event delivery in Watch

  1. Open Settings → API & Integrations, then expand Advanced event delivery.
  2. Enter the integration name, receiver URL, and secret environment variable name. After creation, check for signed rather than secret missing.
  3. For the first test, select critical severity and the sdk.test event type. Use live.event for live alerts and select offline.event if offline-video events are needed.
  4. Once the receiver is ready, uncheck Create in dry-run first and select Create connector. A dry-run connector simulates delivery without sending an HTTP request.

3. Confirm an actual test delivery

Under Test end-to-end, select critical. A queued message means Watch accepted the test. Confirm that the receiver verified the signature and saved the event, and check Watch’s delivery record. If it does not arrive, check the sdk.test filter, dry-run status, secret availability, and receiver connectivity.

After the test, have the operator verify one real alert. A test notification checks delivery, not the camera, mission, or analysis accuracy. If an existing connector is dry-run, create a separate connector for actual delivery rather than treating simulated success as receipt.

Receiver format: sentinel.alert.v1

Event delivery created in the v0.39 desktop interface uses this format by default, with Content-Type application/cloudevents+json. Fields are at the top level, without a data wrapper. This shortened example uses illustrative values.

{
  "schema": "sentinel.alert.v1",
  "contract_version": 2,
  "specversion": "1.0",
  "id": "evt_example",
  "type": "sdk.test",
  "time": "2026-08-29T23:41:08Z",
  "state": "raised",
  "severity": "critical",
  "title": "Integration test",
  "summary": "Test event from Watch",
  "camera_id": null,
  "snapshot_url": null,
  "correlation_id": "evt_example"
}
Desktop sentinel.alert.v1 delivery differs from the sentinel.event.v1 returned by GET /v1/events. Validate the expected schema rather than applying the public Event shape directly. The existing Agent Alert Webhook channel’s schema: 2 is also a different format.

Verify the signature

X-Sentinel-Delivery-ID: whd_example
X-Sentinel-Event-ID: evt_example
X-Sentinel-Timestamp: 1788056468
X-Sentinel-Signature: v1=<hex HMAC-SHA256>
Idempotency-Key: whd_example

signed_bytes = utf8(timestamp) + b"." + raw_request_body
import crypto from "node:crypto";

export function verifyWatch(secret, timestamp, rawBody, signature) {
  if (!secret || typeof timestamp !== "string" ||
      typeof signature !== "string" || !Buffer.isBuffer(rawBody)) return false;
  const seconds = Number(timestamp);
  if (!Number.isInteger(seconds) || Math.abs(Date.now() / 1000 - seconds) > 300) return false;
  const expected = "v1=" + crypto.createHmac("sha256", secret)
    .update(timestamp + ".").update(rawBody).digest("hex");
  const actualBytes = Buffer.from(signature);
  const expectedBytes = Buffer.from(expected);
  return actualBytes.length === expectedBytes.length &&
    crypto.timingSafeEqual(actualBytes, expectedBytes);
}

Preserve the raw body and verify the timestamp and signature before parsing JSON. Require schema sentinel.alert.v1 and specversion 1.0. Check that X-Sentinel-Event-ID matches the body id and Idempotency-Key matches X-Sentinel-Delivery-ID. Desktop sends a signature only when the secret is available; reject unsigned requests.

Retries and images

Notifications may be retried. Deduplicate by delivery ID, save the event, and return 2xx promptly. Your business workflow should also avoid processing the same event twice. Inspect retries and delivery records in Watch; the public read-only API does not manage them.

snapshot_url belongs to the desktop compatibility interface and should not be used directly with the LAN API. For images, use an events:read key to retrieve the same id through GET /v1/events/{event_id}, then download any available evidence.image_url.

Read events and snapshots