{
  "openapi": "3.1.0",
  "info": {
    "title": "Cerul API — Daily integration",
    "version": "1.0.0-foundation",
    "description": "Customer upload, indexing, search, export and resource management."
  },
  "servers": [
    {
      "url": "https://api.cerul.ai",
      "description": "Cloud runtime"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Videos",
      "description": "Video ingestion and lifecycle"
    },
    {
      "name": "Search",
      "description": "Search clips across your videos"
    },
    {
      "name": "Jobs",
      "description": "Asynchronous capability and workflow execution"
    },
    {
      "name": "Deletions",
      "description": "Asynchronous workspace-scoped cloud content erasure"
    }
  ],
  "paths": {
    "/videos": {
      "get": {
        "operationId": "listVideos",
        "x-cerul-required-scopes": [
          "videos:read"
        ],
        "summary": "List videos",
        "description": "Lists videos in the caller's workspace, newest first, including unfinished uploads. Returns at most `limit` videos (default 100, maximum 500); pass `next_cursor` back as `cursor` for the next page. `q` matches the filename or the video ID. Per-video `data[].indexing` is authoritative.",
        "tags": [
          "Videos"
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 512
            }
          },
          {
            "name": "q",
            "in": "query",
            "required": false,
            "description": "Case-insensitive filename substring or an exact video ID.",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Restrict to videos whose derived status is one of these values (comma separated).",
            "schema": {
              "type": "string",
              "pattern": "^(uploading|uploaded|processing|ready|failed)(,(uploading|uploaded|processing|ready|failed))*$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Videos in the workspace, newest first",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VideoListResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "post": {
        "operationId": "createVideo",
        "x-cerul-required-scopes": [
          "videos:write"
        ],
        "summary": "Add a video",
        "description": "Starts ingesting one video and returns it with a derived status. Supply\n`filename`, `media_type` and `byte_size` to upload bytes: the response\ncarries short-lived presigned PUT URLs in `upload.parts`. Upload each\nexact byte range with the returned headers, then call\nPOST /videos/{video_id}/complete. Maximum size is 5 GiB. A verified\nemail is required. Omit library_id to use the workspace default library.\nURL ingestion, including YouTube links, is not available; the reserved\n`url` form returns HTTP 503 `capability_unavailable`.\n",
        "tags": [
          "Videos"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateVideoRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Video accepted, with upload instructions when bytes are expected",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateVideoResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/videos/{video_id}/complete": {
      "post": {
        "operationId": "completeVideoUpload",
        "x-cerul-required-scopes": [
          "videos:write"
        ],
        "summary": "Complete a video upload",
        "description": "Confirms the uploaded bytes and starts indexing speech and visuals unless\n`index` is false. On-screen text is off by default; opt in with\nprocessing.screen_text.enabled and optionally\nprocessing.screen_text.interval_seconds (default 10). Indexing additionally\nrequires jobs:write, videos:read and files:write, a verified email\nand sufficient prepaid credits. Supply the actual duration and SHA-256.\nPoll GET /videos/{video_id} for ready, then inspect `indexing` per type;\nready does not guarantee every type succeeded. Exact\nIdempotency-Key replays return the original operation. Successful\nunique-material billing is deduplicated by `content_sha256`; a distinct\nvideo asset with the same bytes may still be processed independently.\n",
        "tags": [
          "Videos"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/VideoId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CompleteVideoRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Video with its derived status and index job",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VideoResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/videos/{video_id}/index": {
      "post": {
        "operationId": "indexVideo",
        "x-cerul-required-scopes": [
          "jobs:write",
          "videos:read",
          "collection-items:write",
          "files:write"
        ],
        "summary": "Index a video",
        "description": "Starts indexing speech and visuals for a video completed with index false, or re-indexes it. On-screen text is off unless processing.screen_text.enabled is true. Requires verified email and sufficient prepaid credits. Idempotent by Idempotency-Key for the same video; successful unique-material billing is deduplicated by content hash.",
        "tags": [
          "Videos"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/VideoId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IndexVideoRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Index job accepted or replayed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/videos/{video_id}/transcript": {
      "get": {
        "operationId": "getVideoTranscript",
        "x-cerul-required-scopes": [
          "videos:read"
        ],
        "summary": "Read a video transcript",
        "description": "Returns the whole transcript once indexing has succeeded, so a caller need not walk from the job to its artifacts.",
        "tags": [
          "Videos"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/VideoId"
          },
          {
            "name": "include",
            "in": "query",
            "required": false,
            "description": "`screen_text` also returns the on-screen text read from the video, merged into `segments` in time order with `type: screen_text`. Identical text on adjacent samples is collapsed into one segment. `text` stays speech only. A video without an audio track returns its on-screen text instead of `no_audio_track`.",
            "schema": {
              "type": "string",
              "enum": [
                "screen_text"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Transcript segments with timecodes",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TranscriptResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/videos/{video_id}": {
      "get": {
        "operationId": "getVideo",
        "x-cerul-required-scopes": [
          "videos:read"
        ],
        "summary": "Get a video",
        "description": "Returns the video with a status derived from its newest index job, so one poll answers whether it is searchable yet.",
        "tags": [
          "Videos"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/VideoId"
          }
        ],
        "responses": {
          "200": {
            "description": "Video",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VideoResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "delete": {
        "operationId": "deleteVideo",
        "summary": "Delete a video and reclaim its persisted storage",
        "description": "Accepts an idempotent asynchronous erasure of the video and all\ncloud-derived content and references. After safety preflight succeeds,\nthe video becomes unavailable immediately, active work is canceled or\nfenced by the deletion workflow, and storage quota is released only\nafter cleanup succeeds. A failed safety preflight has no tombstone or\ncancellation side effect.\nContent-free billing and security audit records may be retained. This\noperation never deletes or modifies local App content.\nReusing the same Idempotency-Key only replays the current receipt. If\na non-retryable safety preflight later becomes resolvable, a new key\nre-arms the same canonical deletion resource without losing completed\ncleanup phases.\n",
        "tags": [
          "Videos"
        ],
        "x-cerul-required-scopes": [
          "videos:write"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/VideoId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "202": {
            "description": "Video deletion accepted or idempotently replayed",
            "headers": {
              "Location": {
                "description": "Relative URL of the deletion status resource",
                "required": true,
                "schema": {
                  "type": "string",
                  "format": "uri-reference"
                }
              },
              "Cache-Control": {
                "description": "Deletion responses must not be cached",
                "required": true,
                "schema": {
                  "type": "string",
                  "example": "no-store"
                }
              },
              "Retry-After": {
                "description": "Suggested delay in seconds before refreshing deletion state",
                "required": true,
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResourceDeletionResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/exports": {
      "post": {
        "operationId": "createExport",
        "summary": "Export a time range of a video as an MP4 file",
        "description": "Starts an asynchronous export of one bounded time range. Poll GET /exports/{export_id}; once it succeeds, `file.url` downloads the MP4. Optionally pass the `clip_id` of a search result the range came from. Exports are not billed.",
        "tags": [
          "Videos"
        ],
        "x-cerul-required-scopes": [
          "jobs:write",
          "videos:read",
          "files:write"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ExportRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Export accepted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExportResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/exports/{export_id}": {
      "get": {
        "operationId": "getExport",
        "summary": "Get an export",
        "description": "Returns the export state. Pending exports include Retry-After. `file` is present once the export succeeded and until the file is deleted.",
        "tags": [
          "Videos"
        ],
        "x-cerul-required-scopes": [
          "jobs:read",
          "files:read"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ExportId"
          }
        ],
        "responses": {
          "200": {
            "description": "Export",
            "headers": {
              "Retry-After": {
                "description": "Suggested polling delay in seconds; present while the export is pending.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExportResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/exports/{export_id}/file": {
      "get": {
        "operationId": "getExportFile",
        "summary": "Download an exported MP4 file",
        "description": "Streams the exported MP4. Supports Range requests.",
        "tags": [
          "Videos"
        ],
        "x-cerul-required-scopes": [
          "files:read"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ExportId"
          },
          {
            "name": "Range",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "pattern": "^bytes=(?:[0-9]+-[0-9]*|-[0-9]+)$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "MP4 file",
            "content": {
              "video/mp4": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "206": {
            "description": "Partial MP4 content",
            "content": {
              "video/mp4": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/search": {
      "post": {
        "operationId": "search",
        "x-cerul-required-scopes": [
          "videos:read"
        ],
        "summary": "Search your videos",
        "description": "Returns the clips that best answer the query, across all videos in the workspace unless `filter.video_ids` narrows it. Requires a verified email and sufficient prepaid credits. Results are ordered by fused relevance; `score` is the raw similarity within the clip's own `type` and is not comparable across types or a correctness probability. When nothing is close enough the response has an empty `data` and the `no_confident_match` warning; that completed search is still billed. A search with no indexed videos is not billed. `playback.url` and `thumbnail_url` expire after one hour; store `console_url` instead. Reuse the same Idempotency-Key only with unchanged input.",
        "tags": [
          "Search"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SearchRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Search results",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SearchResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/jobs/{job_id}": {
      "get": {
        "operationId": "getJob",
        "x-cerul-required-scopes": [
          "jobs:read"
        ],
        "summary": "Get job state",
        "description": "Returns state and progress. Pending jobs include Retry-After; wait that many seconds before polling again. Failed jobs expose their asynchronous execution error.",
        "tags": [
          "Jobs"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/JobId"
          }
        ],
        "responses": {
          "200": {
            "description": "Job",
            "headers": {
              "Retry-After": {
                "description": "Suggested polling delay in seconds; present while the job is pending.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/jobs/{job_id}/cancel": {
      "post": {
        "operationId": "cancelJob",
        "x-cerul-required-scopes": [
          "jobs:write"
        ],
        "summary": "Request idempotent cancellation of a job",
        "description": "Queued cancellation releases unused prepaid reservations. Running jobs stop cooperatively, settle durable successful billable units, and release the remainder. Canceling a terminal job does not reverse completed usage.",
        "tags": [
          "Jobs"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/JobId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Job cancellation state",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/deletions/{deletion_id}": {
      "get": {
        "operationId": "getResourceDeletion",
        "x-cerul-required-scopes": [],
        "summary": "Get asynchronous cloud deletion state",
        "description": "Requires videos:write for a video deletion and files:write for a file deletion.",
        "tags": [
          "Deletions"
        ],
        "x-cerul-dynamic-required-scopes": "deletion_resource_type",
        "parameters": [
          {
            "$ref": "#/components/parameters/DeletionId"
          }
        ],
        "responses": {
          "200": {
            "description": "Workspace-scoped deletion state",
            "headers": {
              "Cache-Control": {
                "description": "Deletion status responses must not be cached",
                "schema": {
                  "type": "string",
                  "example": "no-store"
                }
              },
              "Retry-After": {
                "description": "Suggested polling delay in seconds while deletion is queued or running",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResourceDeletionResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/videos/{video_id}/content": {
      "get": {
        "operationId": "getVideoContent",
        "x-cerul-required-scopes": [
          "videos:read"
        ],
        "summary": "Stream authenticated source video",
        "tags": [
          "Videos"
        ],
        "description": "Downloads the original uploaded file. Requires videos:read. Supports a single HTTP byte range for seeking; content remains workspace private and unavailable after deletion. Full and ranged responses preserve the uploaded video's media type, represented by video/*; playback support depends on the client's container and codec support.",
        "parameters": [
          {
            "$ref": "#/components/parameters/VideoId"
          },
          {
            "in": "header",
            "name": "Range",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Private source video",
            "content": {
              "video/*": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "video/mp4": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "video/webm": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "206": {
            "description": "Requested byte range",
            "headers": {
              "Content-Range": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "video/*": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "video/webm": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "video/mp4": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "416": {
            "description": "Unsatisfiable byte range"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "VideoListResponse": {
        "unevaluatedProperties": false,
        "allOf": [
          {
            "$ref": "#/components/schemas/ResponseMetadata"
          },
          {
            "type": "object",
            "required": [
              "data"
            ],
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Video"
                }
              },
              "next_cursor": {
                "description": "Pass as `cursor` to read the next page; null on the last page.",
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          }
        ]
      },
      "ResponseMetadata": {
        "type": "object",
        "required": [
          "request_id",
          "usage",
          "warnings"
        ],
        "properties": {
          "request_id": {
            "$ref": "#/components/schemas/RequestId"
          },
          "usage": {
            "$ref": "#/components/schemas/Usage"
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "RequestId": {
        "type": "string",
        "pattern": "^req_[A-Za-z0-9]+$"
      },
      "Usage": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "billable",
          "quantity",
          "unit"
        ],
        "properties": {
          "billable": {
            "description": "True when this logical request is metered and consumes Cerul credits, whether funded by the one-time free grant or prepaid top-ups.",
            "type": "boolean"
          },
          "quantity": {
            "description": "Quantity metered synchronously for this response. Async submissions report zero and identify deferred settlement in usage_pending.",
            "type": "number",
            "minimum": 0
          },
          "unit": {
            "description": "Unit for quantity, such as request.",
            "type": "string"
          },
          "usage_pending": {
            "description": "Indicates that any metering happens when the accepted background job settles, not in this response.",
            "type": "string",
            "enum": [
              "background_job"
            ]
          }
        }
      },
      "Video": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "status",
          "playable",
          "indexing",
          "filename",
          "media_type",
          "byte_size",
          "duration_seconds",
          "summary",
          "summary_generated",
          "suggested_queries",
          "error",
          "created_at",
          "indexed_at",
          "index_job_id"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/VideoId"
          },
          "status": {
            "description": "Derived from the newest index Job, never stored. `ready` means that Job has a retained searchable index; an older successful index can still be searchable after a newer re-index fails.",
            "type": "string",
            "enum": [
              "uploading",
              "uploaded",
              "processing",
              "ready",
              "failed"
            ]
          },
          "playable": {
            "description": "Whether the web-playable copy is ready. A video can be playable before it is searchable.",
            "type": "boolean"
          },
          "indexing": {
            "description": "Per-type result for the newest retained index; null when the newest Job has no valid index, including after a failed re-index.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/VideoIndexing"
              },
              {
                "type": "null"
              }
            ]
          },
          "filename": {
            "type": [
              "string",
              "null"
            ]
          },
          "media_type": {
            "type": [
              "string",
              "null"
            ]
          },
          "byte_size": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "duration_seconds": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0
          },
          "summary": {
            "description": "One or two sentences generated from the transcript and on-screen text after indexing. Generated content; see summary_generated.",
            "type": [
              "string",
              "null"
            ],
            "maxLength": 600
          },
          "summary_generated": {
            "description": "True when summary was written by a model rather than taken from the video.",
            "type": "boolean"
          },
          "suggested_queries": {
            "description": "Up to six phrases from the video that make good searches.",
            "type": "array",
            "maxItems": 6,
            "items": {
              "$ref": "#/components/schemas/SuggestedQuery"
            }
          },
          "error": {
            "description": "Why indexing failed, when it did.",
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "indexed_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "index_job_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "upload": {
            "description": "Present only in the response that created the video, while bytes are still expected.",
            "$ref": "#/components/schemas/VideoUploadInstructions"
          }
        }
      },
      "VideoId": {
        "description": "A Video is the developer-facing name for a media Asset, and shares its identifier.",
        "type": "string",
        "pattern": "^asset_[A-Za-z0-9_-]+$"
      },
      "VideoIndexing": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "speech",
          "screen_text",
          "visual"
        ],
        "properties": {
          "speech": {
            "$ref": "#/components/schemas/VideoIndexingResult"
          },
          "screen_text": {
            "$ref": "#/components/schemas/VideoIndexingResult"
          },
          "visual": {
            "$ref": "#/components/schemas/VideoIndexingResult"
          }
        }
      },
      "VideoIndexingResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "status",
          "count",
          "reason"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "indexed",
              "absent",
              "failed"
            ]
          },
          "count": {
            "description": "Number of indexed units of this type.",
            "type": "integer",
            "minimum": 0
          },
          "reason": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "no_audio_track",
              "partial_failure",
              "asr_unavailable",
              "embedding_failed",
              "decode_failed",
              "model_unavailable",
              "startup_failed",
              "timeout",
              "oom",
              "invalid_output",
              "internal_error",
              "disabled",
              "no_text_detected",
              null
            ]
          },
          "failed_count": {
            "description": "Present only when status is indexed and reason is partial_failure; omitted for absent and failed outcomes.",
            "type": "integer",
            "minimum": 1
          }
        }
      },
      "SuggestedQuery": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "text",
          "type",
          "start_seconds"
        ],
        "properties": {
          "text": {
            "description": "A phrase taken verbatim from the video's transcript or on-screen text.",
            "type": "string",
            "minLength": 1,
            "maxLength": 160
          },
          "type": {
            "type": "string",
            "enum": [
              "speech",
              "screen_text"
            ]
          },
          "start_seconds": {
            "type": "number",
            "minimum": 0
          }
        }
      },
      "VideoUploadInstructions": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "method",
          "url",
          "required_headers",
          "expires_at",
          "parts"
        ],
        "properties": {
          "method": {
            "type": "string",
            "const": "PUT"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "required_headers": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "Content-Type",
              "Content-Length"
            ],
            "properties": {
              "Content-Type": {
                "type": "string",
                "minLength": 3,
                "maxLength": 127
              },
              "Content-Length": {
                "type": "string",
                "pattern": "^[1-9][0-9]{0,9}$"
              }
            }
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "parts": {
            "description": "Upload each part with its own PUT. A dropped connection costs one part, not the whole file. A small file has exactly one.",
            "type": "array",
            "minItems": 1,
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "part_number",
                "url",
                "byte_size"
              ],
              "properties": {
                "part_number": {
                  "type": "integer",
                  "minimum": 1,
                  "maximum": 10000
                },
                "url": {
                  "type": "string",
                  "format": "uri"
                },
                "byte_size": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            }
          }
        }
      },
      "ErrorEnvelope": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "request_id",
          "error"
        ],
        "properties": {
          "request_id": {
            "$ref": "#/components/schemas/RequestId"
          },
          "error": {
            "$ref": "#/components/schemas/ErrorDetail"
          }
        }
      },
      "ErrorDetail": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "code",
          "message",
          "retryable"
        ],
        "properties": {
          "code": {
            "type": "string",
            "enum": [
              "invalid_request",
              "invalid_credentials",
              "invalid_grant",
              "invalid_client",
              "unauthorized",
              "forbidden",
              "permission_denied",
              "already_exists",
              "session_expired",
              "not_found",
              "no_audio_track",
              "conflict",
              "authorization_pending",
              "slow_down",
              "access_denied",
              "expired_token",
              "capability_unavailable",
              "scope_violation",
              "data_egress_not_authorized",
              "insufficient_entitlement",
              "rate_limited",
              "internal_error"
            ]
          },
          "message": {
            "type": "string"
          },
          "retryable": {
            "type": "boolean"
          },
          "retry_after_seconds": {
            "description": "Suggested delay before retrying a throttled request, when supplied.",
            "type": "integer",
            "minimum": 1
          },
          "field": {
            "type": [
              "string",
              "null"
            ]
          },
          "details": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "CreateVideoRequest": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/CreateVideoFromUrlRequest"
          },
          {
            "$ref": "#/components/schemas/CreateVideoUploadRequest"
          }
        ]
      },
      "CreateVideoFromUrlRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "url"
        ],
        "properties": {
          "url": {
            "description": "Public source to fetch. Planned; currently answers capability_unavailable.",
            "type": "string",
            "format": "uri",
            "maxLength": 2048
          }
        }
      },
      "CreateVideoUploadRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "filename",
          "media_type",
          "byte_size"
        ],
        "properties": {
          "filename": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255
          },
          "media_type": {
            "type": "string",
            "minLength": 3,
            "maxLength": 127,
            "pattern": "^[Vv][Ii][Dd][Ee][Oo]/[A-Za-z0-9][A-Za-z0-9!#$&^_.+-]*$"
          },
          "byte_size": {
            "type": "integer",
            "minimum": 1,
            "maximum": 5368709120
          }
        }
      },
      "CreateVideoResponse": {
        "unevaluatedProperties": false,
        "allOf": [
          {
            "$ref": "#/components/schemas/ResponseMetadata"
          },
          {
            "type": "object",
            "required": [
              "data"
            ],
            "properties": {
              "data": {
                "$ref": "#/components/schemas/Video"
              }
            }
          }
        ]
      },
      "CompleteVideoRequest": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/CompleteVideoWithoutIndexRequest"
          },
          {
            "$ref": "#/components/schemas/CompleteAndIndexVideoRequest"
          }
        ]
      },
      "CompleteVideoWithoutIndexRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "index"
        ],
        "properties": {
          "duration_seconds": {
            "description": "Source duration, used for quota admission before transcription.",
            "type": "number",
            "minimum": 0
          },
          "content_sha256": {
            "description": "Declares source identity for upload completion. When indexing occurs, the Worker verifies it against the uploaded bytes and successful unique-material billing is deduplicated by this hash; a distinct video asset may still be processed independently.",
            "type": "string",
            "pattern": "^[a-fA-F0-9]{64}$"
          },
          "index": {
            "description": "Leave the uploaded video unindexed.",
            "type": "boolean",
            "const": false
          }
        }
      },
      "CompleteAndIndexVideoRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "duration_seconds",
          "content_sha256"
        ],
        "properties": {
          "duration_seconds": {
            "description": "Source duration, used for quota admission before transcription.",
            "type": "number",
            "exclusiveMinimum": 0
          },
          "content_sha256": {
            "description": "Declares source identity for indexing. The Worker verifies it against the uploaded bytes and successful unique-material billing is deduplicated by this hash; a distinct video asset may still be processed independently.",
            "type": "string",
            "pattern": "^[a-fA-F0-9]{64}$"
          },
          "index": {
            "description": "Start indexing once the upload is confirmed. Defaults to true.",
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "processing": {
            "$ref": "#/components/schemas/VideoProcessingOptions"
          }
        }
      },
      "VideoProcessingOptions": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "screen_text": {
            "type": "object",
            "additionalProperties": false,
            "properties": {
              "enabled": {
                "description": "Index text visible on screen, sampled independently of speech. Defaults to false.",
                "type": "boolean",
                "default": false
              },
              "interval_seconds": {
                "description": "On-screen text sampling interval. Defaults to 10 seconds.",
                "type": "integer",
                "minimum": 1,
                "maximum": 3600,
                "default": 10
              }
            }
          }
        }
      },
      "VideoResponse": {
        "unevaluatedProperties": false,
        "allOf": [
          {
            "$ref": "#/components/schemas/ResponseMetadata"
          },
          {
            "type": "object",
            "required": [
              "data"
            ],
            "properties": {
              "data": {
                "$ref": "#/components/schemas/Video"
              }
            }
          }
        ]
      },
      "IndexVideoRequest": {
        "type": "object",
        "additionalProperties": false,
        "description": "To re-index a video, send an empty body; the duration and content hash from its last successful index are reused. Both fields are required until an index succeeds, and must be sent together.",
        "dependentRequired": {
          "duration_seconds": [
            "content_sha256"
          ],
          "content_sha256": [
            "duration_seconds"
          ]
        },
        "properties": {
          "duration_seconds": {
            "type": "number",
            "exclusiveMinimum": 0
          },
          "content_sha256": {
            "description": "Declares source identity for indexing. The Worker verifies it against the uploaded bytes and successful unique-material billing is deduplicated by this hash; a distinct video asset may still be processed independently.",
            "type": "string",
            "pattern": "^[a-fA-F0-9]{64}$"
          },
          "processing": {
            "$ref": "#/components/schemas/VideoProcessingOptions"
          }
        }
      },
      "JobResponse": {
        "unevaluatedProperties": false,
        "allOf": [
          {
            "$ref": "#/components/schemas/ResponseMetadata"
          },
          {
            "type": "object",
            "required": [
              "data"
            ],
            "properties": {
              "data": {
                "$ref": "#/components/schemas/Job"
              }
            }
          }
        ]
      },
      "Job": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "status",
          "type",
          "video_id",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/JobId"
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "running",
              "succeeded",
              "failed",
              "cancel_requested",
              "canceled"
            ]
          },
          "type": {
            "description": "What the job does. `index` builds a video's searchable index, `export` produces an MP4 file, `annotate` produces semantic annotations; `other` covers internal jobs.",
            "type": "string",
            "enum": [
              "index",
              "export",
              "annotate",
              "other"
            ]
          },
          "video_id": {
            "description": "The video the job works on, when it has exactly one.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/VideoId"
              },
              {
                "type": "null"
              }
            ]
          },
          "progress": {
            "description": "Current stage and its progress. Index stages are upload, playable, speech, visual and index; speech and visual run at the same time.",
            "type": "object",
            "additionalProperties": false,
            "required": [
              "stage",
              "completed",
              "total"
            ],
            "properties": {
              "stage": {
                "type": "string"
              },
              "completed": {
                "type": "integer",
                "minimum": 0
              },
              "total": {
                "type": "integer",
                "minimum": 1
              }
            }
          },
          "failure": {
            "type": [
              "string",
              "null"
            ],
            "description": "Failure reason for a terminal job, including media processing startup failures."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "JobId": {
        "type": "string",
        "pattern": "^job_[A-Za-z0-9_-]+$"
      },
      "TranscriptResponse": {
        "unevaluatedProperties": false,
        "allOf": [
          {
            "$ref": "#/components/schemas/ResponseMetadata"
          },
          {
            "type": "object",
            "required": [
              "data"
            ],
            "properties": {
              "data": {
                "$ref": "#/components/schemas/Transcript"
              }
            }
          }
        ]
      },
      "Transcript": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "video_id",
          "format",
          "segments",
          "text"
        ],
        "properties": {
          "video_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "format": {
            "type": "string",
            "enum": [
              "json",
              "srt",
              "vtt"
            ]
          },
          "segments": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TranscriptSegment"
            }
          },
          "text": {
            "type": "string"
          }
        }
      },
      "TranscriptSegment": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "type",
          "start_seconds",
          "end_seconds",
          "text"
        ],
        "properties": {
          "type": {
            "description": "`speech` for the transcript; `screen_text` only when requested with `include=screen_text`.",
            "type": "string",
            "enum": [
              "speech",
              "screen_text"
            ]
          },
          "start_seconds": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0
          },
          "end_seconds": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0
          },
          "text": {
            "type": "string"
          }
        }
      },
      "ResourceDeletionResponse": {
        "unevaluatedProperties": false,
        "allOf": [
          {
            "$ref": "#/components/schemas/ResponseMetadata"
          },
          {
            "type": "object",
            "required": [
              "data"
            ],
            "properties": {
              "data": {
                "$ref": "#/components/schemas/ResourceDeletion"
              }
            }
          }
        ]
      },
      "ResourceDeletion": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "resource_type",
          "resource_id",
          "status",
          "status_url",
          "requested_at",
          "updated_at",
          "completed_at",
          "failure"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/DeletionId"
          },
          "resource_type": {
            "type": "string",
            "enum": [
              "video",
              "file"
            ]
          },
          "resource_id": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/AssetId"
              },
              {
                "$ref": "#/components/schemas/ArtifactId"
              }
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "running",
              "succeeded",
              "failed"
            ]
          },
          "status_url": {
            "type": "string",
            "format": "uri-reference"
          },
          "requested_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "completed_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "failure": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/DeletionFailure"
              },
              {
                "type": "null"
              }
            ]
          }
        }
      },
      "DeletionId": {
        "type": "string",
        "pattern": "^del_[A-Za-z0-9_-]+$"
      },
      "AssetId": {
        "type": "string",
        "pattern": "^asset_[A-Za-z0-9_-]+$"
      },
      "ArtifactId": {
        "type": "string",
        "pattern": "^artifact_[A-Za-z0-9_-]+$"
      },
      "DeletionFailure": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "code",
          "retryable"
        ],
        "properties": {
          "code": {
            "type": "string",
            "enum": [
              "deletion_failed"
            ]
          },
          "retryable": {
            "type": "boolean"
          }
        }
      },
      "ExportRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "video_id",
          "start_seconds",
          "end_seconds"
        ],
        "properties": {
          "video_id": {
            "$ref": "#/components/schemas/VideoId"
          },
          "start_seconds": {
            "type": "number",
            "minimum": 0
          },
          "end_seconds": {
            "type": "number",
            "exclusiveMinimum": 0
          },
          "clip_id": {
            "description": "The search result clip this range came from, recorded for reference.",
            "$ref": "#/components/schemas/ClipId"
          }
        }
      },
      "ClipId": {
        "description": "Identifies one search result clip. Stable across searches of the same index.",
        "type": "string",
        "pattern": "^ev_[A-Za-z0-9_-]+$"
      },
      "ExportResponse": {
        "unevaluatedProperties": false,
        "allOf": [
          {
            "$ref": "#/components/schemas/ResponseMetadata"
          },
          {
            "type": "object",
            "required": [
              "data"
            ],
            "properties": {
              "data": {
                "$ref": "#/components/schemas/Export"
              }
            }
          }
        ]
      },
      "Export": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "status",
          "video_id",
          "start_seconds",
          "end_seconds",
          "clip_id",
          "file",
          "failure",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/ExportId"
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "running",
              "succeeded",
              "failed",
              "cancel_requested",
              "canceled"
            ]
          },
          "video_id": {
            "$ref": "#/components/schemas/VideoId"
          },
          "start_seconds": {
            "type": "number",
            "minimum": 0
          },
          "end_seconds": {
            "type": "number",
            "minimum": 0
          },
          "clip_id": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/ClipId"
              },
              {
                "type": "null"
              }
            ]
          },
          "file": {
            "description": "The exported MP4 once the export succeeded; null before that and after the file is deleted.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/ExportFile"
              },
              {
                "type": "null"
              }
            ]
          },
          "failure": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ExportId": {
        "description": "An export is identified by the job that produces it.",
        "type": "string",
        "pattern": "^job_[A-Za-z0-9_-]+$"
      },
      "ExportFile": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "url",
          "content_type",
          "byte_size",
          "duration_seconds"
        ],
        "properties": {
          "url": {
            "description": "Authenticated download URL (GET /exports/{export_id}/file) using the same API key.",
            "type": "string",
            "format": "uri"
          },
          "content_type": {
            "type": "string",
            "const": "video/mp4"
          },
          "byte_size": {
            "type": "integer",
            "minimum": 0
          },
          "duration_seconds": {
            "type": "number",
            "minimum": 0
          }
        }
      },
      "SearchRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "query"
        ],
        "properties": {
          "query": {
            "type": "string",
            "minLength": 1,
            "maxLength": 1000
          },
          "filter": {
            "description": "Omit to search every video in the workspace.",
            "$ref": "#/components/schemas/SearchFilter"
          },
          "limit": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100,
            "default": 20
          },
          "include": {
            "description": "Optional extra blocks. `debug` adds model, version and ranking details to each clip.",
            "type": "array",
            "uniqueItems": true,
            "items": {
              "type": "string",
              "enum": [
                "debug"
              ]
            }
          }
        }
      },
      "SearchFilter": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "video_ids": {
            "type": "array",
            "uniqueItems": true,
            "items": {
              "$ref": "#/components/schemas/VideoId"
            }
          }
        }
      },
      "SearchResponse": {
        "unevaluatedProperties": false,
        "allOf": [
          {
            "$ref": "#/components/schemas/ResponseMetadata"
          },
          {
            "type": "object",
            "required": [
              "data"
            ],
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Clip"
                }
              }
            }
          }
        ]
      },
      "Clip": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "video_id",
          "start_seconds",
          "end_seconds",
          "score",
          "type",
          "text",
          "related",
          "context",
          "thumbnail_url",
          "playback",
          "console_url",
          "video"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/ClipId"
          },
          "video_id": {
            "$ref": "#/components/schemas/VideoId"
          },
          "start_seconds": {
            "type": "number",
            "minimum": 0
          },
          "end_seconds": {
            "type": "number",
            "minimum": 0
          },
          "score": {
            "description": "Raw similarity within this clip's type, 0 to 1. Not comparable across types.",
            "type": "number",
            "minimum": 0,
            "maximum": 1
          },
          "type": {
            "$ref": "#/components/schemas/ClipType"
          },
          "text": {
            "description": "Verbatim transcript or on-screen text; null for a visual match.",
            "type": [
              "string",
              "null"
            ],
            "maxLength": 4000
          },
          "related": {
            "description": "Other types that matched in the same stretch of the video.",
            "type": "array",
            "maxItems": 10,
            "items": {
              "$ref": "#/components/schemas/ClipMatch"
            }
          },
          "context": {
            "$ref": "#/components/schemas/ClipContext"
          },
          "thumbnail_url": {
            "description": "Signed JPEG link, valid for one hour; null while the web-playable copy is not ready.",
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "playback": {
            "description": "Signed link that plays this clip, valid for one hour; null while the web-playable copy is not ready.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/PlaybackLink"
              },
              {
                "type": "null"
              }
            ]
          },
          "console_url": {
            "description": "Permanent Console link to this moment; opening it requires signing in to the workspace.",
            "type": "string",
            "format": "uri"
          },
          "video": {
            "$ref": "#/components/schemas/ClipVideo"
          },
          "debug": {
            "$ref": "#/components/schemas/ClipDebug"
          }
        }
      },
      "ClipType": {
        "description": "What matched. `speech` is spoken words, `screen_text` is text visible on screen, `visual` is the picture itself.",
        "type": "string",
        "enum": [
          "speech",
          "screen_text",
          "visual"
        ]
      },
      "ClipMatch": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "type",
          "start_seconds",
          "end_seconds",
          "text"
        ],
        "properties": {
          "type": {
            "$ref": "#/components/schemas/ClipType"
          },
          "start_seconds": {
            "type": "number",
            "minimum": 0
          },
          "end_seconds": {
            "type": "number",
            "minimum": 0
          },
          "text": {
            "description": "Verbatim transcript or on-screen text; null for a visual match.",
            "type": [
              "string",
              "null"
            ],
            "maxLength": 4000
          }
        }
      },
      "ClipContext": {
        "description": "Verbatim transcript and on-screen text just before and after the clip (up to 15 seconds, at most two lines each side). Never generated.",
        "type": "object",
        "additionalProperties": false,
        "required": [
          "before",
          "after"
        ],
        "properties": {
          "before": {
            "type": "array",
            "maxItems": 2,
            "items": {
              "$ref": "#/components/schemas/ClipContextLine"
            }
          },
          "after": {
            "type": "array",
            "maxItems": 2,
            "items": {
              "$ref": "#/components/schemas/ClipContextLine"
            }
          }
        }
      },
      "ClipContextLine": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "type",
          "start_seconds",
          "end_seconds",
          "text"
        ],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "speech",
              "screen_text"
            ]
          },
          "start_seconds": {
            "type": "number",
            "minimum": 0
          },
          "end_seconds": {
            "type": "number",
            "minimum": 0
          },
          "text": {
            "type": "string",
            "maxLength": 4000
          }
        }
      },
      "PlaybackLink": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "url",
          "format",
          "expires_at"
        ],
        "properties": {
          "url": {
            "description": "Signed link to the web-playable copy. For a clip it ends with a `#t=start,end` media fragment that browsers honour.",
            "type": "string",
            "format": "uri"
          },
          "format": {
            "type": "string",
            "enum": [
              "mp4",
              "hls"
            ]
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ClipVideo": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "filename",
          "duration_seconds",
          "summary",
          "summary_generated"
        ],
        "properties": {
          "filename": {
            "type": [
              "string",
              "null"
            ]
          },
          "duration_seconds": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0
          },
          "summary": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 600
          },
          "summary_generated": {
            "type": "boolean"
          }
        }
      },
      "ClipDebug": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "rank",
          "index_job_id",
          "provenance"
        ],
        "properties": {
          "rank": {
            "description": "Position after fusing all types, starting at 1.",
            "type": "integer",
            "minimum": 1
          },
          "index_job_id": {
            "$ref": "#/components/schemas/JobId"
          },
          "provenance": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/EvidenceProvenance"
              },
              {
                "type": "null"
              }
            ]
          }
        }
      },
      "EvidenceProvenance": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "station",
          "model_id",
          "model_version",
          "segment_key"
        ],
        "properties": {
          "station": {
            "type": "string",
            "enum": [
              "speech",
              "visual"
            ]
          },
          "model_id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128
          },
          "model_version": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128
          },
          "segment_key": {
            "type": "string",
            "minLength": 8,
            "maxLength": 256
          }
        }
      }
    },
    "responses": {
      "Error": {
        "description": "Standard Cerul error envelope",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            }
          }
        }
      }
    },
    "parameters": {
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": true,
        "schema": {
          "type": "string",
          "minLength": 8,
          "maxLength": 200
        }
      },
      "VideoId": {
        "name": "video_id",
        "in": "path",
        "required": true,
        "schema": {
          "$ref": "#/components/schemas/VideoId"
        }
      },
      "ExportId": {
        "name": "export_id",
        "in": "path",
        "required": true,
        "schema": {
          "$ref": "#/components/schemas/ExportId"
        }
      },
      "JobId": {
        "name": "job_id",
        "in": "path",
        "required": true,
        "schema": {
          "$ref": "#/components/schemas/JobId"
        }
      },
      "DeletionId": {
        "name": "deletion_id",
        "in": "path",
        "required": true,
        "schema": {
          "$ref": "#/components/schemas/DeletionId"
        }
      }
    },
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "Cerul access token"
      }
    }
  }
}
