---
title: "Create Ai Eval"
method: POST
path: "/eval/ai"
tags: ["eval"]
---

# Create Ai Eval

`POST /eval/ai`

## 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/ai`
- Auth: API key in header `X-API-Key`

## Request body

- CreateAIEvalRequest
  - `schema_version` string, required: Schema version
  - `tenant_id` string, uuid, required: Tenant ID
  - `site_id` string, uuid, required: Site ID
  - `camera_id` string, uuid, required: Camera ID
  - `clip_id` string, uuid, required: Clip ID
  - `job_id` string, required: Job ID
  - `detections` DetectionModel[], required: Detections
    - `provider` string, required: Detection provider
    - `provider_version` string, required: Detection provider version
    - `bbox` BboxModel, required
      - `x1` number, required: Bounding box top-left x coordinate
      - `y1` number, required: Bounding box top-left y coordinate
      - `x2` number, required: Bounding box bottom-right x coordinate
      - `y2` number, required: Bounding box bottom-right y coordinate
    - `class_label` string, required: Detected class label
    - `confidence` number, nullable, required: Detection confidence score; null = the producer made no calibrated claim about this box (ii InterpretationResultV1). Required-nullable: an omitted field is still a validation error.
    - `frame_index` integer, required: Frame index
    - `timestamp_ms` integer, required: Timestamp in milliseconds
    - `track_id` string, nullable: Track ID for object tracking
  - `roi_hits` ROIHitModel[], required: ROI hits
    - `roi_id` string, required: ROI ID
    - `bbox` BboxModel, required
      - `x1` number, required: Bounding box top-left x coordinate
      - `y1` number, required: Bounding box top-left y coordinate
      - `x2` number, required: Bounding box bottom-right x coordinate
      - `y2` number, required: Bounding box bottom-right y coordinate
    - `confidence` number, nullable, required: Confidence score; null = the producer made no calibrated claim about this hit (ii InterpretationResultV1). Required-nullable: an omitted field is still a validation error.
    - `frame_index` integer, required: Frame index
    - `timestamp_ms` integer, required: Timestamp in milliseconds
    - `source_provider` string, nullable: Provider of the detection this ROI hit was derived from, e.g. 'deepalert' | 'gpt-4o-vision'. Null on rows written before ii emitted it.
  - `keyframes` KeyframeModel[], required: Keyframes
    - `frame_index` integer, required: Frame index
    - `timestamp_ms` integer, required: Timestamp in milliseconds
    - `role` 'pre' | 'early' | 'trigger' | 'late' | 'post', required
    - `image_ref` string, required: Image reference
    - `detections` DetectionModel[], required: Detections
      - `provider` string, required: Detection provider
      - `provider_version` string, required: Detection provider version
      - `bbox` BboxModel, required
        - `x1` number, required: Bounding box top-left x coordinate
        - `y1` number, required: Bounding box top-left y coordinate
        - `x2` number, required: Bounding box bottom-right x coordinate
        - `y2` number, required: Bounding box bottom-right y coordinate
      - `class_label` string, required: Detected class label
      - `confidence` number, nullable, required: Detection confidence score; null = the producer made no calibrated claim about this box (ii InterpretationResultV1). Required-nullable: an omitted field is still a validation error.
      - `frame_index` integer, required: Frame index
      - `timestamp_ms` integer, required: Timestamp in milliseconds
      - `track_id` string, nullable: Track ID for object tracking
  - `incident_type` 'INTRUSION' | 'TAILGATING' | 'FIGHTING' | 'ARMED_ROBBERY' | 'VEHICLE_THEFT' | 'FIRE' | 'LOITERING' | 'PACKAGE_LEFT' | 'MAINTENANCE' | 'DELIVERY' | 'MULTI_PERSON' | 'LOW_LIGHT_ACTIVITY' | 'HEIGHTENED_ACTIVITY' | 'PERSON_DOWN' | 'NORMAL' | 'UNKNOWN', required
  - `severity` 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL', required
  - `confidence_band` 'LOW' | 'MEDIUM' | 'HIGH', required
  - `suggested_disposition` 'ESCALATE' | 'MONITOR' | 'DISMISS' | 'NEEDS_REVIEW', required
  - `recommended_action` 'false_alarm' | 'non_threatening' | 'escalate_voice_down' | 'escalate_dispatch'
  - `matched_exception` string, nullable: Heightened monitoring: the site exception label the AI cited when clearing human activity as non-threatening; absent from older pipelines and outside heightened windows
  - `subjects` SubjectDescriptorRequest[]: Visible person/vehicle appearance descriptors for conservative cross-camera matching
    - `kind` 'person' | 'vehicle', required
    - `confidence_band` 'LOW' | 'MEDIUM' | 'HIGH', required
    - `attributes` string[]
    - `description` string, nullable
  - `needs_human_review` boolean, required: Whether human review is needed
  - `rationale` string, required: Rationale for the result
  - `llm_provider` string, required: LLM provider
  - `llm_model` string, required: LLM model
  - `llm_prompt_version` string, required: LLM prompt version
  - `detection_provider` string, required: Detection provider
  - `detection_model_version` string, required: Detection model version
  - `pipeline_version` string, required: Pipeline version
  - `roi_config_version` string, required: ROI config version
  - `failovers` FailoversModel[], required: Failover events
    - `provider` string, required: Provider that failed
    - `reason` string, required: Reason for failover
    - `fallback_target` string, required: Fallback target used
  - `decode_ms` integer, required: Decode time in ms
  - `detect_ms` integer, required: Detection time in ms
  - `llm_ms` integer, required: LLM time in ms
  - `total_ms` integer, required: Total processing time in ms
  - `cost_usd` union, required: Cost in USD
    - number
    - string
  - `debug` object, nullable: Debug information
  - `terminal_stage` string: 'interpretation' | 'object_gate' — see round-0b design §7
  - `gate_outcome` GateOutcomeModel: DeepAlert Phase B (round-0b design §7): typed reason the object-of-interest gate stopped before a full interpretation ran. Populated only when CreateAIEvalRequest.terminal_stage == "object_gate". reason is plain str, NOT a closed Literal/enum, on purpose (round-0 design §1.2 in verdun/scratch/handoff/deepalert-phase-b-api/): ii owns and pins the closed set of reason values at the source (contracts/interpretation_result_v1.py); re-closing it here would mean a future ii-added reason value 422s /eval/ai ingestion instead of landing the row. Known values as of this writing: no_object_of_interest, detector_error, detector_timeout, fire_screen_error, misconfigured_detection_config. detector_confidence keeps ii's original strictness (Codex stage-4b review, finding 2, CONFIRMED): a finite value in [0, 1], never NaN/inf/>1, matching contracts/common_v1.NormalizedFloat.
    - `reason` string, required: Typed reason the object-of-interest gate stopped before a full interpretation ran
    - `detector_provider` string, required: Which detector/stage produced this outcome, e.g. 'deepalert' | 'fire_screen' | 'none'
    - `detector_confidence` number, nullable: Detector confidence at the decisive stage, when available. Finite [0, 1] — rejects bool, out-of-range, NaN, and infinity.
  - `detection_stages` DetectionStageModel[], nullable: Itemized per-stage breakdown of the detection/gate cascade, when available
    - `stage` string, required: 'object_detection' | 'fire_screen' | 'interpretation'
    - `provider` string, required: Stage provider
    - `model` string, required: Stage model identifier
    - `ran` boolean, required: Whether this stage actually executed. Strict bool — a string/int is rejected, not coerced.
    - `outcome` string, required: Stage outcome, e.g. 'alerted', 'not_alerted', 'error', 'timeout'
    - `latency_ms` integer, required: Stage latency in milliseconds. Strict, non-negative int — no float/string coercion.
    - `cost_usd` union, required: Stage cost in USD. Non-negative Decimal, parsed only from a Decimal or a decimal string — never a float.
      - number
      - string
  - `backup_assessment` unknown

## Response `200`

Successful Response

- object

## 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)
