> ## Documentation Index
> Fetch the complete documentation index at: https://docs.upriver.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Search Breakout Topics

> Search breakout topics using hybrid vector + keyword search.

Supports three search modes:
- vector: Semantic similarity search using embeddings
- keyword: Full-text search using PostgreSQL tsvector
- hybrid: Combined vector and keyword search (default)



## OpenAPI

````yaml /api-reference/openapi.json post /v1/topics/breakout/search
openapi: 3.1.0
info:
  title: Upriver API
  description: >-
    A social insights API for ad generation platforms. It provides structured
    signals, like psychographics, behavioral insights, trends, and audience
    language, to help AI models generate relevant, higher-converting ads.
  version: 1.0.0
servers:
  - url: https://api.upriver.ai
    description: Production API server
security: []
tags:
  - name: Brands
  - name: Products
  - name: Creators
  - name: Audience
  - name: Sponsorships
  - name: Trends
  - name: Breakout Topics
  - name: Taxonomy
paths:
  /v1/topics/breakout/search:
    post:
      tags:
        - Breakout Topics
      summary: Search Breakout Topics
      description: |-
        Search breakout topics using hybrid vector + keyword search.

        Supports three search modes:
        - vector: Semantic similarity search using embeddings
        - keyword: Full-text search using PostgreSQL tsvector
        - hybrid: Combined vector and keyword search (default)
      operationId: search_breakout_topics
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SearchTopicsRequest'
        required: true
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SearchTopicsResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      security:
        - APIKeyHeader: []
components:
  schemas:
    SearchTopicsRequest:
      properties:
        query:
          type: string
          minLength: 1
          title: Query
          description: Search query text
        vertical:
          anyOf:
            - type: string
            - type: 'null'
          title: Vertical
          description: Filter by vertical (e.g., 'sports')
        mode:
          $ref: '#/components/schemas/SearchMode'
          description: 'Search mode: vector, keyword, hybrid'
          default: hybrid
        surface_mode:
          $ref: '#/components/schemas/ListSurfaceMode'
          description: Return raw topics or deduped derived story surfaces
          default: topic
        limit:
          type: integer
          maximum: 100
          minimum: 1
          title: Limit
          description: >-
            Maximum number of results. Requesting more than 20 results requires
            a credits-based plan.
          default: 20
        include:
          items:
            type: string
            enum:
              - citations
              - entities
          type: array
          title: Include
          description: >-
            Optional expansions to include in the response. Allowed values:
            citations, entities. Example: ["citations", "entities"]
        include_citations:
          type: boolean
          title: Include Citations
          description: 'Deprecated: use include=["citations","entities"] instead.'
          default: false
        query_context:
          anyOf:
            - $ref: '#/components/schemas/SearchQueryContext'
            - type: 'null'
          description: >-
            Optional source-aware context for query rewriting. Useful for terse
            external prompts such as Kalshi markets.
        kalshi_event_url:
          anyOf:
            - type: string
              maxLength: 500
            - type: 'null'
          title: Kalshi Event Url
          description: >-
            Optional Kalshi event URL or ticker. When provided, the server
            resolves event metadata and uses it for query planning. Mutually
            exclusive with query_context.
        citation_sources:
          anyOf:
            - items:
                $ref: '#/components/schemas/CitationSourceCategory'
              type: array
            - type: 'null'
          title: Citation Sources
          description: >-
            Restrict returned citations to these source categories (news,
            reddit, twitter). Omit for all sources. Only applies when
            surface_mode=topic.
        llm_relevance:
          type: boolean
          title: Llm Relevance
          description: >-
            Enable enhanced relevance scoring for search results. When true,
            results are scored and re-ranked by how well they match the query
            intent.
          default: true
      type: object
      required:
        - query
      title: SearchTopicsRequest
      description: Request for searching breakout topics.
    SearchTopicsResponse:
      properties:
        surface_mode:
          $ref: '#/components/schemas/ListSurfaceMode'
          description: Whether search returned raw topics or derived story surfaces
          default: topic
        topics:
          items:
            $ref: '#/components/schemas/BreakoutTopicResponse'
          type: array
          title: Topics
          description: Matching topics when surface_mode=topic
        stories:
          items:
            $ref: '#/components/schemas/TopicStoryViewResponse'
          type: array
          title: Stories
          description: Matching story surfaces when surface_mode=story
        search_mode:
          type: string
          title: Search Mode
          description: Search mode used
      type: object
      required:
        - search_mode
      title: SearchTopicsResponse
      description: Response for searching breakout topics.
    HTTPValidationError:
      properties:
        detail:
          items:
            $ref: '#/components/schemas/ValidationError'
          type: array
          title: Detail
      type: object
      title: HTTPValidationError
    SearchMode:
      type: string
      enum:
        - vector
        - keyword
        - hybrid
      title: SearchMode
      description: Search mode for topic search.
    ListSurfaceMode:
      type: string
      enum:
        - topic
        - story
      title: ListSurfaceMode
      description: List surface mode for breakout browse responses.
    SearchQueryContext:
      properties:
        source:
          type: string
          title: Source
          description: >-
            Optional source hint for query rewriting. Currently only 'kalshi'
            changes search behavior.
        series_title:
          anyOf:
            - type: string
            - type: 'null'
          title: Series Title
          description: Source series/event family title for broader context.
        market_subtitle:
          anyOf:
            - type: string
            - type: 'null'
          title: Market Subtitle
          description: Source subtitle, often containing compact participant codes.
        competition:
          anyOf:
            - type: string
            - type: 'null'
          title: Competition
          description: Source competition or league label, e.g. 'Pro Basketball (M)'.
        competition_scope:
          anyOf:
            - type: string
            - type: 'null'
          title: Competition Scope
          description: Source event scope such as Game, Future, or Tournament.
        contract_tickers:
          items:
            type: string
          type: array
          title: Contract Tickers
          description: Structured contract tickers associated with the source market.
        contract_titles:
          items:
            type: string
          type: array
          title: Contract Titles
          description: Optional contract display titles from the source market.
        contract_subtitles:
          items:
            type: string
          type: array
          title: Contract Subtitles
          description: Optional contract subtitles from the source market.
      type: object
      required:
        - source
      title: SearchQueryContext
      description: >-
        Optional caller context for source-aware search planning.


        Today this is used for Kalshi-originated queries, where the visible
        query text

        is often too terse to retrieve the right breakout topics without extra
        market

        metadata. Unknown sources are accepted but ignored by the current API
        logic.
    CitationSourceCategory:
      type: string
      enum:
        - news
        - reddit
        - twitter
      title: CitationSourceCategory
      description: >-
        Citation source categories usable as a citation filter.


        A subset of the ``source_category`` values that appear on returned
        citations —

        the categories worth filtering on. Other categories (web, tiktok,
        trends) can

        still appear on citations but are not offered as filter values.
    BreakoutTopicResponse:
      properties:
        topic_id:
          type: string
          title: Topic Id
          description: >-
            Topic UUID. Reuse this value with the breakout detail, story-view,
            and similar-topics endpoints.
        topic_name:
          type: string
          title: Topic Name
          description: Primary name for the topic
        canonical_name:
          type: string
          title: Canonical Name
          description: 'Deprecated: use topic_name instead. Primary name for the topic.'
          deprecated: true
        vertical:
          type: string
          title: Vertical
          description: 'Vertical: sports, tech, politics'
        category:
          anyOf:
            - type: string
            - type: 'null'
          title: Category
          description: >-
            Category value on the topic. Filtering by category is only supported
            for sports topics.
        status:
          type: string
          title: Status
          description: 'Lifecycle status: detected, emerging, trending, declining'
        score:
          anyOf:
            - type: number
            - type: 'null'
          title: Score
          description: >-
            Primary ranking score (0-1). Time-decayed composite of source
            authority, signal velocity, cross-platform confirmation, and
            engagement quality. Use this for sorting results.
        relevance_score:
          anyOf:
            - type: number
            - type: 'null'
          title: Relevance Score
          description: >-
            Query match confidence (0-1) when a search query is provided. Higher
            values indicate a stronger match to the query. Null for browse/list
            results.
        engagement:
          anyOf:
            - $ref: '#/components/schemas/TopicEngagementResponse'
            - type: 'null'
          description: Multi-signal engagement scores for query-time weighting
        peak_score:
          type: number
          title: Peak Score
          description: >-
            Peak composite importance score (0-1) combining: source authority
            (domain trust), velocity (signal frequency), volume (total
            mentions), cross-platform confirmation (source diversity), and
            engagement quality. This is a frozen/historical metric representing
            the topic's peak importance—it does not decay over time. Use score
            for current rankings.
        confidence_score:
          anyOf:
            - type: number
            - type: 'null'
          title: Confidence Score
          description: >-
            Detection confidence (0-1) based on: cross-platform confirmation
            (multiple source types), source authority (trusted domains), entity
            resolution quality (how reliably entities were identified), and
            deduplication method (exact vs fuzzy matching).
        discovered_at:
          type: string
          format: date-time
          title: Discovered At
          description: When the topic was first detected
        last_signal_at:
          anyOf:
            - type: string
              format: date-time
            - type: 'null'
          title: Last Signal At
          description: >-
            Latest evidence-backed signal time for this topic. Prefer this over
            updated_at for user-facing freshness.
        updated_at:
          type: string
          format: date-time
          title: Updated At
          description: Last material row mutation timestamp for the topic
        source_summary:
          additionalProperties:
            type: integer
          type: object
          title: Source Summary
          description: 'Signal count by source category: {news: 5, reddit: 12, web: 3}'
        citations:
          items:
            $ref: '#/components/schemas/BreakoutCitationResponse'
          type: array
          title: Citations
          description: Top citations for this topic
        entities:
          items:
            $ref: '#/components/schemas/BreakoutEntityResponse'
          type: array
          title: Entities
          description: Resolved entities mentioned in topic
        trend:
          anyOf:
            - $ref: '#/components/schemas/TopicTrendResponse'
            - type: 'null'
          description: Momentum and trend direction signals
        citation_rate:
          anyOf:
            - items:
                $ref: '#/components/schemas/CitationRateBucket'
              type: array
            - type: 'null'
          title: Citation Rate
          description: Daily citation counts for charting (detail endpoint only)
        narrative:
          anyOf:
            - $ref: '#/components/schemas/TopicNarrativeContext'
            - type: 'null'
          description: Narrative context when collapse_narratives is enabled
        temporal_status:
          anyOf:
            - type: string
              enum:
                - upcoming
                - ongoing
                - past
            - type: 'null'
          title: Temporal Status
          description: >-
            Whether the event this topic is about is upcoming, ongoing, or
            already past, relative to the request time. Null when the topic is
            not tied to a scheduled event.
        event_start_at:
          anyOf:
            - type: string
              format: date-time
            - type: 'null'
          title: Event Start At
          description: >-
            Scheduled start time (UTC) of the event this topic is about, if
            known.
        event_end_at:
          anyOf:
            - type: string
              format: date-time
            - type: 'null'
          title: Event End At
          description: Scheduled end time (UTC) of the event this topic is about, if known.
      type: object
      required:
        - topic_id
        - topic_name
        - canonical_name
        - vertical
        - status
        - peak_score
        - discovered_at
        - updated_at
      title: BreakoutTopicResponse
      description: Single breakout topic in API response.
    TopicStoryViewResponse:
      properties:
        requested_view:
          $ref: '#/components/schemas/StoryViewKind'
          description: Requested derived view
        seed_topic:
          $ref: '#/components/schemas/BreakoutTopicResponse'
          description: Seed topic
        surface:
          $ref: '#/components/schemas/StorySurfaceResponse'
          description: Resolved story surface
        member_topics:
          items:
            $ref: '#/components/schemas/BreakoutTopicResponse'
          type: array
          title: Member Topics
          description: Hydrated member topics in surface order
        search_match:
          anyOf:
            - $ref: '#/components/schemas/StorySearchMatchResponse'
            - type: 'null'
          description: Search-only metadata explaining why this story matched
      type: object
      required:
        - requested_view
        - seed_topic
        - surface
      title: TopicStoryViewResponse
      description: Response for a cluster/timeline/story surface seeded by one topic.
    ValidationError:
      properties:
        loc:
          items:
            anyOf:
              - type: string
              - type: integer
          type: array
          title: Location
        msg:
          type: string
          title: Message
        type:
          type: string
          title: Error Type
      type: object
      required:
        - loc
        - msg
        - type
      title: ValidationError
    TopicEngagementResponse:
      properties:
        percentile_score:
          anyOf:
            - type: number
            - type: 'null'
          title: Percentile Score
          description: >-
            Peak subreddit-relative engagement (0-1). Measures how exceptional
            the topic's best-performing citation is within its community. 0.9 =
            top 10% of that subreddit's posts. Useful for finding niche topics
            that over-perform in their community.
      type: object
      title: TopicEngagementResponse
      description: Engagement scoring signals for a topic.
    BreakoutCitationResponse:
      properties:
        source_category:
          type: string
          title: Source Category
          description: 'Source category: news, web, reddit, tiktok, trends'
        source_url:
          type: string
          title: Source Url
          description: URL of the source
        title:
          anyOf:
            - type: string
            - type: 'null'
          title: Title
          description: Headline of the source, when it has one (null for posts)
        display:
          type: string
          title: Display
          description: >-
            Display-ready label for the source — its headline, or the post text
            when the source has no headline. Prefer this over title.
          default: ''
        snippet:
          anyOf:
            - type: string
            - type: 'null'
          title: Snippet
          description: Relevant snippet from the source
        source_authority:
          anyOf:
            - type: number
            - type: 'null'
          title: Source Authority
          description: Authority score of the source (0-1)
        engagement_score:
          anyOf:
            - type: number
            - type: 'null'
          title: Engagement Score
          description: Normalized engagement score (0-1) for this citation
        published_at:
          anyOf:
            - type: string
              format: date-time
            - type: 'null'
          title: Published At
          description: When the source was published
      type: object
      required:
        - source_category
        - source_url
      title: BreakoutCitationResponse
      description: >-
        Citation in API response — the full topic-surface shape.


        Inherits the shared display-facing fields (source_category, source_url,
        title,

        display) from ``CitationBase`` and adds the richer fields the topic
        detail

        surface shows.
    BreakoutEntityResponse:
      properties:
        canonical_name:
          type: string
          title: Canonical Name
          description: Resolved canonical name
        entity_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Entity Id
          description: Opaque identifier for this entity, if resolved
        entity_type:
          type: string
          title: Entity Type
          description: 'Coarse type: person, org, loc, event, product, entity'
        confidence:
          type: number
          title: Confidence
          description: Resolution confidence (0-1)
        entity_subtype:
          anyOf:
            - type: string
            - type: 'null'
          title: Entity Subtype
          description: Fine-grained entity type (e.g., sportsperson, city, company)
      type: object
      required:
        - canonical_name
        - entity_type
        - confidence
      title: BreakoutEntityResponse
      description: Resolved entity in API response.
    TopicTrendResponse:
      properties:
        momentum:
          anyOf:
            - type: number
              maximum: 2
              minimum: 0
            - type: 'null'
          title: Momentum
          description: >-
            Activity ratio (0.0-2.0). Compares recent signal rate to baseline.
            2.0 = 2x usual activity, 1.0 = normal, 0.5 = half, 0.0 = no recent
            activity.
        direction:
          anyOf:
            - $ref: '#/components/schemas/TrendDirection'
            - type: 'null'
          description: >-
            Simplified trend indicator derived from momentum. 'up' (>1.3) =
            accelerating, 'flat' (0.7-1.3) = steady, 'down' (<0.7) =
            decelerating.
      type: object
      title: TopicTrendResponse
      description: Momentum and trend signals for a topic.
    CitationRateBucket:
      properties:
        day:
          type: string
          title: Day
          description: Date in YYYY-MM-DD format
        count:
          type: integer
          title: Count
          description: Number of citations published that day
      type: object
      required:
        - day
        - count
      title: CitationRateBucket
      description: A single day's citation count for charting.
    TopicNarrativeContext:
      properties:
        narrative_id:
          type: string
          title: Narrative Id
          description: Narrative UUID
        display_name:
          type: string
          title: Display Name
          description: Human-readable narrative name
        member_count:
          type: integer
          title: Member Count
          description: Number of topics in this narrative
        arc_summary:
          items:
            type: string
          type: array
          title: Arc Summary
          description: Names of member topics (up to 3, ordered by discovered_at)
      type: object
      required:
        - narrative_id
        - display_name
        - member_count
      title: TopicNarrativeContext
      description: Inline narrative context on a topic in the list endpoint.
    StoryViewKind:
      type: string
      enum:
        - cluster
        - story
        - timeline
      title: StoryViewKind
      description: Requested derived view flavor.
    StorySurfaceResponse:
      properties:
        story_id:
          type: string
          title: Story Id
          description: Stable opaque ID for this topic-seeded derived surface
        surface_type:
          $ref: '#/components/schemas/StorySurfaceType'
          description: Resolved surface type
        member_topic_ids:
          items:
            type: string
          type: array
          title: Member Topic Ids
          description: Ordered topic members
        lead_topic_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Lead Topic Id
          description: Current presentation-leading topic
        display_name:
          type: string
          title: Display Name
          description: Display name for the surface
        description:
          anyOf:
            - type: string
            - type: 'null'
          title: Description
          description: Surface summary
        story_score:
          type: number
          title: Story Score
          description: Story-level ranking score
        latest_signal_at:
          anyOf:
            - type: string
              format: date-time
            - type: 'null'
          title: Latest Signal At
          description: Latest signal time across members
        member_count:
          type: integer
          title: Member Count
          description: Current member count
        coherence_score:
          anyOf:
            - type: number
            - type: 'null'
          title: Coherence Score
          description: How coherent the current member set is
        projection_refreshed_at:
          anyOf:
            - type: string
              format: date-time
            - type: 'null'
          title: Projection Refreshed At
          description: When the backing projection row was last refreshed, if cached
      type: object
      required:
        - story_id
        - surface_type
        - member_topic_ids
        - display_name
        - story_score
        - member_count
      title: StorySurfaceResponse
      description: Derived story surface for a topic-seeded view.
    StorySearchMatchResponse:
      properties:
        matched_topic_ids:
          items:
            type: string
          type: array
          title: Matched Topic Ids
          description: Matched member topic ids that caused this story result to surface
        matched_topic_count:
          type: integer
          title: Matched Topic Count
          description: Number of matched member topics represented by this story result
        match_sources:
          items:
            type: string
          type: array
          title: Match Sources
          description: Search lanes that surfaced this story result (e.g. topic, family)
      type: object
      required:
        - matched_topic_count
      title: StorySearchMatchResponse
      description: How a story result matched the search query.
    TrendDirection:
      type: string
      enum:
        - up
        - flat
        - down
      title: TrendDirection
      description: Trend direction indicator based on momentum ratio.
    StorySurfaceType:
      type: string
      enum:
        - topic
        - cluster
        - timeline
      title: StorySurfaceType
      description: Surface type returned by the derived story view builder.
  securitySchemes:
    APIKeyHeader:
      type: apiKey
      in: header
      name: X-API-Key

````