Partner integration
Quick integration: receive Watch events
This guide covers integrations where Watch manages cameras and monitoring rules, and your existing system receives alerts. After deployment, configure sources, rules and notification endpoints in the Web GUI. Receive webhooks and query events or images when needed.
Deploy Docker → Configure in the Web GUI → Receive events
Download the example (Python source, Compose overlay and instructions)
Basic integration: provide a backend webhook receiver for Watch POST notifications. GET queries are optional. Receiving alerts does not require implementing camera or rule configuration APIs. Jump to POST / GET examples ↓
Do you need RTSP or other APIs?
RTSP carries video from the camera to Watch. Enter a reachable RTSP URL in the GUI; the event receiver does not need to process video streams. A VMS without a compatible RTSP source requires a separate integration assessment.
The installer still configures model credentials, signing secrets and network allowlists in the server environment. The GUI handles day-to-day source, monitoring-rule and notification-endpoint settings.
Managing cameras in bulk, changing rules, controlling Watch or embedding its interface from your product requires a separate review of the full API and authentication. This guide covers event delivery and retrieval; validate capture, model behavior and delivery at the target site before launch.
What do you receive? Event output and fields
Watch sends event JSON by HTTP POST to your configured webhook URL. This shortened alert example shows common fields; IDs, time and content are illustrative.
{
"id": "evt_example",
"schema": "sentinel.event.v1",
"type": "monitor.alert.raised",
"severity": "critical",
"state": "raised",
"created_at": "2026-09-07T12:00:00Z",
"source_id": "src_camera03",
"monitor_id": "mon_restricted_area",
"title": "Person entered restricted area",
"summary": "Camera 03 detected a person entering the specified area.",
"evidence": {
"image_url": "/v1/events/evt_example/image"
}
}| Field | Meaning |
|---|---|
| id | Event ID; state updates may share this ID. |
| type | What happened, such as monitor.alert.raised. |
| severity | Severity: safe, suspicious, or critical. |
| state | Lifecycle: raised, updated, or cleared. |
| created_at | Event creation time (ISO 8601). |
| source_id / monitor_id | Source and monitor IDs; may be null for system events. |
| title / summary | Human-readable text; use typed fields for alarm logic. |
| evidence.image_url | Evidence image location, when available; requires an events:read API key. |
Common types include monitor.alert.raised, monitor.alert.updated, monitor.alert.cleared, source.disconnected and inference.failed. Delivery depends on your webhook filters; critical + raised alone does not include all updates or cleared notifications.
Verify the signature, persist the event and return 2xx. Deduplicate retries using the X-Sentinel-Delivery-ID HTTP header, not just the event ID. Webhooks do not deliver every ordinary inference.
1. Start Watch and the example receiver
Obtain the current Sentinel source deployment kit from Tensor Dynamics and install Docker Compose v2 and Python 3. Extract the example into the kit root, preserving the deploy/ and docs/ paths. This example uses a reachable RTSP camera and Gemini; inference images go to the cloud model and use your API quota.
cd deploy/api
./bootstrap.sh cloud_geminiRun bootstrap only for a fresh deployment; keep an existing .env. Edit these values in .env, replacing the camera address and port. Keep the generated API key and webhook signing secret.
SENTINEL_GEMINI_API_KEY=your-gemini-api-key
SENTINEL_RTSP_ALLOWED_HOSTS=10.40.8.21:554
SENTINEL_WEBHOOK_ALLOWED_HOSTS=partner-receiver:9090docker compose -f docker-compose.yml -f partner-webhook.compose.yml --profile ui up -d --buildThis builds the API and console from the kit and starts the receiver on the same Docker network. Use a private model · Deployment options
2. Configure the camera and rule in the Web GUI
- On the server, open http://localhost:3000. Leave API base URL blank, enter SENTINEL_API_KEY from .env, and select Connect and verify. Use an SSH tunnel or protected reverse proxy for remote access.
- In Sources, add the RTSP camera, test the connection and check the preview.
- In Monitors, select the camera, describe the condition—for example, notify when a person enters a restricted area—then enable and test the monitor. Validate the model on representative site images.
3. Receive the first webhook
In Webhooks, add an endpoint with these values:
Name: Partner receiver
Destination URL: http://partner-receiver:9090/events
Signing secret environment variable: SENTINEL_WEBHOOK_SIGNING_SECRET
Enabled: on
Dry run: off
Severity: critical
State: raisedThe signing-secret field takes the environment variable name, not the secret value. Leave event types, source IDs and monitor IDs unrestricted for the first test. Save, select Test signed delivery and use critical severity.
docker compose -f docker-compose.yml -f partner-webhook.compose.yml logs --tail=20 partner-receiverAn accepted log with evt_… and whd_… means the receiver verified the signature and committed the event to SQLite. Next, trigger the monitoring condition and confirm a real alert arrives. The test notification verifies delivery, not camera or model acceptance.
How to receive events: POST delivery and GET queries
| Method | Direction | Use |
|---|---|---|
| POST /events | Watch → your receiver | Automatic alert delivery (recommended) |
| GET /v1/events | Your system → Watch | Query stored events |
A. POST: receive notifications in your system
Your backend provides a URL that accepts POST, such as /events. Watch sends the event JSON above in the request body when a matching event occurs. This is the flow implemented by the downloadable Python receiver:
# Inside the receiver's do_POST handler (shortened)
raw = self.rfile.read(length)
event = verify(raw, self.headers, secret)
fresh = accept(database, event, self.headers["X-Sentinel-Delivery-ID"], raw)
self.send_response(204)
self.end_headers()This is an excerpt; download the complete source for verify, accept, request bounds and error handling. verify checks HMAC; accept commits to SQLite and deduplicates. Return 204 after storage succeeds, then process the inbox in your alarm workflow.
Download the full POST receiver (Python 3.11+, no dependencies)
The receiver is already running if you followed the Compose steps. To run it without Docker, set the same signing secret as Watch on the receiver host, then start it:
# Set these in the receiver's environment / secret manager:
# SENTINEL_WEBHOOK_SIGNING_SECRET = same secret as Watch
# RECEIVER_HOST = 0.0.0.0
# RECEIVER_PORT = 9090
python3 partner_webhook_receiver.pyEnter the receiver URL in Watch's Webhooks screen: http://partner-receiver:9090/events for the Compose example, or your HTTPS URL for a remote production receiver. Select Test signed delivery and look for accepted in the receiver logs. Do not put the Watch API key in this URL.
B. GET: query Watch from your system
Your system sends GET and Watch returns JSON; Watch does not push notifications with GET. Run these commands on the Watch server, or replace the base URL with its protected HTTPS address. Set SENTINEL_API_KEY in your environment to a key with events:read permission.
# Query a page of stored events
curl --fail-with-body 'http://localhost:8000/v1/events?limit=10' \
-H "Authorization: Bearer $SENTINEL_API_KEY"The response wraps events in data. Each item uses the event shape above; this example shows an empty list:
{
"object": "list",
"data": [],
"has_more": false,
"next_cursor": null
}If has_more is true, pass next_cursor unchanged as after to fetch the next page. Do not construct cursors. This is pagination: the final next_cursor may be null, so it is not a permanent polling checkpoint. Use webhooks for ongoing delivery.
# Set NEXT_CURSOR to the returned next_cursor value
curl --fail-with-body --get 'http://localhost:8000/v1/events' \
-H "Authorization: Bearer $SENTINEL_API_KEY" \
--data-urlencode "after=$NEXT_CURSOR" \
--data-urlencode 'limit=10'
# Set EVENT_ID to a real id from data[] or a webhook
curl --fail-with-body "http://localhost:8000/v1/events/$EVENT_ID" \
-H "Authorization: Bearer $SENTINEL_API_KEY"
# Download evidence when the event has an image
curl --fail "http://localhost:8000/v1/events/$EVENT_ID/image" \
-H "Authorization: Bearer $SENTINEL_API_KEY" \
--output event.jpgSuccessful queries return 200. For 401, check the API key; for 403, check events:read permission; for 404, check the event ID or image availability. The POST signing secret and GET API key serve different purposes.
Connect your own system
The example verifies, deduplicates and stores events. Connect its inbox to your alarm list or workflow using typed fields such as type, severity and state, rather than parsing model prose. Webhooks carry alerts and errors, not every ordinary inference.
For production, use HTTPS, share the signing secret with Watch, verify the original request body and return 2xx promptly after durable acceptance. Deduplicate retries by delivery ID; different deliveries for one event may be state updates. Add business processing, retention and capacity planning to the SQLite example.
Full webhook contract · Production deployment · Build your own settings UI: full API