{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/govtube-us/json-schema/govtube-us-video-detail-schema.json",
  "title": "VideoDetail",
  "x-generated": "2026-11-11",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/govtube-us-openapi.json#/components/schemas/VideoDetail",
  "properties": {
    "video": {
      "$ref": "#/$defs/VideoMeta"
    },
    "rights": {
      "$ref": "#/$defs/RightsSummary"
    }
  },
  "type": "object",
  "required": [
    "video",
    "rights"
  ],
  "$defs": {
    "PlaybackAsset": {
      "properties": {
        "kind": {
          "type": "string",
          "enum": [
            "youtube",
            "hls",
            "mp4"
          ],
          "title": "Kind"
        },
        "ref": {
          "type": "string",
          "title": "Ref",
          "description": "YouTube video ID, or an absolute URL for hls/mp4."
        },
        "offset_ms": {
          "type": "integer",
          "title": "Offset Ms",
          "description": "playback_ms = transcript_ms + offset_ms (simple maps only).",
          "default": 0
        },
        "alignment_verified": {
          "type": "boolean",
          "title": "Alignment Verified",
          "default": false
        },
        "made_for_kids": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "title": "Made For Kids",
          "description": "YouTube videos only (ORTH-150): YouTube's Made for Kids designation, as GovTube last checked it within the past 30 days. Null when unknown, never checked, or the check is older than 30 days. Embed with tracking off unless this is false."
        }
      },
      "type": "object",
      "required": [
        "kind",
        "ref"
      ],
      "title": "PlaybackAsset",
      "description": "The media a viewer actually plays.\n\n``alignment_verified`` must be true before instances are offered as playable:\nthe transcript clock and this asset's clock are only assumed equal when the\ntranscript was made from this exact asset, or a verified ``TimeMap`` links them."
    },
    "RightsSummary": {
      "properties": {
        "source_id": {
          "type": "string",
          "title": "Source Id"
        },
        "source_name": {
          "type": "string",
          "title": "Source Name"
        },
        "kicker": {
          "type": "string",
          "title": "Kicker",
          "description": "Display kicker for the source, e.g. 'House floor · public record'. From the source registry; never hard-code it by source_id."
        },
        "short_name": {
          "type": "string",
          "title": "Short Name",
          "description": "Short display name of the publisher, e.g. 'House Clerk'."
        },
        "rights_short": {
          "type": "string",
          "title": "Rights Short",
          "description": "Rights in two or three words for the meta line, e.g. 'public domain'. Full basis in rights_basis; restrictions in use_restrictions."
        },
        "rights_basis": {
          "type": "string",
          "title": "Rights Basis"
        },
        "use_restrictions": {
          "items": {
            "type": "string"
          },
          "type": "array",
          "title": "Use Restrictions"
        },
        "confidence": {
          "type": "string",
          "title": "Confidence",
          "description": "EXACT, HEURISTIC or OPEN, per the research behind the policy."
        },
        "policy_url": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Policy Url"
        }
      },
      "type": "object",
      "required": [
        "source_id",
        "source_name",
        "kicker",
        "short_name",
        "rights_short",
        "rights_basis",
        "use_restrictions",
        "confidence",
        "policy_url"
      ],
      "title": "RightsSummary"
    },
    "SourceChannel": {
      "properties": {
        "channel_id": {
          "type": "string",
          "title": "Channel Id",
          "description": "YouTube channel ID (UC...), which never changes."
        },
        "name": {
          "type": "string",
          "title": "Name",
          "description": "The channel's name, e.g. 'The White House'."
        },
        "url": {
          "type": "string",
          "title": "Url",
          "description": "The channel's address, by ID."
        }
      },
      "type": "object",
      "required": [
        "channel_id",
        "name",
        "url"
      ],
      "title": "SourceChannel",
      "description": "The official channel a platform video was published on (ADR 0006)."
    },
    "SpeakerInfo": {
      "properties": {
        "cluster": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Cluster",
          "description": "Speaker label, e.g. 'S0'. Null when the words have no speaker label (display_name 'No speaker label'): no voice was found there, or the document names no speaker. GovTube doesn't guess a speaker for them."
        },
        "person_id": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Person Id",
          "description": "Bioguide ID for members of Congress, when named."
        },
        "display_name": {
          "type": "string",
          "title": "Display Name",
          "description": "Official title and name, 'Reporter', 'Unconfirmed speaker', or 'No speaker label'."
        },
        "confirmed": {
          "type": "boolean",
          "title": "Confirmed",
          "description": "A person checked this name. Unchanged by match_status.",
          "default": false
        },
        "match_status": {
          "type": "string",
          "enum": [
            "unconfirmed",
            "matched_unreviewed",
            "confirmed"
          ],
          "title": "Match Status",
          "description": "unconfirmed: no name (display_name is 'Unconfirmed speaker', or a name printed in a document, which is a hint). matched_unreviewed: the name was matched from the on-screen name caption of the official video and no person has reviewed it yet; show it only with the words 'matched from on-screen name, not reviewed'. confirmed: a person checked the name (same as confirmed true). Filters (speaker, confirmed_only) count confirmed names only.",
          "default": "unconfirmed"
        },
        "match_source": {
          "items": {
            "type": "string",
            "enum": [
              "onscreen",
              "congressional_record",
              "reviewer"
            ]
          },
          "type": "array",
          "title": "Match Source",
          "description": "What the name rests on: onscreen = the official video's on-screen name caption; congressional_record = the Congressional Record for that day lists this person as speaking; reviewer = a person checked it. Empty when there is no name."
        }
      },
      "type": "object",
      "required": [
        "cluster",
        "display_name"
      ],
      "title": "SpeakerInfo",
      "description": "How a diarization cluster is shown publicly."
    },
    "TranscriptSource": {
      "properties": {
        "producer": {
          "type": "string",
          "title": "Producer",
          "description": "Who produced the text, e.g. 'White House (DCPD, GPO)'."
        },
        "origin_url": {
          "type": "string",
          "title": "Origin Url"
        },
        "retrieved_at": {
          "type": "string",
          "title": "Retrieved At",
          "description": "UTC ISO timestamp of the download."
        },
        "sha256": {
          "type": "string",
          "title": "Sha256",
          "description": "SHA-256 of the file the text was parsed from."
        },
        "registry_id": {
          "type": "string",
          "title": "Registry Id",
          "description": "The source's entry in the policy registry."
        },
        "granularity": {
          "type": "string",
          "enum": [
            "word",
            "segment",
            "sentence",
            "turn",
            "chunk",
            "document"
          ],
          "title": "Granularity"
        },
        "fidelity": {
          "type": "string",
          "enum": [
            "verbatim",
            "clean",
            "edited"
          ],
          "title": "Fidelity"
        },
        "note": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Note",
          "description": "How granularity and fidelity were judged."
        }
      },
      "type": "object",
      "required": [
        "producer",
        "origin_url",
        "retrieved_at",
        "sha256",
        "registry_id",
        "granularity",
        "fidelity"
      ],
      "title": "TranscriptSource",
      "description": "Where a third-party transcript came from (ORTH-177 transcript source record)."
    },
    "VideoLink": {
      "properties": {
        "video_id": {
          "type": "string",
          "title": "Video Id",
          "description": "The linked video (house-YYYYMMDD), its own result in /v1/videos/{video_id}."
        },
        "video_rev": {
          "type": "integer",
          "minimum": 1.0,
          "title": "Video Rev",
          "description": "The video's transcript_rev the match was made against. If the video's transcript_rev is now higher, its words may have moved: treat the link as approximate until it is recomputed."
        },
        "start_ms": {
          "type": "integer",
          "minimum": 0.0,
          "title": "Start Ms",
          "description": "Where the matched words start, in the linked video's transcript time (add its playback.offset_ms for player time; open PREROLL_MS earlier)."
        },
        "end_ms": {
          "type": "integer",
          "minimum": 0.0,
          "title": "End Ms",
          "description": "Where the matched words end, in the linked video's transcript time."
        },
        "coverage": {
          "type": "number",
          "maximum": 1.0,
          "minimum": 0.0,
          "title": "Coverage",
          "description": "Share of the printed words matched to words heard in the video (MEASURED per speech by the aligner)."
        },
        "tier": {
          "type": "string",
          "enum": [
            "high",
            "standard",
            "bracketed"
          ],
          "title": "Tier",
          "description": "high: 100+ printed words and coverage at least 0.8. standard: 40+ printed words, coverage at least 0.5, at least 2 rare 5-word anchors and precision at least 0.6. bracketed: a speech under 40 words placed between two found speeches of the same Record article."
        },
        "method": {
          "type": "string",
          "const": "text_alignment",
          "title": "Method",
          "default": "text_alignment"
        }
      },
      "type": "object",
      "required": [
        "video_id",
        "video_rev",
        "start_ms",
        "end_ms",
        "coverage",
        "tier"
      ],
      "title": "VideoLink",
      "description": "ORTH-271: a Record speech's place in the House floor video, found by text match (a cross-link, not timing)."
    },
    "VideoMeta": {
      "properties": {
        "video_id": {
          "type": "string",
          "title": "Video Id",
          "description": "GovTube canonical video ID, stable across sources. Official documents without video use 'dcpd-<package number>'."
        },
        "title": {
          "type": "string",
          "title": "Title",
          "description": "Speaker — Event — Date, per the neutrality charter; for an official document, the document's own title. A Senate committee hearing's title is the short form (ORTH-213), at most 80 characters: committee, kind of meeting and date, e.g. 'Senate Banking Committee — Nominations hearing — October 1, 2026'. Lists, results, certificates and citations use it; full_title has the whole title."
        },
        "full_title": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Full Title",
          "description": "Senate committee hearings only (null otherwise, where title is already the whole title): 'U.S. Senate — {official committee name} — {hearing title exactly as Congress.gov publishes it} — {date}'. Can run to thousands of characters."
        },
        "full_title_truncated": {
          "type": "boolean",
          "title": "Full Title Truncated",
          "description": "True when Congress.gov itself cut the hearing title off (it keeps the first 5,000 characters), so full_title is incomplete. GovTube adds nothing to mark the cut inside full_title; show this flag instead.",
          "default": false
        },
        "event_date": {
          "type": "string",
          "format": "date",
          "title": "Event Date"
        },
        "source_id": {
          "type": "string",
          "title": "Source Id",
          "description": "Key into the source policy registry, e.g. 'house_floor_clerk'."
        },
        "source_url": {
          "type": "string",
          "title": "Source Url",
          "description": "The source page; for an official document, the document itself."
        },
        "transcript_rev": {
          "type": "integer",
          "title": "Transcript Rev",
          "default": 1
        },
        "speakers": {
          "additionalProperties": {
            "$ref": "#/$defs/SpeakerInfo"
          },
          "type": "object",
          "title": "Speakers"
        },
        "playback": {
          "anyOf": [
            {
              "$ref": "#/$defs/PlaybackAsset"
            },
            {
              "type": "null"
            }
          ]
        },
        "asr_model": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Asr Model",
          "description": "Model and version that produced the words."
        },
        "duration_ms": {
          "anyOf": [
            {
              "type": "integer",
              "minimum": 0.0
            },
            {
              "type": "null"
            }
          ],
          "title": "Duration Ms",
          "description": "Length of the source audio in milliseconds, measured at ingest. Null for videos published before this field existed; then use the last word's end_ms as the length."
        },
        "word_cloud": {
          "anyOf": [
            {
              "$ref": "#/$defs/WordCloud"
            },
            {
              "type": "null"
            }
          ],
          "description": "Words that stood out in this session, and the words used most. Null when the lists have not been made for this session yet."
        },
        "timing_granularity": {
          "type": "string",
          "enum": [
            "word",
            "segment",
            "sentence",
            "turn",
            "chunk",
            "document"
          ],
          "title": "Timing Granularity",
          "description": "What the timing is attached to (ORTH-177): word = every word has a time (our transcripts); document = no timing at all, the words come from an official document (ADR 0004). Times are null exactly when this is document.",
          "default": "word"
        },
        "resolution_ms": {
          "anyOf": [
            {
              "type": "integer",
              "minimum": 1.0
            },
            {
              "type": "null"
            }
          ],
          "title": "Resolution Ms",
          "description": "Longest timed unit in milliseconds, for comparing coarse timings. Null for word (each word is timed) and for document (nothing is timed)."
        },
        "fidelity": {
          "type": "string",
          "enum": [
            "verbatim",
            "clean",
            "edited"
          ],
          "title": "Fidelity",
          "description": "verbatim: what was said, as said (our transcripts). edited: revised after the fact, e.g. a White House transcript; label it 'Official transcript · edited · no timing' and never certify it as spoken.",
          "default": "verbatim"
        },
        "transcript_source": {
          "anyOf": [
            {
              "$ref": "#/$defs/TranscriptSource"
            },
            {
              "type": "null"
            }
          ],
          "description": "Provenance of a third-party transcript; null for our own (see asr_model)."
        },
        "subjects": {
          "items": {
            "type": "string"
          },
          "type": "array",
          "title": "Subjects",
          "description": "The source's subject index, as metadata (not searched as speech)."
        },
        "source_certainty": {
          "type": "string",
          "enum": [
            "official_record",
            "official_channel",
            "unverified"
          ],
          "title": "Source Certainty",
          "description": "How sure GovTube is about the source material (ADR 0006). official_record: the official recording or record of the proceeding (House and Senate video, the Daily Compilation of Presidential Documents). official_channel: published by the office itself, e.g. on its official YouTube channel; it may be edited or excerpted and is not the complete record. unverified: not confirmed as official. Show source_caveats whenever this is not official_record or source_caveats is not empty.",
          "default": "unverified"
        },
        "source_caveats": {
          "items": {
            "type": "string"
          },
          "type": "array",
          "title": "Source Caveats",
          "description": "Plain sentences about what is uncertain in this source material, to show (and pass along) with any quote, e.g. 'Speakers are identified by machine and not reviewed.' Empty when there is nothing to add."
        },
        "source_channel": {
          "anyOf": [
            {
              "$ref": "#/$defs/SourceChannel"
            },
            {
              "type": "null"
            }
          ],
          "description": "The official YouTube channel the video was published on; null for other sources."
        },
        "record_delivery": {
          "anyOf": [
            {
              "type": "string",
              "enum": [
                "not_spoken",
                "may_include_not_spoken"
              ]
            },
            {
              "type": "null"
            }
          ],
          "title": "Record Delivery",
          "description": "Congressional Record only (ORTH-209). not_spoken: the Record marks the statement as not delivered on the floor (the Senate's bullet); show 'Inserted in the Record · not spoken on the floor'. may_include_not_spoken: the Record can't tell spoken from inserted words here (the House marks inserted words only by typeface, which GovInfo's text doesn't keep, or a Senate speech holds a bulleted passage); show 'May include remarks not spoken on the floor'. Null for every other source, and for a Senate speech with no bullet."
        },
        "part_of_page": {
          "type": "boolean",
          "title": "Part Of Page",
          "description": "True when this record is one part of the page at source_url (one speech of a Congressional Record article). No highlight link is made for it: the same words may appear elsewhere on that page.",
          "default": false
        },
        "video_link": {
          "anyOf": [
            {
              "$ref": "#/$defs/VideoLink"
            },
            {
              "type": "null"
            }
          ],
          "description": "Congressional Record House speeches only (ORTH-271): where this printed speech is in the House floor video, found by matching its text against GovTube's own transcript of the video. The Record result itself stays untimed text (playable false, ADR 0004); this is a cross-link to a separate video result. Show it with the words 'Located in the House floor video by text match'. It never confirms who speaks in the video. Null when the speech wasn't found with enough confidence."
        },
        "video_delivery": {
          "anyOf": [
            {
              "type": "string",
              "enum": [
                "delivered",
                "not_found"
              ]
            },
            {
              "type": "null"
            }
          ],
          "title": "Video Delivery",
          "description": "Congressional Record House speeches only (ORTH-271), from matching the printed words against GovTube's own transcript of that day's House floor video, and only on days whose video runs to the end of the Record (a video that goes dark early would make delivered speeches look missing). delivered: the speech was found in the video and at least 80% of its printed words were matched to words heard there; show 'Delivered on the floor (matched to video)'. not_found: a speech of 150+ printed words that matched (almost) nothing while the speeches on either side of it in the Record were found in the video; show 'Not found in the floor video (may have been inserted)'. Never read either value as 'not spoken'. Null: no such signal (most speeches, every Senate speech)."
        }
      },
      "type": "object",
      "required": [
        "video_id",
        "title",
        "event_date",
        "source_id",
        "source_url"
      ],
      "title": "VideoMeta"
    },
    "WordCloud": {
      "properties": {
        "terms": {
          "items": {
            "$ref": "#/$defs/WordCloudTerm"
          },
          "type": "array",
          "title": "Terms",
          "description": "Words that stood out in this session, largest first."
        },
        "top_words": {
          "items": {
            "$ref": "#/$defs/WordCount"
          },
          "type": "array",
          "title": "Top Words",
          "description": "Words used most in this session, most first."
        },
        "generated_at": {
          "type": "string",
          "title": "Generated At",
          "description": "When these lists were made (ISO 8601, UTC)."
        },
        "words": {
          "type": "integer",
          "minimum": 0.0,
          "title": "Words",
          "description": "Words in the transcript these lists were made from."
        }
      },
      "type": "object",
      "required": [
        "generated_at",
        "words"
      ],
      "title": "WordCloud",
      "description": "Words that stood out in this session, and the words used most (computed when the session is published)."
    },
    "WordCloudTerm": {
      "properties": {
        "text": {
          "type": "string",
          "title": "Text",
          "description": "The word, as it was most often written in this transcript."
        },
        "weight": {
          "type": "number",
          "maximum": 1.0,
          "minimum": 0.0,
          "title": "Weight",
          "description": "Display size from 0 to 1; 1 is the largest word."
        },
        "count": {
          "type": "integer",
          "minimum": 1.0,
          "title": "Count",
          "description": "Times the word was said in this session."
        }
      },
      "type": "object",
      "required": [
        "text",
        "weight",
        "count"
      ],
      "title": "WordCloudTerm"
    },
    "WordCount": {
      "properties": {
        "text": {
          "type": "string",
          "title": "Text",
          "description": "The word, as it was most often written in this transcript."
        },
        "count": {
          "type": "integer",
          "minimum": 1.0,
          "title": "Count",
          "description": "Times the word was said in this session."
        }
      },
      "type": "object",
      "required": [
        "text",
        "count"
      ],
      "title": "WordCount"
    }
  }
}