BidClub Search API

The Search API from BidClub — 1 operation(s) for search.

Operations 2

GET /api/v1/search Search the whole library #
OPTIONS /api/v1/search CORS preflight #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/bidclub-ai:bidclub-ai-search-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

bidclub-ai-search-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: BidClub Open Podcast Transcript Search API
  version: 2026.9.22.2
  description: 'Public reads are keyless, account-free, CORS *. Pitch administrator POST routes use a verified private session. All /api/* responses carry X-Robots-Tag: noindex. Agents: POST /api/mcp speaks Model Context Protocol over Streamable HTTP and exposes the same library as tools (rate limited, JSON-RPC, deliberately not modelled here as it is not a REST resource). Private: POST /api/revalidate (publish hook, Bearer auth — not documented here). Direct SQL-style queries: public read-only PostgREST endpoint documented at https://bidclub.ai/api-docs (PostgREST self-serves its own OpenAPI at {SUPABASE_URL}/rest/v1/).'
  x-bilingual: All editorial content is bilingual EN/ZH via *_alt fields; lang/lang_alt mark each edition's language.
servers:
- url: https://bidclub.ai
tags:
- name: Search
paths:
  /api/v1/search:
    get:
      operationId: searchEpisodes
      summary: Search the whole library
      description: '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.'
      parameters:
      - name: q
        in: query
        required: true
        description: 2–100 code points, no control characters.
        schema:
          type: string
          minLength: 2
          maxLength: 100
      - name: time
        in: query
        required: false
        description: Publication window, measured on published_at with a calendar-date fallback for archives that expose no exact timestamp.
        schema:
          type: string
          enum:
          - 24h
          - 7d
          - 30d
      - name: person
        in: query
        required: false
        description: Exact participant name without the "person:" prefix; matched against the episode's chips. Up to 120 code points.
        schema:
          type: string
          maxLength: 120
      - name: show
        in: query
        required: false
        description: Exact show id, or the literal __untracked__ for every episode whose show is not part of the tracked roster.
        schema:
          type: string
          oneOf:
          - pattern: ^[a-z0-9][a-z0-9_-]{0,63}$
          - const: __untracked__
      - name: lang
        in: query
        required: false
        description: Source language. Input is uppercased before matching.
        schema:
          type: string
          enum:
          - EN
          - ZH
      - name: len
        in: query
        required: false
        description: Duration bucket; min inclusive, max exclusive.
        schema:
          type: string
          enum:
          - lt30
          - 30to60
          - 60to120
          - gt120
      - name: asset
        in: query
        required: false
        description: Comma-separated asset ids. Values are ORed within this facet; supplied facets are ANDed. Omitting the facet or selecting every id leaves it unfiltered, including untagged episodes; none returns no episodes.
        schema:
          type: string
          pattern: ^(?:none|(?:equities|crypto|vc_pe|other)(?:,(?:equities|crypto|vc_pe|other))*)$
      - name: sector
        in: query
        required: false
        description: Comma-separated sector ids. Values are ORed within this facet; supplied facets are ANDed. Omitting the facet or selecting every id leaves it unfiltered, including untagged episodes; none returns no episodes.
        schema:
          type: string
          pattern: ^(?:none|(?:ai_software|semis|robotics|biotech|consumer|finance|blockchain|energy|space_defense)(?:,(?:ai_software|semis|robotics|biotech|consumer|finance|blockchain|energy|space_defense))*)$
      - name: focus
        in: query
        required: false
        description: Comma-separated focus ids. Values are ORed within this facet; supplied facets are ANDed. Omitting the facet or selecting every id leaves it unfiltered, including untagged episodes; none returns no episodes.
        schema:
          type: string
          pattern: ^(?:none|(?:investing|company_building|technical|macro|policy)(?:,(?:investing|company_building|technical|macro|policy))*)$
      responses:
        '200':
          description: Matches, newest first.
          headers:
            Cache-Control:
              schema:
                type: string
                const: public, s-maxage=60
              description: Origin cache policy. The hosting CDN may consume shared-cache directives before forwarding this header to clients.
            Access-Control-Allow-Origin:
              schema:
                type: string
                const: '*'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SearchResponse'
        '400':
          description: '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}'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '502':
          description: 'Upstream database unavailable. Body: {"error": "upstream unavailable"}.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      tags:
      - Search
    options:
      summary: CORS preflight
      description: Returns 204 with permissive CORS headers. No body.
      responses:
        '204':
          description: Preflight accepted.
      tags:
      - Search
      operationId: optionsApiV1Search
      x-operation-id-source: derived
components:
  schemas:
    SearchResult:
      type: object
      required:
      - slug
      - show_id
      - title
      properties:
        slug:
          type: string
          description: Stable public identifier.
        show_id:
          type: string
          description: Foreign key into /api/v1/shows.
        title:
          type: string
          description: Complete canonical publisher title.
        display_title:
          type:
          - string
          - 'null'
          description: Feed-only compression of an overlength title; null when unneeded.
        title_alt:
          type:
          - string
          - 'null'
          description: Title in the alternate language (lang_alt).
        display_title_alt:
          type:
          - string
          - 'null'
        title_orig:
          type:
          - string
          - 'null'
          description: Source-platform title when it differs.
        dek:
          type:
          - string
          - 'null'
          description: One-line editorial standfirst.
        dek_alt:
          type:
          - string
          - 'null'
        chips:
          type: array
          items:
            type: string
          description: Participant tags, each prefixed "person:" (e.g. "person:Jensen Huang").
        lang:
          type:
          - string
          - 'null'
          enum:
          - EN
          - ZH
          - null
          description: Language of the primary editorial fields.
        date:
          type:
          - string
          - 'null'
          description: Publication calendar date, YYYY-MM-DD.
        published_at:
          type:
          - string
          - 'null'
          description: Exact publication timestamp (RFC 3339); null for date-only archives.
        duration_min:
          type:
          - number
          - 'null'
          description: Episode length in minutes.
        youtube_id:
          type:
          - string
          - 'null'
        youtube_url:
          type:
          - string
          - 'null'
        thumbnail_url:
          type:
          - string
          - 'null'
        source_url:
          type:
          - string
          - 'null'
        source_label:
          type:
          - string
          - 'null'
        rss_url:
          type:
          - string
          - 'null'
        tag_assets:
          type: array
          maxItems: 2
          uniqueItems: true
          items:
            type: string
            enum:
            - equities
            - crypto
            - vc_pe
            - other
          description: Zero to two closed asset taxonomy ids, primary first. Empty is valid even after classification.
        tag_sectors:
          type: array
          maxItems: 2
          uniqueItems: true
          items:
            type: string
            enum:
            - ai_software
            - semis
            - robotics
            - biotech
            - consumer
            - finance
            - blockchain
            - energy
            - space_defense
          description: Zero to two closed sector taxonomy ids, primary first. Empty is valid even after classification.
        tag_focus:
          type: array
          maxItems: 2
          uniqueItems: true
          items:
            type: string
            enum:
            - investing
            - company_building
            - technical
            - macro
            - policy
          description: Zero to two closed editorial-focus taxonomy ids, primary first. Empty is valid even after classification.
        tagging_status:
          type: string
          enum:
          - pending
          - classified
          - failed
          - skipped
          description: Classification state. Non-classified episodes have empty tag arrays; classified does not require a tag in every facet.
        tagging_version:
          type:
          - string
          - 'null'
          description: Taxonomy version used for classification; nonblank when tagging_status is classified, otherwise it may be null.
        shows:
          type:
          - object
          - 'null'
          properties:
            name:
              type: string
    SearchResponse:
      type: object
      required:
      - q
      - count
      - results
      properties:
        q:
          type: string
          description: The trimmed query as executed.
        count:
          type: integer
          description: Number of results returned (at most 20).
        results:
          type: array
          items:
            $ref: '#/components/schemas/SearchResult'
        partial:
          type: boolean
          const: true
          description: Present only when the results came from a windowed query rather than the whole library.
        searched_recent:
          type: integer
          const: 300
          description: Window ceiling in newest episodes matching the other filters, not the actual number scanned. Appears with partial.
    Error:
      type: object
      required:
      - error
      properties:
        error:
          type: string