Reference

The API

JSON over HTTPS. Send your key in the X-API-Key header. Lists return { "data": [...] }. Ids and slugs are interchangeable in paths.

curl -H "X-API-Key: pi_..." https://api.podintel.io/v1/brands/betterhelp/placements?limit=5

Endpoints

GET/podcasts

List tracked shows. Includes host and measurement vendor chain.

params: q, category, limit, offset

GET/podcasts/{id|slug}

Show detail: counts, latest episode, whether dynamic ads were observed.

GET/podcasts/{id|slug}/episodes

Episodes, newest first.

params: limit, offset

GET/podcasts/{id|slug}/sponsors

Brands on this show with placement counts, host-read vs inserted, first and last seen.

GET/podcasts/{slug}/episodes/{episode-slug}

Episode with its ad segments, dynamic insertions and fetch fingerprints.

GET/podcasts/{slug}/episodes/{episode-slug}/transcript

Transcript. JSON segments carry ad_id; text and vtt also available.

params: format=json|text|vtt

GET/episodes/{id}

Episode by numeric id.

GET/episodes/{id}/ads

Ad segments for an episode.

params: include_text

GET/episodes/{id}/transcript

Transcript by numeric id.

params: format

GET/brands

Advertisers with placement counts.

params: q, category, active_only, limit

GET/brands/{id|slug}

Brand: shows it sponsors, promo codes, URLs.

GET/brands/{id|slug}/placements

Every placement for a brand, newest first.

params: limit, offset

GET/ads

Latest placements across all shows.

params: status=parsed|unparsed|self_promo, kind=host_read|inserted, since=YYYY-MM-DD

GET/ads/new-advertisers

Brands whose first placement falls in the window.

params: days

GET/search

Full-text search across transcripts. FTS5 syntax.

params: q, limit

GET/vendors

Attribution, measurement and hosting vendors decoded from enclosure URLs, and which shows use each.

GET/backlog

Episodes still waiting for a transcript. Their inserted ads are already available.

GET/stats

Corpus counts.

Ad segment object

{
  "id": 4821,
  "episode_id": 42,
  "start_sec": 749.8,
  "end_sec": 947.8,
  "placement": "mid_roll",          // pre_roll | mid_roll | post_roll
  "kind": "host_read",              // host_read | inserted | self_promo
  "detected_by": "trigger+chapter", // chapter, trigger, dai, or combinations
  "brand_id": 1,
  "brand_name": "BetterHelp",
  "brand_slug": "betterhelp",
  "promo_code": null,
  "url": "betterhelp.com/huberman",
  "confidence": 1.0,
  "status": "parsed"                // parsed | parsed_auto | unparsed | self_promo
}

inserted segments were found by fetching the episode as several different clients and diffing the audio. Not every listener hears them. unparsed segments are ad windows where no known brand matched; the text is kept so nothing is lost.

MCP server

The same data as tools for Claude, Cursor or any MCP client: search_podcasts, podcast_sponsors, get_episode, get_transcript, search_transcripts, get_brand, brand_placements, recent_ads, new_advertisers, vendors.

claude mcp add podintel -e PODINTEL_API_KEY=pi_... -- npx -y podintel-mcp

Access

API keys are in early access. Join the waitlist and we will email you when yours is ready.