API
A JSON API, no key needed, CORS open. Base URL: https://podpeopledb.com/api/v2. Please send a descriptive User-Agent. If you're forwarding contributions on behalf of your users, also send X-PodPeople-Client: yourapp/1.2.
Identifying podcasts
Wherever an endpoint takes a podcast, pass any one of podcastindex_id, feed_url, guid (the podcast:guid), or our own id.
Each person on a podcast comes with a scope: "podcast" means they're credited on the show itself (a regular), "episodes" means they're only credited on individual episodes. sources says whether the credit came from the show's feed or the community, and verified is false for community additions nobody has reviewed yet.
/podcasts/lookup?podcastindex_id=920666A podcast and its people. If we've never seen it, it's added from the Podcast Index (or its feed) and crawled first, so the first call can take a few seconds. Add add=false to only look at what we already have.
{
"podcast": { "id": 138, "podcastindex_id": 920666, "title": "Podcasting 2.0", "feed_url": "…", "has_person_tags": true, … },
"people": [
{ "person": { "id": 205, "slug": "adam-curry", "name": "Adam Curry", "img": "…", "verified": true },
"roles": ["host"], "group": "cast", "scope": "podcast", "episode_count": 208,
"sources": ["feed"], "verified": true }
],
"guests": [ … ],
"suggestions": ["Jane Example"],
"episode_count": 208
}
/podcasts/batchPeople for up to 500 podcasts in one request, from data we already have (never crawls). Unknown podcasts are left out of results. With include_episode_credits, community credits on individual episodes come along too. Feed credits are skipped there, since you have the feed.
{ "podcasts": [{ "podcastindex_id": 920666 }, { "feed_url": "https://example.com/feed.xml" }],
"include_episode_credits": true }
/podcasts/{id} · /podcasts/{id}/episodes?limit=20&offset=0By our id. Episodes come newest first, each with its people.
/episodes/lookup?podcastindex_id=…&episode_guid=…One episode's credits, by podcast plus episode_guid or enclosure_url.
/podcasts/search?q=…Podcasts we have (local), plus Podcast Index matches we don't have yet (index).
/people/search?q=…Typeahead-friendly person search: exact matches first, then prefix matches, ranked by how many shows someone is on. known_for lists a few of their shows to tell namesakes apart.
/people/{id} · /people/{id}/episodes?limit=50&offset=0A person, every podcast they're on, and the episodes they're individually credited on. If the id belonged to someone who was merged into another person, you get the merged person and merged_from tells you to update the id you stored.
/submissionsAdd people to a podcast, or to one episode. Live immediately (unverified). Names that exactly match an existing person reuse them; pass person_id to pick someone specific. Role defaults to host on a podcast and guest on an episode.
{
"podcast": { "podcastindex_id": 920666 },
"episode": { "guid": "…", "enclosure_url": "…", "title": "Episode 200" }, // optional
"people": [ { "name": "Jane Example", "role": "co-host" }, { "person_id": 205 } ],
"instance_id": "random-id-for-your-installation" // optional
}
Podcasts with no public feed can be created on the fly by passing "podcast": {"title": "…", "link": "…"}. Rate limited per IP.
/people/{id}/editUpdate name, bio, img or website. Only the fields you send change; an empty string clears a field.
/discover/top-people · /discover/recent-people · /discover/popular-podcasts · /statsMirroring
/changes?since=2026-10-01T00:00:00ZEverything public that changed since a timestamp (RFC 3339 or Unix seconds): people, podcasts, episodes (only credited ones), credits and deletions. Store the response's until and pass it as since next time. /dump is the same thing from the beginning of time. There's also a SQLite download.
v1 endpoints
/api/hosts/{podcastindex_id}, /api/host-search?name=, /api/podcast/{podcastindex_id} and /api/discover/* still work with their old response shapes, so older Pinepods versions keep working. New code should use v2.