Our Sentinel Watch API
The Sentinel Watch REST API provides programmatic access to your account, locations, cameras, staff, wallet, reports, and configuration. All requests require authentication via a Bearer token (Firebase ID token for app/authorized clients, or a customer API token for third-party integrations).
Authentication
All API requests require a valid authentication token in the Authorization header:
Authorization: Bearer YOUR_JWT_TOKEN
Token Types:
- Firebase ID token — issued on login to mobile/web clients, valid for 1 hour, auto-refresh built-in
- API token — for third-party or server-to-server integrations, issued in your account settings, no expiration unless revoked
- Customer token — shared credentials for integrations (e.g. Zapier, Make.com), includes role-based scopes
Base URL: https://api.sentinel.watch
Rate Limiting
All endpoints enforce rate limits to ensure fair usage and platform stability:
- Read endpoints — 100 requests per 60 seconds per API token
- Write endpoints — 10 requests per 60 seconds per API token
- Rate limit headers: Check response headers
X-RateLimit-Limit,X-RateLimit-Remaining,X-RateLimit-Reset
Exceeding the limit returns 429 Too Many Requests with Retry-After header.
Common Response Format
All endpoints return JSON:
// Success (2xx)
{
"ok": true,
"data": { /* endpoint-specific payload */ }
}
// Error (4xx, 5xx)
{
"ok": false,
"error": {
"code": "FIELD_ERROR | AUTH_ERROR | TENANT_ERROR | RATE_LIMIT",
"message": "Human-readable error description"
}
}
Core Concepts
Locations
A location is a physical place you manage (office, warehouse, storefront, residence). Each location can have multiple cameras.
- owned by — your account
- permissions — your role (Owner / Manager / Worker) determines what you can read and edit
- timezone — affects schedule interpretation and report aggregation
Cameras
A camera is assigned to exactly one location. Each camera has:
- status —
onlineoroffline(you control this; offline cameras don’t receive reports) - hourly rate — Sentinos per hour paid to watchers (you set this; higher rates = more viewer engagement)
- schedule — weekly availability (Mon–Sun, with time ranges and exceptions for holidays/maintenance)
- attention-check settings — optional periodic checks to ensure watchers stay engaged (reward / penalty / max failures)
- events — configured incident types (theft, vandalism, medical emergency) with bounties and cooldown periods
Wallet & Sentinos
Your wallet holds two currencies:
- Watch Credits — pre-loaded capacity; consumed by hourly camera rates as watchers view
- Sentinos — rewards earned from platform activities (affiliate revenue, partner payouts)
The ledger tracks all transactions: credits purchased, Sentinos earned, payouts to watchers, fees, and refunds.
Subscriptions (“Licenses”)
Your account holds active subscriptions that define your licensed capacity:
- Camera plan — max cameras you can register (e.g., 5, 10, 20, unlimited)
- Location plan — max locations (e.g., 2, 5, unlimited)
- Watch Credits plan — monthly recurring top-up amount
- Sentinos plan — optional monthly Sentinos allowance (partner payouts)
Important: Licensed capacity ≠ actual usage. Call both list_subscriptions (to get licensed limits) and list_cameras (to count actual cameras) to check headroom.
Read-Only Endpoints (GET)
GET /api/customer/me
Description: Returns your account identity, role, and permissions.
Query parameters: None
Response:
{
"ok": true,
"data": {
"customerId": "cust_abc123",
"email": "owner@example.com",
"displayName": "John Doe",
"role": "customer_owner", // customer_owner | customer_manager | customer_worker
"scopes": ["locations:read", "cameras:read", "cameras:write"],
"allowedLocations": ["loc_1", "loc_2"], // null = all locations
"createdAt": "2024-01-15T09:00:00Z"
}
}
GET /api/customer/locations
Description: Lists all locations your account owns.
Query parameters: None
Response:
{
"ok": true,
"data": {
"locations": [
{
"id": "loc_1",
"name": "Main Office",
"type": "commercial", // commercial | residential | other
"timezone": "America/New_York",
"address": "123 Main St, New York, NY",
"cameraIds": ["cam_1", "cam_2"], // Note: may be stale; use list_cameras for authoritative count
"createdAt": "2024-01-15T09:00:00Z"
},
{
"id": "loc_2",
"name": "Warehouse",
"type": "commercial",
"timezone": "America/Chicago",
"address": "456 Oak Ave, Chicago, IL",
"cameraIds": ["cam_3", "cam_4", "cam_5"],
"createdAt": "2024-02-20T14:30:00Z"
}
]
}
}
GET /api/customer/locations/{locationId}
Description: Full configuration for a single location.
Path parameters:
locationId— location post ID (e.g.loc_1)
Response includes: All fields from list_locations plus watcher/viewer coverage, schedule, and watchers assigned.
GET /api/customer/cameras
Description: Lists all cameras you own, optionally filtered by location.
Query parameters:
locationId(optional) — restrict to cameras at this location (e.g.?locationId=loc_1)
Response:
{
"ok": true,
"data": {
"cameras": [
{
"id": "cam_1",
"name": "Front Door",
"locationId": "loc_1",
"status": "online", // online | offline
"hourlyRate": 5000, // Sentinos per hour
"streams": {
"whepUrl": "https://stream.example.com/cam1/whep", // WebRTC endpoint
"hlsUrl": "https://stream.example.com/cam1/index.m3u8" // HLS fallback
},
"schedule": [
{ "days": ["Mon", "Tue", "Wed", "Thu", "Fri"], "startTime": "08:00", "endTime": "18:00", "is24Hours": false },
{ "days": ["Sat", "Sun"], "startTime": null, "endTime": null, "is24Hours": true }
],
"scheduleExceptions": [
{ "type": "whole-day", "date": "2026-07-04", "title": "Independence Day" }
],
"attentionCheck": {
"enabled": true,
"intervalMinutes": 30,
"rewardSentinos": 100,
"penaltySentinos": 50,
"maxFailures": 3
},
"events": [
{ "name": "Shoplifting", "bounty": 50000, "cooldownMinutes": 60 },
{ "name": "Vandalism", "bounty": 30000, "cooldownMinutes": 120 }
],
"createdAt": "2024-01-15T09:00:00Z"
},
// ... more cameras
]
}
}
GET /api/customer/cameras/{cameraId}
Description: Full detailed configuration for a single camera.
Same fields as list_cameras entry, plus:
- thumbnail URL
- current active watchers count
- last event timestamp
- AI hint / data classification
GET /api/customer/staff
Description: Lists all staff members on your account (Owners, Managers, Workers).
Response:
{
"ok": true,
"data": {
"staff": [
{
"uid": "user_abc123",
"email": "manager@example.com",
"displayName": "Alice Manager",
"role": "customer_manager",
"status": "active" // active | suspended
},
{
"uid": "user_def456",
"email": "worker@example.com",
"displayName": "Bob Worker",
"role": "customer_worker",
"status": "active"
}
]
}
}
GET /api/customer/wallet
Description: Returns current wallet balance.
Response:
{
"ok": true,
"data": {
"watchCredits": 50000, // total balance
"sentinos": 12500, // total balance
"currencyCode": "USD",
"lastUpdate": "2026-05-03T15:42:00Z"
}
}
GET /api/customer/wallet/ledger
Description: Transaction history (credits purchased, Sentinos earned, camera payouts, attention-check rewards, fees).
Query parameters:
limit(optional, 1-200, default 50) — number of entries to return
Response:
{
"ok": true,
"data": {
"entries": [
{
"id": "txn_xyz",
"direction": "credit", // credit | debit
"type": "purchase", // purchase | payout | attention_reward | hourly_rate | fee | refund
"amount": 100000, // Sentinos
"balanceBefore": 250000,
"balanceAfter": 350000,
"note": "Watch Credits purchase (monthly plan)",
"createdAt": "2026-05-03T14:22:00Z"
},
{
"id": "txn_uvw",
"direction": "debit",
"type": "hourly_rate",
"amount": 2500,
"balanceBefore": 350000,
"balanceAfter": 347500,
"note": "Hourly rate for cam_1 (1 hour @ 2500 Sentinos/hr)",
"createdAt": "2026-05-03T13:00:00Z"
}
]
}
}
GET /api/customer/subscriptions
Description: Your active SureCart subscription plans (licensed capacity).
Response:
{
"ok": true,
"data": {
"subscriptions": [
{
"id": "sub_1",
"name": "Camera Plan (10 seats)",
"type": "camera_plan",
"quantity": 10, // licensed capacity
"interval": "yearly",
"renewDate": "2025-01-15",
"status": "active"
},
{
"id": "sub_2",
"name": "Location Plan (5 seats)",
"type": "location_plan",
"quantity": 5,
"interval": "yearly",
"renewDate": "2025-02-20",
"status": "active"
},
{
"id": "sub_3",
"name": "Watch Credits (monthly)",
"type": "watch_credits",
"quantity": 50000, // Sentinos per month
"interval": "monthly",
"renewDate": "2026-06-03",
"status": "active"
}
],
"summary": {
"cameras": 10, // total licensed camera capacity
"locations": 5, // total licensed location capacity
"monthlyWatchCredits": 50000
}
}
}
GET /api/customer/market/benchmarks
Description: Aggregated market data showing how your hourly camera rates compare to platform-wide norms.
Response:
{
"ok": true,
"data": {
"benchmarks": {
"mediaIndustry": {
"median": 5000,
"p25": 3000,
"p75": 8000,
"yourMedian": 5500,
"percentile": 55
},
"yourOverallMedian": 5500,
"platformMedian": 4800,
"recommendation": "Your rates are competitive. Consider 4500–6500 Sentinos/hour for optimal engagement."
}
}
}
GET /api/customer/reports
Description: Aggregated reporting data (events reported, watch coverage minutes, attention-check results).
Query parameters:
from(optional) — ISO-8601 start date (e.g.2026-04-01), defaults to 30 days agoto(optional) — ISO-8601 end date (e.g.2026-05-01), defaults to todaylocationId(optional) — restrict to one locationcameraId(optional) — restrict to one camera
Response includes: events array, coverage hours, attention-check stats, hourly/daily breakdowns.
GET /api/customer/reports/export
Description: Export reports as CSV with presigned URL or inline data.
Query parameters:
from,to,locationId— same as /reportsformat(optional) —csv(default),json
Response: Presigned download URL or CSV body depending on size.
GET /api/customer/audit-log
Description: Audit trail of sensitive actions (staff role changes, config edits, token creation).
Query parameters:
limit(optional, 1-200, default 50)cursor(optional) — opaque pagination token from previous response
Response:
{
"ok": true,
"data": {
"entries": [
{
"id": "audit_xyz",
"action": "config_update",
"actor": "user_abc123",
"target": "cam_1",
"details": { "field": "hourlyRate", "oldValue": 5000, "newValue": 5500 },
"createdAt": "2026-05-03T10:15:00Z"
}
],
"nextCursor": "eyJpZCI6ImF1ZGl0X3d2In0="
}
}
Write Endpoints (PATCH)
All write endpoints require:
- Owner or Manager role
- Proper audit trail logging
- Confirmation workflow in the UI (proposal → user review → approval → execution)
PATCH /api/customer/cameras/{cameraId}/hourly-rate
Description: Update a camera’s hourly Sentino rate.
Request body:
{
"hourlyRate": 5500 // Sentinos per hour, 1-10000000
}
Response: Updated camera object with new rate.
PATCH /api/customer/cameras/{cameraId}/status
Description: Set a camera online or offline.
Request body:
{
"status": "offline" // online | offline
}
PATCH /api/customer/cameras/{cameraId}/attention-check
Description: Update attention-check settings (any subset).
Request body:
{
"enabled": true,
"intervalMinutes": 30,
"rewardSentinos": 100,
"penaltySentinos": 50,
"maxFailures": 3
}
PATCH /api/customer/cameras/{cameraId}/schedule
Description: Replace a camera’s full weekly schedule and exceptions.
Request body:
{
"schedule": [
{ "days": ["Mon", "Tue", "Wed", "Thu", "Fri"], "startTime": "08:00", "endTime": "18:00" },
{ "days": ["Sat", "Sun"], "is24Hours": true }
],
"scheduleExceptions": [
{ "type": "whole-day", "date": "2026-07-04", "title": "Independence Day" },
{ "type": "time-range", "days": ["Mon", "Tue"], "startTime": "12:00", "endTime": "13:00", "title": "Lunch break" }
]
}
Error Codes
| Code | HTTP Status | Description |
|---|---|---|
AUTH_ERROR |
401 | Invalid or expired token |
FORBIDDEN |
403 | Insufficient permissions (e.g., Worker trying to edit a camera) |
TENANT_ERROR |
403 | Camera/location belongs to a different account |
FIELD_ERROR |
400 | Invalid field value (e.g., hourlyRate out of range) |
NOT_FOUND |
404 | Camera, location, or staff member does not exist |
RATE_LIMIT |
429 | Too many requests; check Retry-After header |
CONFLICT |
409 | Resource already exists (e.g., duplicate camera name) |
SERVER_ERROR |
500 | Internal server error; retry with exponential backoff |
SDK & Integrations
Official SDKs:
- JavaScript / TypeScript — npm
@sentinel-watch/sdk - Python — pip
sentinel-watch - REST — curl, Postman, OpenAPI spec available
No-code integrations:
- Zapier — trigger on camera events, update rates
- Make.com — multi-step workflows
- Google Sheets — sync reports as CSV
Best Practices
- Use filters. Call
list_cameras?locationId=loc_1instead of pulling all cameras and filtering client-side. - Check licensed capacity. For “do I have headroom?” questions, call
list_subscriptionsANDlist_cameras; don’t assume licensed = actual. - Batch writes. If you’re updating multiple cameras, make multiple PATCH calls in parallel (respecting rate limits).
- Cache read results. Locations, cameras, and staff rarely change; cache for 5 minutes server-side.
- Monitor audit logs. Use
GET /api/customer/audit-logregularly to catch unauthorized changes. - Paginate ledger. The ledger can be large; use the
cursorfor pagination instead of pulling all 10,000 entries.
Support & Feedback
Questions or issues? Contact: api-support@sentinel.watch
View detailed API logs and debugging: Your account dashboard → Integrations → API Monitor