API Documentation

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 — online or offline (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 ago
  • to (optional) — ISO-8601 end date (e.g. 2026-05-01), defaults to today
  • locationId (optional) — restrict to one location
  • cameraId (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 /reports
  • format (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_1 instead of pulling all cameras and filtering client-side.
  • Check licensed capacity. For “do I have headroom?” questions, call list_subscriptions AND list_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-log regularly to catch unauthorized changes.
  • Paginate ledger. The ledger can be large; use the cursor for 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

Save to list

Scroll to Top