[BidClub_]

Query the entire library

Every published episode — metadata, TL;DR, digest, full transcript, bilingual editorial fields, participant tags, and provenance — plus the show registry, as JSON or portable files. The BidClub API and downloads require no account and no API key.

Fastest path: use the complete catalog endpoint to discover every slug, then fetch full episodes in parallel. Use the versioned API for common reads, file routes for research artifacts, or the public read-only PostgREST endpoint for custom queries. JSON and download routes support cross-origin browser requests. Episode and show responses use a five-minute cache; search uses one minute.

This page runs top to bottom from the smallest surface to the largest: the REST endpoints, then the discovery files a machine reads on its own, then agent installs, then feeds for human readers, and finally direct database access for queries the REST layer does not express.

Endpoints

GET /api/v1/shows
    show registry: identity, language, hosts, tracking state, source URLs

GET /api/feed-index
    complete compact catalog in one JSON response: count + every published episode

GET /api/v1/episodes?show={show_id}&lang={EN|ZH}&limit={1..100}&offset={0..}
    paginated newest episode metadata; default limit 50 and offset 0
    pagination.next_offset is null on the final page

GET /api/v1/episodes/{slug}
    one full episode: editorial markdown, transcript, alternates, provenance

GET /api/v1/search?q={query}&show=...&person=...&lang=...&len=...&time=...
    deep full-library search; up to 20 newest matches
    a degraded fallback is explicitly marked partial: true

GET /dl/{slug}/{summary|transcript|full}.{md|txt|pdf}
    one episode artifact

GET /dl/show/{show_id}/{summary|transcript|full}.{md|txt|pdf}
    one ZIP containing the available artifacts for every published episode

Grab everything

No account, cookie, or BidClub API key is required. The catalog endpoint returns every published episode as compact metadata in one request. Each slug then resolves to the complete JSON record, including the available editorial Markdown and transcript. For a lower-bandwidth export, page through /api/v1/episodes instead.

# download the complete compact catalog (currently a few MB)
curl -o bidclub-catalog.json "https://bidclub.ai/api/feed-index"

# fetch every complete episode JSON with modest parallelism
jq -r '.episodes[].slug' bidclub-catalog.json |
  xargs -P 6 -I {} sh -c   'curl -fsS "https://bidclub.ai/api/v1/episodes/{}" -o "{}.json"'

# browser / JavaScript: no auth header required
const catalog = await fetch("https://bidclub.ai/api/feed-index").then(r => r.json());

Search filters

Search covers titles, descriptions, TL;DRs, digests, and transcripts. It uses the full-text index first, then a substring fallback for Chinese and partial-word matches. Participant names match the exact person tag stored on an episode. If the database times out before its search index is available, the response stays usable but explicitly returns partial: true with the number of newest matching-filter episodes searched.

q       required · 2–100 characters
show    exact show id, available from /api/v1/shows
person  exact participant name, without the "person:" prefix
lang    EN | ZH
len     lt30 (<30) | 30to60 (30–59) | 60to120 (60–119) | gt120 (≥120)
time    24h | 7d | 30d  (exact release time; date fallback where unavailable)

Examples

# English and Chinese search
curl "https://bidclub.ai/api/v1/search?q=OpenAI&lang=EN"
curl --get "https://bidclub.ai/api/v1/search" --data-urlencode "q=泡沫"

# combine transcript search filters
curl --get "https://bidclub.ai/api/v1/search" \
  --data-urlencode "q=AI" \
  --data-urlencode "person=Jensen Huang" \
  --data-urlencode "len=60to120" \
  --data-urlencode "time=30d"

# five newest metadata records from one show
curl "https://bidclub.ai/api/v1/episodes?show=iltb&limit=5"

# next page of metadata; follow pagination.next_offset until it is null
curl "https://bidclub.ai/api/v1/episodes?limit=100&offset=100"

# full episode as JSON, then a terminal-friendly transcript
curl "https://bidclub.ai/api/v1/episodes/ai-selloff-gavin-baker"
curl "https://bidclub.ai/dl/ai-selloff-gavin-baker/transcript.txt"

Response fields

The collection endpoint stays compact and wraps its rows in episodes plus a pagination object containing limit, offset, and next_offset. Fetch an episode by slug when you need long-form markdown or alternate-language editorial fields; search results also stay compact and never include the long markdown bodies. title is always the complete canonical publisher title; display_title is a nullable, feed-only compression for overlength titles. Nullable source and translation fields are returned as null when unavailable.

SHOW
  id, name, lang, hosts, tracked, position, sources

EPISODE LIST ITEM
  slug, show_id, title, display_title, title_orig, dek, lang, date, published_at, duration_min,
  source_url, source_label, rss_url, youtube_id, youtube_url,
  provenance, shows { name }

EPISODE DETAIL
  list fields + thumbnail_url, chips, title_alt, display_title_alt, dek_alt, lang_alt,
  tldr_md, digest_md, transcript_md, tldr_md_alt, digest_md_alt,
  shows { name, hosts }

SEARCH RESULT
  compact discovery metadata + title_alt, display_title_alt, dek_alt, thumbnail_url, chips

Download behavior

summary contains the TL;DR and digest; transcript contains the full transcript; full combines both. Markdown preserves structure, text removes most Markdown syntax, and PDF is typeset and cached on first request. A show route streams a ZIP and includes a README recording any unavailable episode artifact; the first large PDF archive can take longer to assemble.

Limits and errors

The versioned episode collection accepts at most 100 rows per request; follow pagination.next_offset until it is null. The one-response catalog is deliberately much larger and is intended for occasional discovery or mirroring, not tight polling. JSON API errors use an error field: 400 for an invalid query, 404 for a missing episode, and 502 when the upstream is unavailable. Download routes use the corresponding HTTP status with a short text response.

Machine discovery

Agents and code generators can read this surface directly. The OpenAPI document describes the bidclub.ai routes on this page only; the PostgREST endpoint below self-serves its own OpenAPI document at its root when called with the public key. Note that every /api/* response carries X-Robots-Tag: noindex — that governs search indexing of the JSON, not access to it.

GET /openapi.json
    OpenAPI 3.1 schema: every endpoint, parameter, and response shape

GET /llms.txt
    short discovery file for language models (llmstxt.org convention)

GET /llms-full.txt
    the same, with the complete API reference and live show registry inlined

Agents

An agent can reach the library three ways, in descending order of preference. The MCP server is the richest: it speaks Model Context Protocol over Streamable HTTP at /api/mcp, needs no key, and exposes six tools. It is rate limited to 30 requests per minute per IP because these calls bypass the CDN; for bulk reads use the cached REST endpoints above.

POST https://bidclub.ai/api/mcp

bidclub_list_shows        the show registry
bidclub_list_episodes     episode metadata, newest first
bidclub_search_episodes   full-text and Chinese substring search
bidclub_get_episode       one section, paged deterministically for long text
bidclub_feed_index        the slim whole-library index
bidclub_download_links    the /dl URL matrix, built without fetching

# Claude Code
claude mcp add --transport http bidclub https://bidclub.ai/api/mcp

# any client that speaks Streamable HTTP
{ "mcpServers": { "bidclub": { "url": "https://bidclub.ai/api/mcp" } } }

# stdio-only clients bridge through mcp-remote
npx -y mcp-remote https://bidclub.ai/api/mcp

Long sections page rather than truncate: when a result carries truncated: true, call bidclub_get_episode again with offset set to next_offset and concatenate content_md until next_offset is null. The window defaults to 20,000 characters for Latin text and 14,000 for Chinese, where one character costs roughly one token.

For an agent with no MCP support, the Claude Code skill teaches the same workflow over plain HTTP. It is one file and installs with one command. There is also a zero-dependency CLI on npm for shells and scripts.

mkdir -p ~/.claude/skills/bidclub \
  && curl -fsSL https://bidclub.ai/skill/SKILL.md \
       -o ~/.claude/skills/bidclub/SKILL.md

npx bidclub search "kospi"
npx bidclub episodes --show dwarkesh --limit 5
npx bidclub get <slug> --section digest --lang EN
npx bidclub dl <slug> --file transcript -o transcript.md

Feeds

RSS 2.0 feeds, no account and no API key. Each feed is published as two separate language editions rather than one mixed feed, and the site's language toggle decides which edition a link on the site points at. Global feeds cover tracked shows and carry the 30 newest episodes; a per-show feed exists for every show with a page — tracked or not — and carries 20. Per-show feed links live on the coverage page, one per row; the OPML files list tracked shows only.

GET /feeds/global.xml · /feeds/global.zh.xml
    all tracked shows, 30 newest episodes

GET /feeds/{show_id}.xml · /feeds/{show_id}.zh.xml
    one show, 20 newest episodes
    linked per row on /coverage

GET /opml · /opml.zh
    OPML 2.0 download: per-show feeds in ONE language, no global feed
    importing both languages would subscribe you to every show twice

Entry bodies are the dek plus the TL;DR and links back — the full digest, transcript, and downloads stay on the episode page. Item guids are stable, slug-based, and language-qualified: tag:bidclub.ai,2026:e:{slug}:en or :zh. They are tag: URIs rather than URLs, hence isPermaLink="false". A republished episode keeps its guid, so corrections refresh in place instead of arriving as a new unread item, and subscribing to both editions of one show never collapses them. Feeds carry Last-Modified and answer If-Modified-Since with 304. Cache-Control is "public, max-age=60, s-maxage=300, stale-while-revalidate=600", so a new episode surfaces within about five minutes of publishing. These are article feeds: no audio enclosures and no podcast namespace tags.

Direct database access

For explicit field selection, filtering, ordering, joins, and pagination, query the public database directly with the PostgREST query language. The key below is intentionally public; row-level security permits reads of published content and denies writes. PostgREST commonly caps one response at 1,000 rows, so direct-database clients must page with limit and offset (or Range headers) and should select only the fields they need.

SB="https://fexwajqmulkvqfsdxodo.supabase.co/rest/v1"
KEY="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImZleHdhanFtdWxrdnFmc2R4b2RvIiwicm9sZSI6ImFub24iLCJpYXQiOjE3ODU5OTk5MDIsImV4cCI6MjEwMTU3NTkwMn0.vqZwHNNcpcFmPQ-Ca1Xlps9kjvsB0QMZOtdL4Nu4Rj4"

# page through compact rows; never assume an unbounded response
curl "$SB/episodes?select=slug,show_id,title,date,published_at&order=published_at.desc.nullslast,date.desc,slug.asc&limit=100&offset=0" \
  -H "apikey: $KEY"

# indexed full-text search across titles, summaries, and transcripts
curl "$SB/episodes?select=slug,title,date,published_at&fts=wfts(simple).NVIDIA&limit=50" \
  -H "apikey: $KEY"

# join each episode to its show
curl "$SB/episodes?select=slug,title,published_at,shows(name)&order=published_at.desc.nullslast,date.desc&limit=100" \
  -H "apikey: $KEY"

Public schema

shows
  id, name, lang, hosts, tracked, position, sources (jsonb), updated_at

episodes · identity and discovery
  slug, show_id → shows.id, title, display_title, title_orig, title_alt,
  display_title_alt, dek, dek_alt,
  lang, lang_alt, date, published_at, duration_min, thumbnail_url

episodes · source and provenance
  source_url, source_label, rss_url, youtube_id, youtube_url,
  chips (jsonb: ["person:<name>"]), provenance (jsonb: [[stage, tool], ...])

episodes · editorial content
  tldr_md, digest_md, transcript_md, tldr_md_alt, digest_md_alt

episodes · system
  status, updated_at, fts

A link back to the BidClub episode and its original source is appreciated.