{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/govtube-us/json-schema/govtube-us-speaker-profile-schema.json",
  "title": "SpeakerProfile",
  "description": "GET /v1/speakers/{person_id}: who they are, where they speak, how much, and their words.",
  "x-generated": "2026-11-11",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/govtube-us-openapi.json#/components/schemas/SpeakerProfile",
  "properties": {
    "api_version": {
      "type": "string",
      "title": "Api Version",
      "default": "v1"
    },
    "person": {
      "$ref": "#/$defs/SpeakerPerson"
    },
    "matched_unreviewed_label": {
      "type": "string",
      "title": "Matched Unreviewed Label",
      "description": "The words to show with every matched_unreviewed count, event or quote.",
      "default": "matched from on-screen name, not reviewed"
    },
    "totals": {
      "$ref": "#/$defs/SpeakerTotals"
    },
    "events": {
      "items": {
        "$ref": "#/$defs/SpeakerEvent"
      },
      "type": "array",
      "title": "Events",
      "description": "Every video session they speak in and their newest documents (at most documents_listed), newest first."
    },
    "documents_listed": {
      "type": "integer",
      "minimum": 0.0,
      "title": "Documents Listed",
      "description": "How many of their documents events lists: the newest ones. totals.documents.sessions counts them all; search with their speaker filter finds the words in any of them.",
      "default": 0
    },
    "word_cloud": {
      "anyOf": [
        {
          "$ref": "#/$defs/SpeakerWordCloud"
        },
        {
          "type": "null"
        }
      ],
      "description": "Words this speaker uses most, and words they use more than other speakers do. Null when the lists have not been made for this speaker yet."
    }
  },
  "type": "object",
  "required": [
    "person",
    "totals",
    "events"
  ],
  "$defs": {
    "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)."
    },
    "SpeakerEvent": {
      "properties": {
        "video_id": {
          "type": "string",
          "title": "Video Id"
        },
        "title": {
          "type": "string",
          "title": "Title"
        },
        "event_date": {
          "type": "string",
          "format": "date",
          "title": "Event Date"
        },
        "source_id": {
          "type": "string",
          "title": "Source Id"
        },
        "source_url": {
          "type": "string",
          "title": "Source Url"
        },
        "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."
        },
        "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."
        },
        "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."
        },
        "playable": {
          "type": "boolean",
          "title": "Playable",
          "description": "A playback asset exists and its alignment with the transcript is verified."
        },
        "identification": {
          "type": "string",
          "enum": [
            "confirmed",
            "matched_unreviewed"
          ],
          "title": "Identification",
          "description": "confirmed: a person checked the name for every turn counted here. matched_unreviewed: some or all of the turns were named from the on-screen name caption and nobody has reviewed them; show 'matched from on-screen name, not reviewed' with them."
        },
        "display_name": {
          "type": "string",
          "title": "Display Name",
          "description": "The name as shown next to their words in this session."
        },
        "clusters": {
          "items": {
            "type": "string"
          },
          "type": "array",
          "title": "Clusters",
          "description": "The session's speaker labels counted as this person."
        },
        "first_start_ms": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "title": "First Start Ms",
          "description": "Start of their first turn, to open the session there. Null exactly when timing_granularity is document (no made-up times)."
        },
        "turns": {
          "type": "integer",
          "minimum": 1.0,
          "title": "Turns"
        },
        "speaking_ms": {
          "anyOf": [
            {
              "type": "integer",
              "minimum": 0.0
            },
            {
              "type": "null"
            }
          ],
          "title": "Speaking Ms",
          "description": "Total length of their turns. Null exactly when timing_granularity is document (no made-up times)."
        },
        "words": {
          "type": "integer",
          "minimum": 0.0,
          "title": "Words"
        },
        "confirmed_turns": {
          "type": "integer",
          "minimum": 0.0,
          "title": "Confirmed Turns",
          "description": "Of turns, those where a person checked the name."
        }
      },
      "type": "object",
      "required": [
        "video_id",
        "title",
        "event_date",
        "source_id",
        "source_url",
        "source_certainty",
        "timing_granularity",
        "playable",
        "identification",
        "display_name",
        "clusters",
        "first_start_ms",
        "turns",
        "speaking_ms",
        "words",
        "confirmed_turns"
      ],
      "title": "SpeakerEvent",
      "description": "One session or hearing the speaker appears in, with how much they spoke there."
    },
    "SpeakerPerson": {
      "properties": {
        "person_id": {
          "type": "string",
          "title": "Person Id",
          "description": "Bioguide ID."
        },
        "name": {
          "type": "string",
          "title": "Name",
          "description": "Official name from the people registry; when the person is not in it, the name as shown in the newest session."
        },
        "display_name": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Display Name",
          "description": "The name as shown next to their words in the newest session they speak in; null when they have no indexed speech."
        },
        "title": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Title",
          "description": "e.g. 'Representative', 'Senator', 'Delegate'; 'Former Senator' etc. for a member who has left (in_office false)."
        },
        "chamber": {
          "anyOf": [
            {
              "type": "string",
              "enum": [
                "House",
                "Senate"
              ]
            },
            {
              "type": "null"
            }
          ],
          "title": "Chamber"
        },
        "state": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "State",
          "description": "Two-letter state or territory code."
        },
        "district": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "title": "District",
          "description": "House district; 0 for an at-large seat; null for senators."
        },
        "party": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Party",
          "description": "Party as the official list states it, as text (e.g. 'D', 'R', 'I')."
        },
        "official_url": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Official Url"
        },
        "portrait_url": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Portrait Url",
          "description": "Official portrait, only when it is public domain; else null."
        },
        "portrait_credit": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Portrait Credit",
          "description": "Where the portrait comes from and why it may be shown."
        },
        "in_office": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "title": "In Office",
          "description": "True for a sitting member; false for a member of the 119th Congress who has left (term_end is the day they left); null when not in the registry."
        },
        "term_start": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Term Start",
          "description": "Start of their current (or, for a former member, last) term, YYYY-MM-DD, as the registry records it."
        },
        "term_end": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Term End",
          "description": "Scheduled end of a sitting member's term, or the day a former member left, YYYY-MM-DD."
        },
        "in_registry": {
          "type": "boolean",
          "title": "In Registry",
          "description": "False when the person is not in GovTube's list of members of the 119th Congress (sitting and former); then only name and display_name are known."
        },
        "details_verified": {
          "type": "boolean",
          "title": "Details Verified",
          "description": "False while the registry record still awaits a field-by-field check."
        }
      },
      "type": "object",
      "required": [
        "person_id",
        "name",
        "display_name",
        "title",
        "chamber",
        "state",
        "district",
        "party",
        "portrait_url",
        "portrait_credit",
        "in_registry",
        "details_verified"
      ],
      "title": "SpeakerPerson",
      "description": "Who the profile is about, from the people registry. The same fields for everyone; party is display text."
    },
    "SpeakerTerm": {
      "properties": {
        "text": {
          "type": "string",
          "title": "Text",
          "description": "The word, as this speaker's transcripts most often write it."
        },
        "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 this speaker said the word."
        }
      },
      "type": "object",
      "required": [
        "text",
        "weight",
        "count"
      ],
      "title": "SpeakerTerm"
    },
    "SpeakerTotals": {
      "properties": {
        "all": {
          "$ref": "#/$defs/SpeechTotals",
          "description": "Everything: videos and documents."
        },
        "videos": {
          "$ref": "#/$defs/SpeechTotals",
          "description": "Video sessions only (confirmed and matched_unreviewed together)."
        },
        "confirmed": {
          "$ref": "#/$defs/SpeechTotals",
          "description": "Turns in videos where a person checked the name."
        },
        "matched_unreviewed": {
          "$ref": "#/$defs/SpeechTotals",
          "description": "Turns in videos named from the on-screen name caption, not reviewed."
        },
        "documents": {
          "$ref": "#/$defs/SpeechTotals",
          "description": "Official transcripts without timing that name them (sessions counts documents: one per Congressional Record speech). The name is the one the document prints, matched to the person; no one at GovTube reviewed it. speaking_ms is 0."
        },
        "first_event_date": {
          "anyOf": [
            {
              "type": "string",
              "format": "date"
            },
            {
              "type": "null"
            }
          ],
          "title": "First Event Date"
        },
        "last_event_date": {
          "anyOf": [
            {
              "type": "string",
              "format": "date"
            },
            {
              "type": "null"
            }
          ],
          "title": "Last Event Date"
        }
      },
      "type": "object",
      "required": [
        "all",
        "confirmed",
        "matched_unreviewed"
      ],
      "title": "SpeakerTotals",
      "description": "Totals split by how the name was identified. In videos, a session with both kinds counts once in each, and once\nin videos and in all. Official transcripts without timing (documents: the Congressional Record, White House\ntranscripts) print the speaker's name themselves; they count only in documents and all, never as confirmed."
    },
    "SpeakerWordCloud": {
      "properties": {
        "terms": {
          "items": {
            "$ref": "#/$defs/SpeakerTerm"
          },
          "type": "array",
          "title": "Terms",
          "description": "Words this speaker uses more than other speakers do, largest first. Empty when words is under min_words, or when the other speakers in the same transcripts said under min_words words between them."
        },
        "top_words": {
          "items": {
            "$ref": "#/$defs/SpeakerWordCount"
          },
          "type": "array",
          "title": "Top Words",
          "description": "Words this speaker uses most, 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 of theirs these lists were made from."
        },
        "words_confirmed": {
          "type": "integer",
          "minimum": 0.0,
          "title": "Words Confirmed",
          "description": "Of words, those in turns where a person checked the name."
        },
        "words_matched_unreviewed": {
          "type": "integer",
          "minimum": 0.0,
          "title": "Words Matched Unreviewed",
          "description": "Of words, those in turns named from the on-screen name caption, not reviewed."
        },
        "min_words": {
          "type": "integer",
          "minimum": 0.0,
          "title": "Min Words",
          "description": "Words needed before terms are shown."
        },
        "sessions": {
          "type": "integer",
          "minimum": 0.0,
          "title": "Sessions",
          "description": "Sessions their words come from."
        }
      },
      "type": "object",
      "required": [
        "generated_at",
        "words",
        "words_confirmed",
        "words_matched_unreviewed",
        "min_words",
        "sessions"
      ],
      "title": "SpeakerWordCloud",
      "description": "Words this speaker uses most, and words they use more than other speakers do (made on GovTube's side and\npublished with the ingest token). Same core shape as WordCloud."
    },
    "SpeakerWordCount": {
      "properties": {
        "text": {
          "type": "string",
          "title": "Text",
          "description": "The word, as this speaker's transcripts most often write it."
        },
        "count": {
          "type": "integer",
          "minimum": 1.0,
          "title": "Count",
          "description": "Times this speaker said the word."
        }
      },
      "type": "object",
      "required": [
        "text",
        "count"
      ],
      "title": "SpeakerWordCount"
    },
    "SpeechTotals": {
      "properties": {
        "sessions": {
          "type": "integer",
          "minimum": 0.0,
          "title": "Sessions",
          "description": "Sessions (videos and documents) with at least one turn."
        },
        "turns": {
          "type": "integer",
          "minimum": 0.0,
          "title": "Turns",
          "description": "Speaker turns: unbroken stretches of their words."
        },
        "speaking_ms": {
          "type": "integer",
          "minimum": 0.0,
          "title": "Speaking Ms",
          "description": "Total length of their turns in milliseconds (timed sessions only)."
        },
        "words": {
          "type": "integer",
          "minimum": 0.0,
          "title": "Words",
          "description": "Words spoken, stage notes such as '[Applause]' excluded."
        }
      },
      "type": "object",
      "required": [
        "sessions",
        "turns",
        "speaking_ms",
        "words"
      ],
      "title": "SpeechTotals"
    }
  }
}