创作者 API
拉取你单集的文字稿、章节和关键时刻(含发言人、时间戳和来源深层链接),在任何地方再次利用。
你发布的每一个单集都充满了值得再次利用的素材:发推串用的金句、博客里的带注释文字稿、新闻通讯里的精彩片段。创作者 API 让你的脚本获得与 Studio 相同的视角:所有状态的每一个单集,草稿也包括在内,以干净的 JSON 形式提供。这样,内容再利用就变成了一条流水线,而不是花一下午来回拖动音频。
API 为每个单集提供的内容:
- 文字稿文档:每一句话都带有发言人姓名和毫秒级精确的起止时间,细到每个词的时间点。
- 章节与关键时刻:AI 提炼出的结构,即带标题的时间区间,其中归档着分类的精彩片段(洞见、金句、预测、问答……)。
- 目录行:标题、摘要、状态和
mediaUrl(YouTube 观看 URL 或 RSS enclosure),任何时间戳都能直接转换成形如watch?v=…&t=95s的来源深层链接。 - 搜索:与 Studio 搜索相同的混合排序,返回匹配片段及其引用 URL。
获取密钥
- 打开 Studio → 设置 → API 密钥(Pro 和 Studio 套餐可用)。
- 创建一个密钥。它只显示一次,请像密码一样保管(例如存为 shell 或 CI 密钥中的
PODHOOD_API_KEY)。 - 每次调用都在
x-api-key请求头中发送它(或以Authorization: Bearer podhood_…的形式发送)。
密钥属于你,而不属于某个频道:一个密钥可以读取你所属的每一个频道,在调用时实时判定;只要该频道所有者的套餐处于付费状态,密钥就有效。你可以随时在同一个设置页面撤销它,下一次请求即刻生效。
API 密钥还有一个交互式的「兄弟」:从 Claude 或 ChatGPT 连接创作者 MCP时,会改用 OAuth 登录,无需粘贴密钥;由此得到的访问令牌也能作为 Bearer 令牌用于这些 REST 端点,规则完全相同。
第一次调用
先询问你的密钥能读取哪些频道。这是一次发现性调用,把一个孤零零的密钥变成其他所有端点都用来寻址的 {slug}:
curl -H "x-api-key: $PODHOOD_API_KEY" "https://podhood.com/api/v1/channels"{
"channels": [
{
"id": "ch_1",
"slug": "latent-space",
"title": "Latent Space",
"providerType": "youtube",
"apiAccess": true
}
]
}apiAccess: false 表示该频道的所有者使用 Free 套餐,它的数据端点会返回 403。脚本因此可以提前规划调用,而不是靠报错才撞上这堵墙。
接着列出某个频道的单集,注意每一行上的 status 和 mediaUrl:
curl -H "x-api-key: $PODHOOD_API_KEY" \
"https://podhood.com/api/v1/channels/{slug}/episodes?sort=newest"{
"episodes": [
{
"id": "ep_123",
"title": "Why agents need better memory",
"status": "published",
"summary": "…",
"mediaUrl": "https://www.youtube.com/watch?v=abc123",
"durationMs": 5400000,
"publishedAt": "2026-07-18T16:00:00.000Z"
}
],
"nextCursor": null
}所有未归档状态都可见,每一行的 status 取值为 pending、processing、indexed、failed、published;可以用 status=live|queued|indexing|failed 视图过滤器缩小列表。分页采用 keyset 方式:把 nextCursor 作为 cursor 传回去,null 表示这是最后一页。
一个单集背后的三份文档
GET /api/v1/channels/{slug}/episodes # catalog rows (id, status, summary, mediaUrl, …)
GET /api/v1/episodes/{episodeId}/transcript # the transcript document
GET /api/v1/episodes/{episodeId}/chapters # chapters with key moments文字稿文档标注了发言人,并精确到每个词的时间:
{
"formatVersion": 1,
"segments": [
{
"speakerLabel": "Cat Wu",
"startMs": 65000,
"endMs": 82000,
"text": "I remember when we first came out with Claude Code…",
"words": [{ "t": "I", "s": 65000, "e": 65180 }]
}
]
}章节承载编辑骨架:带标题的时间区间,其中归档着分类的关键时刻:
[
{
"title": "How day-to-day work changed",
"startMs": 60000,
"endMs": 480000,
"moments": [
{ "type": "quote", "title": "Claude Tag lands 65% of product PRs", "startMs": 95000 }
]
}
]实践方案:带注释的文字稿文章
这是 Simon Willison 的访谈整理文章带火的格式:话题小标题、逐字且标注发言人的引文,以及每条引文都深层链接到视频中的对应时刻。API 提供全部原材料;你的编辑观点则放在引文之间。
const BASE = "https://podhood.com/api/v1";
const headers = { "x-api-key": process.env.PODHOOD_API_KEY! };
const get = async (path: string) => (await fetch(`${BASE}${path}`, { headers })).json();
// 1. Pick the episode.
const { episodes } = await get(`/channels/latent-space/episodes`);
const episode = episodes[0];
// 2. Pull its structure and its words.
const chapters = await get(`/episodes/${episode.id}/chapters`);
const transcript = await get(`/episodes/${episode.id}/transcript`);
// 3. A timestamped source deep link for any moment (YouTube: append &t=<seconds>s).
const deepLink = (ms: number) => `${episode.mediaUrl}&t=${Math.floor(ms / 1000)}s`;
const stamp = (ms: number) =>
`${Math.floor(ms / 60000)}:${String(Math.floor(ms / 1000) % 60).padStart(2, "0")}`;
// 4. One section per chapter: heading, timestamp link, and the quotes inside it.
const post = chapters.map((chapter) => {
const quotes = transcript.segments
.filter((s) => s.startMs >= chapter.startMs && s.startMs < chapter.endMs)
.map((s) => `> **${s.speakerLabel}:** ${s.text}`)
.join("\n>\n");
return `## ${chapter.title} [${stamp(chapter.startMs)}](${deepLink(chapter.startMs)})\n\n${quotes}`;
});
console.log(post.join("\n\n"));精简引文,在各节之间加上你的评论;章节的 moments 则是现成的引言候选,它们的标题本身就写成了自成一体、可引用的论断。
实践方案:为推串提取引言
搜索会直接返回最匹配的片段,每个片段都带有指向你公开单集页面上精确到秒的引用 URL:
curl -H "x-api-key: $PODHOOD_API_KEY" \
"https://podhood.com/api/v1/channels/{slug}/search?query=agent%20memory"结果中的每个单集都带有 segments[],其中包含 text、speaker、startMs 和一个绝对 url(?t= 的单位是毫秒)。引用文本、标注发言人,然后链接到引用 url(你的节目库页面)或由 mediaUrl 构造的来源深层链接:前者利于 SEO,后者面向平台原生的读者。
搜索接受与浏览相同的分面过滤器(topicIds、personIds、entityIds、episodeIds、collectionId、year),另外还有 fast=true 用于低成本的纯关键词查找。一个实用的循环:先搜索整个频道,取回返回的 episodeId,再用 episodeIds=id1,id2 搜索一次,只深挖这几个单集。
参考
| 端点 | 返回内容 |
|---|---|
GET /api/v1/channels | 你的密钥可读取的频道及其 slug |
GET /api/v1/channels/{slug}/search | 排序后的单集,附带匹配的、带时间戳的片段 |
GET /api/v1/channels/{slug}/episodes | keyset 分页的目录行,包含所有未归档状态 |
GET /api/v1/episodes/{episodeId}/transcript | 标注发言人、词级计时的文字稿文档 |
GET /api/v1/episodes/{episodeId}/chapters | 章节及其分类的关键时刻 |
GET /api/v1/episodes/{episodeId}/related | 共享话题最多的已发布单集 |
API 参考由实时的 OpenAPI 3.1 规范渲染出每一个操作,代码生成器和智能体消费的也是同一份文档。
认证、错误与限制
- 每个端点都是幂等、只读的
GET;错误始终是形如{ "error": "message" }的 JSON,绝不会是 HTML。 - 两种凭证,一个身份:API 密钥(
x-api-key,或以podhood_开头的 Bearer)或 OAuth 访问令牌(其他任何 Bearer,由创作者 MCP 登录签发)。两者的成员资格与套餐规则完全相同。 - 凭证缺失或无效返回
401(附带WWW-Authenticate质询,OAuth 客户端借此发现登录流程)。频道所有者使用 Free 套餐返回403。你不是其成员的频道,或未知 id,返回404,两者刻意不作区分。某个密钥的速率限制耗尽返回429。 - 密钥以
podhood_为前缀,泄露的密钥在密钥扫描中可以被识别。 - 稳定的版本化前缀是
/api/v1;破坏性变更会以/api/v2的形式发布,并先在即将退役的版本上加上Deprecation和Sunset头。
生产环境检查清单
- 把密钥留在服务端,绝不要下发到浏览器。
- 把
nextCursor视为不透明值,并接受响应中新增的字段。 - 给读者的链接用返回的引用
url或mediaUrl深层链接,绝不要自己重新拼接主机/路径。 - 缓存强度不要超过响应头允许的范围(带凭证的响应是
private, no-store)。 - 精确词条用
fast=true;自然语言问题保留默认的混合模式。
