Desktop event delivery
Send Watch notifications to another system
Use with AI
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
- Open Settings → API & Integrations, then expand Advanced event delivery.
- Enter the integration name, receiver URL, and secret environment variable name. After creation, check for signed rather than secret missing.
- 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.
- 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"
}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_bodyimport 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.