# spoken.md > Podcast transcripts as clean markdown. Built for AI agents. ## API Base URL: https://spoken.md Authentication: `x-api-key` header, or the same key as `Authorization: Bearer`, or as HTTP Basic (key as username) for feed readers Free demo key: `pt_demo` (returns only the demo episode) Getting a key: https://spoken.md/auth.md ### Search episodes GET /search?q={query} Search by text or paste a URL (Spotify, YouTube, etc.). Returns a JSON object `{ "results": [...] }` of matching episodes, each with `id`, `title`, `podcast`, `podcastId`, and `date`. Requires API key, no credits charged. ### List a show's episodes GET /podcasts/{podcastId}/episodes Returns a show's back-catalog as `{ "podcast", "podcast_id", "count", "episodes": [...] }`, each episode with `id`, `title`, and `date`. Use a `podcastId` from search results. Requires API key, no credits charged. To transcribe a whole show, loop the returned `id`s through `/transcripts/{id}`. ### Get transcript GET /transcripts/{id} Returns markdown with speaker names and timestamps. Use an `id` from search results. Costs 1 credit on first fetch. Repeat fetches of the same episode are free. Errors are never charged. Response headers include `X-Credits-Remaining` and `X-Credits-Charged`. ### Follow shows GET /following PUT /following/{podcastId} DELETE /following/{podcastId} The shows a key is kept current on. Every charged fetch makes its show a follow: the five most-fetched shows from the last 180 days are followed automatically (`"source": "fetch"`), and up to 25 more can be declared with `PUT` (`"source": "explicit"`). `GET` returns `{ "following": [...], "muted": [...], "limits": {...} }`, each follow with `podcast_id`, `podcast`, `source`, `fetch_count`, `last_fetched_at` and `newest_fetched_id` (the highest episode id fetched — what counts as new starts above it). `DELETE` mutes a show so later fetches do not re-add it; `PUT` reverses that. Requires a real key, never charges, never cached. ### What is new GET /new GET /new?format=atom Every followed show with the episodes released in the last 90 days that are newer than the newest one you fetched from it (10 per show at most), each with a `transcript_url`. Episodes with no transcript are left out. Returns `{ "as_of", "count", "shows": [{ "podcast_id", "podcast", "source", "episodes": [{ "id", "title", "date", "transcript_url" }] }] }`. With `?format=atom` or `Accept: application/atom+xml` the same episodes come back as an Atom feed, one entry per episode linking its transcript, for feed readers and automation tools; those can authenticate with HTTP Basic, the key as the username. Polling is free; fetching a transcript costs the normal credit. The list is refreshed hourly. ### Top up credits POST /top-up Redirects to Stripe Checkout to purchase more credits for an existing key. Send the key as on every other route (`x-api-key` or `Authorization` header); `?key={your_api_key}` works too, for a link. The `top_up_url` in 402 and /balance responses points here — use POST, not GET. ### Error codes | Status | Meaning | | --- | --- | | 401 | Missing or invalid API key. Body carries `demo_key` and `purchase_url`. No usable `WWW-Authenticate` challenge — read `/.well-known/oauth-protected-resource` directly. | | 402 | No credits remaining (response includes `top_up_url` — POST to it) | | 404 | Episode not found (on `/following/{podcastId}`: no such show, or not following it) | | 409 | Declared-follow limit reached (`PUT /following/{podcastId}` only) | | 502 | Upstream error | ## Pricing New customers (POST /buy): | Credits | Price | Per credit | Parameter | | --- | --- | --- | --- | | 100 | $15 | $0.15 | default | | 500 | $50 | $0.10 | `?pack=500` | | 2,000 | $160 | $0.08 | `?pack=2000` | Returning customers (POST /top-up): | Credits | Price | Per credit | Parameter | | --- | --- | --- | --- | | 100 | $10 | $0.10 | default | | 500 | $40 | $0.08 | `&pack=500` | | 2,000 | $120 | $0.06 | `&pack=2000` | For larger runs, the 2,000-pack repeats at the same per-credit price, and the top-up ladder applies from your second purchase on. Above 10,000 episodes, email support@spoken.md before you buy. - [pricing.md](https://spoken.md/pricing.md): the same pricing in machine-readable form ## How Spoken differs from speech-to-text APIs Spoken is a transcript retrieval API, not a speech-to-text service. It works on published podcasts only, not on your own audio files. Real speaker names are included in the response — no diarization labels to map afterwards. For published podcasts this is typically 5–10x cheaper than running raw audio through Deepgram, AssemblyAI, or Whisper. - [Why Spoken](https://spoken.md/why-spoken): Spoken vs transcription APIs overview - [Spoken vs Deepgram](https://spoken.md/vs/deepgram): Spoken vs Deepgram for podcasts - [Spoken vs AssemblyAI](https://spoken.md/vs/assemblyai): Spoken vs AssemblyAI for podcasts - [Spoken vs Whisper + Pyannote](https://spoken.md/vs/whisper-diarization): Spoken vs a Whisper + Pyannote pipeline ## When Spoken is the wrong tool Spoken returns the published transcript of a podcast episode, and nothing else. It is the wrong tool when: - The audio is your own (meetings, interviews, voice memos): use a speech-to-text API. - The source is a YouTube video or livestream rather than a podcast episode: Spoken has no YouTube surface. - Search finds no episodes for the show, or a fetch returns 404: that episode has no published transcript, and retrying will not change that. - You need the transcript within minutes of release: new episodes can take several hours to become fetchable. - You need word-level timestamps, SRT/VTT captions, or audio-aligned output: Spoken returns Markdown with paragraph-level timestamps. - You need guaranteed speaker names: they are resolved automatically and usually correct, but an episode can come back with generic speaker labels. - The show is outside the major European languages (English, German, French, Spanish, Italian, Portuguese, Dutch, Swedish have the broadest coverage): if search finds episodes they are fetchable; if not, that is the answer. - You want to redistribute transcripts as a dataset or build a competing transcript API: the terms allow keeping, searching, analysing and archiving what you fetch, not that. ## Use cases - [RAG pipelines](https://spoken.md/use-cases/rag-pipelines): RAG over podcast transcripts - [Podcast summarizer](https://spoken.md/use-cases/podcast-summarizer): build a podcast summarizer in 20 lines - [Fantasy football](https://spoken.md/use-cases/fantasy-football): ask what fantasy football podcasts say about a player ## Integration MCP server: hosted at `https://spoken.md/mcp` (Streamable HTTP; send your key as `Authorization: Bearer pt_...`, or sign in with OAuth from a client that only offers that), or run locally with `npx spoken-mcp` (npm: spoken-mcp; MCP registry: io.github.spokenmd/spoken). Same tools either way: `search_podcasts`, `list_episodes`, `get_transcript`, `get_balance`, `list_following`, `follow_podcast`, `unfollow_podcast`, `list_new_episodes`. - [Agent instructions](https://spoken.md/agents.md): how an agent should use this API - [OpenAPI spec](https://spoken.md/.well-known/openapi.json): full machine-readable API description - [API catalog](https://spoken.md/.well-known/api-catalog): RFC 9727 API catalog - [Agent skills index](https://spoken.md/.well-known/agent-skills/index.json): Agent Skills discovery index - [Agent skill](https://spoken.md/.well-known/skills/spoken-md/SKILL.md): the spoken-md skill itself - [Key registration](https://spoken.md/auth.md): how an agent obtains an API key, and how an MCP client connects to the hosted endpoint - [Source repository](https://github.com/spokenmd/spoken): MCP server source - [Python client](https://pypi.org/project/spoken-md/): `pip install spoken-md`, a standard-library client and CLI with `search`, `episodes`, `transcript`, `balance`, `following`, `follow`, `unfollow`, `new` and a resumable `archive` generator - [Archive script](https://github.com/spokenmd/spoken/blob/master/examples/archive-show.sh): resumable Bash script that downloads a show's entire back catalogue, one Markdown file per episode