eval

Close out several queued alarms with one disposition

The site story's "Close all N". Every event is disposed under the single-event route's rules (tenant scope, disposition permission, one evaluation per event) in its own transaction; ids that could not be disposed come back in failed with the status the single route would have answered, and the rest still land. An alarm another operator holds a live claim on is refused per item with status 423 and code claim_held (never the 409 "already closed"): it stays queued and the others in the batch still close; the caller uses Take over first. Only the false-alarm and non-threatening dispositions are accepted (422 otherwise): a talk-down or a dispatch is decided against one clip on the single route.

post/eval/operator/bulk

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/eval/operator/bulk
  • Auth
    HTTP bearer

Request body

event_idsstring[] required

The queued events to close out with ONE disposition - the site story's "Close all N". Duplicates are collapsed. Each event is disposed in its own transaction under the same rules as the single-event route (tenant scope, disposition permission, one evaluation per event); the response reports every id that could not be disposed instead of failing the batch.

operator_disposition'False alarm - no human activity' | 'Escalate Dispatch' | 'Escalate Voice Down' | 'Non-threatening human activity' | 'Not monitored on this camera' required
notesstring required

The note written on every event's evaluation.

ai_feedback_event_idstring nullable

The ONE event the site story's AI-feedback question was about (owner 2026-10-03: "selected clip only"). Must be one of event_ids, and only with SUSPICIOUS_MONITOR. ai_feedback_asked on that event is decided by the same server rule as the single-event route (capture flag on, real VLM verdict); every other event stays unasked. Valid WITHOUT ai_feedback: the question was shown and left blank.

story_alarm_countinteger nullable

How many alarms the WHOLE site story closed, across every batch (the client splits a story into batches of at most 500). Only with ai_feedback_event_id; stored as provenance beside that event's answer. Omitted = stored as null (unknown); never inferred from this request's own count.

surface'site_bulk' | 'camera_bulk' | 'rail_bulk'

Which console surface sent a bulk close (POST /eval/operator/bulk). Written, verbatim, as the claim_log surface of every line of that call and nothing else. site_bulk (By site, Close all) is the default when the client sends nothing; the single-event close is always single and never uses this enum.

Example request

{
  "event_ids": [
    "6f1c1c1e-0000-4000-8000-000000000001"
  ],
  "notes": "Employee walking the lot, badged in at the side door.",
  "closeout": {
    "schema_version": 1,
    "observed": "Two people on foot crossing the west lot toward the loading dock.",
    "actions": [
      "reviewed_clip",
      "viewed_live",
      "called_owner"
    ],
    "outcome": "subject_left",
    "outcome_note": "delivery driver, left 22:41",
    "ai_feedback": {
      "reason": "benign_routine",
      "should_have_been": "LOITERING",
      "frame_ms": 4200
    }
  },
  "ai_feedback_event_id": "6f1c1c1e-0000-4000-8000-000000000001",
  "ai_feedback": {
    "reason": "benign_routine",
    "should_have_been": "LOITERING",
    "frame_ms": 4200
  },
  "story_alarm_count": 12
}

Response

Successful Response

disposedstring[] required

Event ids that now carry the disposition, in request order

request_idstring nullable

This call's id: the request= value on every claim_log line it wrote. A console can echo it as closes on POST /eval/operator/bulk/undo so the undo's log lines name the close they reverse. Log correlation only; absent from an older api.

Changes

No recorded changes to this operation across all 2 revisions of this API.