---
title: "Search the whole library"
method: GET
path: "/api/v1/search"
---

# Search the whole library

`GET /api/v1/search`

## Request

- Base URL: `https://bidclub.ai`
- URL: `https://bidclub.ai/api/v1/search`
- Auth: none declared

Full-text search across titles, deks, TL;DRs, digests, and transcripts, newest first, capped at 20 results. When full-text finds nothing the query re-runs as a substring (ilike) sweep of title, title_orig, dek, and transcript_md — the path that matches CJK, which the 'simple' text search configuration cannot segment. That sweep is always bounded to the 300 newest episodes matching the other filters, and whenever it produces the returned results the response carries partial: true and searched_recent: 300. The same two fields appear when the full-text query itself times out and is retried inside that window. searched_recent is the window ceiling, not the number of rows actually scanned. A zero-result substring fallback may omit partial; an empty response therefore does not establish that no older substring matches exist.

## Query parameters

- `q` string, required
- `time` '24h' | '7d' | '30d'
- `person` string
- `show` union
  - string
  - '__untracked__'
- `lang` 'EN' | 'ZH'
- `len` 'lt30' | '30to60' | '60to120' | 'gt120'
- `asset` string
- `sector` string
- `focus` string

## Response `200`

Matches, newest first.

- SearchResponse
  - `q` string, required: The trimmed query as executed.
  - `count` integer, required: Number of results returned (at most 20).
  - `results` SearchResult[], required
    - `slug` string, required: Stable public identifier.
    - `show_id` string, required: Foreign key into /api/v1/shows.
    - `title` string, required: Complete canonical publisher title.
    - `display_title` string, nullable: Feed-only compression of an overlength title; null when unneeded.
    - `title_alt` string, nullable: Title in the alternate language (lang_alt).
    - `display_title_alt` string, nullable
    - `title_orig` string, nullable: Source-platform title when it differs.
    - `dek` string, nullable: One-line editorial standfirst.
    - `dek_alt` string, nullable
    - `chips` string[]: Participant tags, each prefixed "person:" (e.g. "person:Jensen Huang").
    - `lang` 'EN' | 'ZH' | 'null', nullable: Language of the primary editorial fields.
    - `date` string, nullable: Publication calendar date, YYYY-MM-DD.
    - `published_at` string, nullable: Exact publication timestamp (RFC 3339); null for date-only archives.
    - `duration_min` number, nullable: Episode length in minutes.
    - `youtube_id` string, nullable
    - `youtube_url` string, nullable
    - `thumbnail_url` string, nullable
    - `source_url` string, nullable
    - `source_label` string, nullable
    - `rss_url` string, nullable
    - `tag_assets` string[]: Zero to two closed asset taxonomy ids, primary first. Empty is valid even after classification.
    - `tag_sectors` string[]: Zero to two closed sector taxonomy ids, primary first. Empty is valid even after classification.
    - `tag_focus` string[]: Zero to two closed editorial-focus taxonomy ids, primary first. Empty is valid even after classification.
    - `tagging_status` 'pending' | 'classified' | 'failed' | 'skipped': Classification state. Non-classified episodes have empty tag arrays; classified does not require a tag in every facet.
    - `tagging_version` string, nullable: Taxonomy version used for classification; nonblank when tagging_status is classified, otherwise it may be null.
    - `shows` object, nullable
      - `name` string
  - `partial` true: Present only when the results came from a windowed query rather than the whole library.
  - `searched_recent` 300: Window ceiling in newest episodes matching the other filters, not the actual number scanned. Appears with partial.

## Other responses

- `400`: q required | q must contain at least 2 characters | q must contain at most 100 printable characters | invalid time | invalid person | invalid show | invalid lang | invalid len | invalid {asset|sector|focus} tag: {id}
- `502`: Upstream database unavailable. Body: {"error": "upstream unavailable"}.

---

[API](https://skmtc.dev/bidclub/apis/bidclub-open-podcast-transcript-api.md) · [All operations](https://skmtc.dev/bidclub/apis/bidclub-open-podcast-transcript-api/llms.txt) · [OpenAPI document](https://skmtc.dev/bidclub/apis/bidclub-open-podcast-transcript-api/revisions/a097c20ae335?raw)
