---
title: "Notify Camera View Flags Site"
method: POST
path: "/camera-health/flags/notify-site"
tags: ["camera-health"]
---

# Notify Camera View Flags Site

`POST /camera-health/flags/notify-site`

## Request

- Base URL: `https://api.verdun.ai` (the document declares no server; this is the origin it was published from)
- URL: `https://api.verdun.ai/camera-health/flags/notify-site`
- Auth: HTTP bearer

ONE e-mail about several cameras at one site, one message per recipient,
each camera's newest checked frame attached. Items must be in scope (404),
at one site (400) and open or confirmed (409); open items are confirmed by
the send, and only once at least one message was accepted. Same e-mail
rules as /{flag_id}/notify (503 EMAIL_NOT_CONFIGURED, 502 when nothing was
accepted). Activity-logged per item, with counts, never addresses.

## Request body

- NotifyCameraViewFlagsSiteRequest
  - `flag_ids` string[], required: The items this e-mail covers, 1-12, all at ONE site and each open or confirmed. Open items are confirmed by the send. Each camera's newest checked frame is attached, in this order.
  - `recipients` string[], required: Addresses to e-mail, 1-10 (one message each, no CC); syntax-checked only.
  - `subject` string, required: E-mail subject, 1-200 characters.
  - `body` string, required: Plain-text e-mail body, 1-5000 characters.

## Response `200`

Successful Response

- NotifyCameraViewFlagsSiteResponse
  - `sent` string[], required: Recipients SES accepted.
  - `rejected` string[], required: Recipients SES rejected or could not confirm; do not assume these were delivered or undelivered.
  - `flags` CameraViewFlag[], required: The items after the send was recorded, in request order. An item deleted or no longer in the caller's scope is omitted; its send is still recorded.
    - `id` string, uuid, required: Flag id.
    - `status` string, required: 'open' (needs a look), 'confirmed' (an operator agreed the view is blocked), 'cleared' (an operator judged it usable), or 'resolved' (two checks hours apart read clear after confirmation and customer notification).
    - `camera_id` string, uuid, required: Camera row id.
    - `camera_label` string, nullable: Operator-facing camera name.
    - `site_id` string, uuid, required: Site id.
    - `site_name` string, nullable: Site name.
    - `site_timezone` string, nullable: The site's IANA zone, for rendering times and the day/night split.
    - `parent_id` string, uuid, required: Client (parent) id.
    - `parent_name` string, nullable: Client company name.
    - `kind` string, nullable: The latest qualifying verdict's kind.
    - `coverage_pct` integer, nullable: The latest qualifying verdict's coverage, 0-100.
    - `reason` string, nullable: The latest qualifying verdict's explanation.
    - `opened_at` string, date-time, required: When the item opened.
    - `opened_kind` string, nullable: Immutable kind at opening; null for legacy items.
    - `opened_coverage_pct` integer, nullable: Immutable coverage at opening; null for legacy items.
    - `opened_reason` string, nullable: Immutable reason at opening; null for legacy items.
    - `opening_checks` CameraViewFlagCheck[]: The two opening verdicts, preserved after sample pruning. Images may expire.
      - `sample_id` string, uuid, nullable: The health sample this verdict was recorded on. Null only on a legacy opening verdict saved without it.
      - `received_at` string, date-time, nullable: When the server received the judged frame, frozen at claim time (view_frame_received_at). Ordering and the 7-day window use this, never the worker's capture clock.
      - `checked_at` string, date-time, required: When the AI verdict was recorded.
      - `captured_at` string, date-time, required: Worker clock at capture of the judged frame (display only; ordering uses the server's receipt time).
      - `light` string, required: 'day' when the frame arrived between 07:00 and 18:59 site-local time, else 'night'. Night haze and IR glare are the common false raises.
      - `obstructed` boolean, nullable: The model's verdict for this frame.
      - `kind` string, nullable: none, object, dirty_lens, web_or_insect, water_or_condensation, glare, out_of_focus, or other.
      - `coverage_pct` integer, nullable: Roughly how much of the frame is covered, 0-100.
      - `reason` string, nullable: The model's one-sentence explanation.
      - `snapshot_url` string, nullable: Presigned GET URL for the judged frame (1h). Null when the frame has no stored image or presigning failed.
    - `first_viewed_at` string, date-time, nullable: First actual item open by staff; list polling does not count.
    - `resolved_at` string, date-time, nullable: When two clear checks resolved a confirmed, notified item.
    - `last_raised_at` string, date-time, required: When a confirmed raise last refreshed it.
    - `raise_count` integer, required: Confirmed raises counted on this item (1 at opening).
    - `checks_obstructed` integer, required: View checks of this camera in the last 7 days that qualified (obstructed, not glare, coverage at or above view_obstructed_coverage_min). Rendered as 'N of M checks in the last 7 days'.
    - `checks_total` integer, required: All view checks of this camera in the last 7 days (the same set as checks, uncapped).
    - `day_snapshot_url` string, nullable: Presigned URL of the newest checked daylight frame (07:00-18:59 site-local), null if none in the last 7 days.
    - `night_snapshot_url` string, nullable: Presigned URL of the newest checked night frame, null if none in the last 7 days.
    - `checks` CameraViewFlagCheck[], required: Up to 24 newest checks of this camera in the last 7 days, newest first.
      - `sample_id` string, uuid, nullable: The health sample this verdict was recorded on. Null only on a legacy opening verdict saved without it.
      - `received_at` string, date-time, nullable: When the server received the judged frame, frozen at claim time (view_frame_received_at). Ordering and the 7-day window use this, never the worker's capture clock.
      - `checked_at` string, date-time, required: When the AI verdict was recorded.
      - `captured_at` string, date-time, required: Worker clock at capture of the judged frame (display only; ordering uses the server's receipt time).
      - `light` string, required: 'day' when the frame arrived between 07:00 and 18:59 site-local time, else 'night'. Night haze and IR glare are the common false raises.
      - `obstructed` boolean, nullable: The model's verdict for this frame.
      - `kind` string, nullable: none, object, dirty_lens, web_or_insect, water_or_condensation, glare, out_of_focus, or other.
      - `coverage_pct` integer, nullable: Roughly how much of the frame is covered, 0-100.
      - `reason` string, nullable: The model's one-sentence explanation.
      - `snapshot_url` string, nullable: Presigned GET URL for the judged frame (1h). Null when the frame has no stored image or presigning failed.
    - `recent_alarms` CameraViewFlagAlarm[], required: Up to 5 newest alarms on this camera since 24 hours before opened_at, newest first.
      - `event_id` string, uuid, required: Alarm (event) id.
      - `at` string, date-time, required: When the alarm was created.
      - `incident_type` string, nullable: The AI's incident type, null when no interpretation landed.
      - `outcome_label` string, required: History's outcome wording: the operator disposition label, 'Auto-dismissed' for the agent's dismissals, 'Expired' for one that aged out unreviewed, else 'Pending'.
      - `auto_dismissed` boolean, required: True when the agent dismissed it.
    - `confirmed_by_name` string, nullable: Who confirmed it.
    - `confirmed_at` string, date-time, nullable: When it was confirmed.
    - `notified_at` string, date-time, nullable: When the customer was last e-mailed about it.
    - `notified_by_name` string, nullable: Who sent that e-mail.
    - `notify_summary` string, nullable: What that send did.
    - `cleared_by_name` string, nullable: Who cleared it.
    - `cleared_at` string, date-time, nullable: When it was cleared.
    - `clear_reason` string, nullable: The operator's reason for clearing.
    - `quiet_until` string, date-time, nullable: After a clear: no new flag for this camera before this time unless coverage rises by view_flag_worse_by_pct.
    - `contacts` CameraViewFlagContact[], required: The site's contacts with an e-mail address (falling back to the client's primary contact), for seeding recipients.
      - `name` string, required: Contact name.
      - `role` string, nullable: The contact's role at the site; 'Primary contact' for the client fallback.
      - `email` string, required: A deliverable-looking address on file.

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/verdun/apis/verdun-api.md) - [All operations](https://skmtc.dev/verdun/apis/verdun-api/llms.txt) - [OpenAPI document](https://skmtc.dev/verdun/apis/verdun-api/revisions/35a2a6ebedda?raw)
