---
title: "Search Youtube"
method: POST
path: "/api/internal/youtube/search"
tags: ["YouTube"]
---

# Search Youtube

`POST /api/internal/youtube/search`

Search YouTube caption chunks.

Institution linkage is dual-route — chunks are matched if EITHER the
video's channel is mapped to the institution (via youtube_links) OR the
video itself carries a per-video tag (raw.video_institution_unique_id).
Results from both routes are unioned and deduped, preferring the
per-video tag when both routes match the same chunk.

The ``query`` field uses ``websearch_to_tsquery('english', ...)`` —
websearch syntax (quoted phrases, OR, leading - to exclude). For tight
phrase matching, quote the phrase. Cover-density ranking (ts_rank_cd)
already favors chunks where query terms appear close together.

At least one of ``institution_ids`` or ``query`` is required.

## Request body

- YouTubeSearchFilters — Search filters for YouTube caption chunks. The ``query`` field is evaluated against the chunks' ``text_search_fts`` column via ``websearch_to_tsquery('english', ...)`` — stemming on, websearch syntax (quoted phrases, OR, leading - to exclude). Institution linkage uses BOTH routes signals uses, results unioned: • Channel route: raw.channel_id → youtube_links.channel_id → unique_id • Video route: raw.video_institution_unique_id (direct per-video tag) The signals retriever uses ``phraseto_tsquery`` because its API takes programmatic keyword groups. Our user-input API uses ``websearch`` to match the rest of the chunk endpoints. For tight phrase matching, consumers quote the phrase: ``query='"school board meeting"'``. Cover-density ranking (ts_rank_cd) already prefers chunks where query terms appear close together. At least one of ``institution_ids`` or ``query`` must be supplied — the chunks table is large and unbounded scans are rejected.
  - `query` string, nullable
  - `institution_ids` string[], nullable
  - `states` string[], nullable
  - `source_tables` string[], nullable
  - `date_after` string, date, nullable
  - `date_before` string, date, nullable
  - `group_by_document` boolean
  - `offset` integer
  - `limit` integer

## Response `200`

Successful Response

- PaginatedResponseYouTubeChunkResponse
  - `results` YouTubeChunkResponse[], required
    - `chunk_id` integer, required
    - `document_id` integer, required
    - `institution_id` string, nullable
    - `institution_name` string, nullable
    - `institution_state` string, nullable
    - `institution_type` string, nullable
    - `video_title` string, nullable
    - `video_url` string, nullable
    - `youtube_id` string, nullable
    - `channel_name` string, nullable
    - `video_date` string, date-time, nullable
    - `video_published_at` string, date-time, nullable
    - `text` string, required
    - `video_start_timestamp` string, nullable
    - `video_end_timestamp` string, nullable
    - `relevance` number, nullable
    - `other_matching_chunks_in_document` integer, nullable
  - `total` integer, required
  - `offset` integer, required
  - `limit` integer, required

## Other responses

- `422` — Validation Error

---

[API](https://skmtc.net/nationgraph/apis/nationgraph-api.md) · [All operations](https://skmtc.net/nationgraph/apis/nationgraph-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/nationgraph/nationgraph-api/versions/85804e68d86d/schema)
