Official TypeScript/JavaScript SDK for the Pod Engine podcast intelligence API β search 4M+ podcasts, pull rich metadata, transcripts, charts, reviews, guest profiles and more, with full type safety.
- π¦ Fully typed β every method's parameters and responses are generated from the API's OpenAPI spec, so your editor autocompletes the entire surface.
- π§© Ergonomic β resources are grouped by domain:
pe.podcasts.getPodcast(...),pe.charts.getLatestChart(...),pe.search.searchPodcasts(...). - πͺΆ Lightweight β zero runtime dependencies. Uses the platform
fetch. - π Resilient β automatic retries with backoff for transient failures (429 / 5xx).
- ποΈ Smart dates β ISO timestamps are hydrated into real
Dateobjects.
npm install @podengine/sdk
# or: pnpm add @podengine/sdk / yarn add @podengine/sdk / bun add @podengine/sdkRequires Node 18+ (or any runtime with a global fetch).
import { PodEngine } from '@podengine/sdk';
const pe = new PodEngine({ apiKey: process.env.PODENGINE_API_KEY! });
// Search podcasts
const { result } = await pe.search.searchPodcasts({
searchTerms: [
{
searchTerm: 'startups',
searchType: 'text',
searchTargets: ['podcast-title', 'podcast-description'],
searchTermOptions: { matchMode: 'optional' },
},
],
});
// Get the latest Apple chart
const chart = await pe.charts.getLatestChart({
chartType: 'apple',
country: 'us',
category: 'top podcasts',
});
// Fetch a podcast (by ID or slug) and its episodes
const { podcast } = await pe.podcasts.getPodcast({ podcastIdOrSlug: 'the-tim-ferriss-show' });
const episodes = await pe.podcasts.getPodcastEpisodes({ podcastIdOrSlug: podcast.id });Get an API key at https://www.podengine.ai/solutions/podcast-api.
Pass your API key when constructing the client. It is sent on every request.
const pe = new PodEngine({ apiKey: 'pe_live_...' });const pe = new PodEngine({
apiKey: process.env.PODENGINE_API_KEY!,
baseUrl: 'https://api.podengine.ai', // override for staging/self-host
source: 'my-app', // sent as the x-source header for attribution
timeout: 30_000, // per-attempt timeout in ms (default: none)
totalTimeout: 60_000, // overall deadline in ms (default: 60 seconds)
maxRetries: 2, // retries for 429/5xx/network (default: 2)
headers: { 'x-team': 'growth' }, // extra headers on every request
fetch: customFetch, // inject a custom fetch implementation
});Every method also accepts per-call options as a final argument:
const controller = new AbortController();
const chart = await pe.charts.getLatestChart(
{ chartType: 'apple', country: 'us', category: 'top podcasts' },
{ signal: controller.signal, timeout: 5_000, totalTimeout: 15_000, headers: { 'x-trace': '1' } }
);For apps, agents and data pipelines, totalTimeout bounds the full call, including attempts, retry waits and response reads. It defaults to 60 seconds. Set a positive number on the client or a single call to change it, or null to disable it. timeout continues to limit each attempt separately.
A valid Retry-After sets the minimum wait before a retry, with 1β250 ms of added jitter. If that wait cannot fit within the remaining deadline, the call raises PodEngineConnectionError immediately. It does not retry early. Expired deadlines also raise PodEngineConnectionError. Caller aborts interrupt attempts, waits and response reads, and preserve the caller's abort reason.
// Plain-text transcript
const { episodeTranscriptText } = await pe.episodes.getEpisodeTranscriptText({ episodeId });
console.log(episodeTranscriptText.text);
// Download a transcript file (returned as a Blob)
const file = await pe.episodes.downloadEpisodeTranscript({ episodeId, format: 'vtt' });
// Request a transcription if one doesn't exist yet
await pe.transcriptions.requestEpisodeTranscription({ episodeId });const categories = await pe.charts.getCategoriesByChartType({ chartType: 'apple' });
const chart = await pe.charts.getChart({
chartType: 'apple',
country: 'us',
category: 'top podcasts',
date: '2024-06-01',
});const profile = await pe.guestProfiles.createGuestProfile({
firstName: 'Ada',
lastName: 'Lovelace',
shortBio: 'Mathematician and writer.',
});
await pe.guestProfiles.updateGuestProfileSocialMediaLinks({
guestProfileId: profile.guestProfileId,
body: [{ socialMediaType: 'twitter', url: 'https://x.com/ada' }],
});All failures throw a PodEngineError subclass:
import { PodEngine, PodEngineApiError, PodEngineConnectionError } from '@podengine/sdk';
try {
await pe.podcasts.getPodcast({ podcastIdOrSlug: 'does-not-exist' });
} catch (err) {
if (err instanceof PodEngineApiError) {
console.error(err.status); // e.g. 404
console.error(err.message); // server-provided message
console.error(err.requestId); // x-request-id, if present
console.error(err.body); // raw parsed error body
} else if (err instanceof PodEngineConnectionError) {
console.error('Network/timeout:', err.message);
}
}Parameter and response types are exported for every operation, named <Operation>Params and
<Operation>Response:
import type { SearchPodcastsParams, GetLatestChartResponse } from '@podengine/sdk';
function buildQuery(): SearchPodcastsParams {
return {
pageSize: 25,
searchTerms: [
{
searchTerm: 'climate',
searchType: 'text',
searchTargets: ['podcast-title', 'podcast-description'],
searchTermOptions: { matchMode: 'optional' },
},
],
};
}The raw OpenAPI types are also available via import type { schema } from '@podengine/sdk', and
the spec itself ships in the package: import spec from 'podengine/openapi.json'.
pe.agent, pe.alerts, pe.autocomplete, pe.charts, pe.episodes, pe.guestProfiles,
pe.podcasts, pe.polling, pe.projects, pe.search, pe.stats, pe.teams,
pe.transcriptions, pe.usage.
See the full interactive reference at https://www.podengine.ai/api-docs.
Found a bug or want an endpoint added? Please open an issue β we read every one.
This SDK is generated from the Pod Engine API's OpenAPI spec, and this repository is an automatically-synced mirror, so direct pull requests to generated files are overwritten on the next sync. See CONTRIBUTING.md for how to get a change landed.