Find Potential Sponsors for Your Podcast
Research brands appearing on similar podcasts and build a shortlist for your next sponsorship pitch.
Before you start
- API token
- The Pod Engine ID or slug of a similar podcast
Choose your example
Your selection applies to every step. HTTP uses built-in clients without the Pod Engine libraries.
Use Node.js 22 or newer. Save the complete script as recipe.mjs.
npm install @podengine/sdk
# macOS / Linux shell; set the same variable in your shell on Windows
export PODENGINE_API_KEY="YOUR_API_KEY"
node recipe.mjs Use Node.js 22 or newer. Save the complete script as recipe.mjs. No package installation is needed.
# macOS / Linux shell; set the same variable in your shell on Windows
export PODENGINE_API_KEY="YOUR_API_KEY"
node recipe.mjs Use Python 3.10 or newer. Save the complete script as recipe.py.
python -m pip install podengine
# macOS / Linux shell; set the same variable in your shell on Windows
export PODENGINE_API_KEY="YOUR_API_KEY"
python recipe.py Use Python 3.10 or newer. Save the complete script as recipe.py. No package installation is needed.
# macOS / Linux shell; set the same variable in your shell on Windows
export PODENGINE_API_KEY="YOUR_API_KEY"
python recipe.py Set up the client
Start your file with this setup, then append each step in order. The complete script below includes everything.
import { PodEngine } from '@podengine/sdk';
const apiKey = process.env.PODENGINE_API_KEY;
if (!apiKey) throw new Error('Set PODENGINE_API_KEY before running this recipe');
const pe = new PodEngine({
apiKey,
baseUrl: process.env.PODENGINE_API_URL || 'https://api.podengine.ai',
}); const apiKey = process.env.PODENGINE_API_KEY;
if (!apiKey) throw new Error('Set PODENGINE_API_KEY before running this recipe');
const baseUrl = process.env.PODENGINE_API_URL || 'https://api.podengine.ai';
async function request(path, body) {
const response = await fetch(`${baseUrl}${path}`, {
method: body === undefined ? 'GET' : 'POST',
headers: { Authorization: apiKey, 'Content-Type': 'application/json' },
...(body === undefined ? {} : { body: JSON.stringify(body) }),
});
if (!response.ok) throw new Error(`Pod Engine request failed: ${response.status} ${response.statusText}`);
return (await response.json()).data;
} import os
from podengine import PodEngine
pe = PodEngine(
api_key=os.environ["PODENGINE_API_KEY"],
base_url=os.environ.get("PODENGINE_API_URL", "https://api.podengine.ai"),
) import json
import os
from urllib.parse import urlencode, quote
from urllib.request import Request, urlopen
api_key = os.environ["PODENGINE_API_KEY"]
base_url = os.environ.get("PODENGINE_API_URL", "https://api.podengine.ai")
def request(path, body=None):
req = Request(
base_url + path,
data=json.dumps(body).encode() if body is not None else None,
headers={"Authorization": api_key, "Content-Type": "application/json"},
method="POST" if body is not None else "GET",
)
# urlopen raises HTTPError for non-success responses.
with urlopen(req, timeout=30) as response:
return json.load(response)["data"] Complete runnable script
import { PodEngine } from '@podengine/sdk';
const apiKey = process.env.PODENGINE_API_KEY;
if (!apiKey) throw new Error('Set PODENGINE_API_KEY before running this recipe');
const pe = new PodEngine({
apiKey,
baseUrl: process.env.PODENGINE_API_URL || 'https://api.podengine.ai',
});
const podcastIdOrSlug = 'this-week-in-startups';
const { podcast, sponsors: summary } = await pe.podcasts.getPodcastSponsors({ podcastIdOrSlug, sinceDays: 90 });
console.table([
{
podcast: podcast.title,
analyzedEpisodes: summary.episodesCount,
oldestAnalyzedEpisode: summary.oldestEpisodeDate,
newestAnalyzedEpisode: summary.mostRecentEpisodeDate,
},
]);
const shortlist = [...summary.sponsors]
.sort(
(a, b) =>
b.appearancesCount - a.appearancesCount ||
new Date(b.mostRecentAppearanceDate).getTime() - new Date(a.mostRecentAppearanceDate).getTime()
)
.slice(0, 10)
.map((item) => ({
name: item.name,
appearances: item.appearancesCount,
latestAppearance: item.mostRecentAppearanceDate,
sourcePodcast: podcast.title,
}));
if (summary.episodesCount === 0) {
console.info('No analyzed episodes. Try a wider window or another show.');
} else if (!shortlist.length) {
console.info('No sponsors returned from the analyzed episodes.');
} else {
console.table(shortlist);
} const apiKey = process.env.PODENGINE_API_KEY;
if (!apiKey) throw new Error('Set PODENGINE_API_KEY before running this recipe');
const baseUrl = process.env.PODENGINE_API_URL || 'https://api.podengine.ai';
async function request(path, body) {
const response = await fetch(`${baseUrl}${path}`, {
method: body === undefined ? 'GET' : 'POST',
headers: { Authorization: apiKey, 'Content-Type': 'application/json' },
...(body === undefined ? {} : { body: JSON.stringify(body) }),
});
if (!response.ok) throw new Error(`Pod Engine request failed: ${response.status} ${response.statusText}`);
return (await response.json()).data;
}
const podcastIdOrSlug = 'this-week-in-startups';
const { podcast, sponsors: summary } = await request(
`/api/v1/podcasts/${encodeURIComponent(podcastIdOrSlug)}/sponsors?${new URLSearchParams({ sinceDays: '90' })}`
);
console.table([
{
podcast: podcast.title,
analyzedEpisodes: summary.episodesCount,
oldestAnalyzedEpisode: summary.oldestEpisodeDate,
newestAnalyzedEpisode: summary.mostRecentEpisodeDate,
},
]);
const shortlist = [...summary.sponsors]
.sort(
(a, b) =>
b.appearancesCount - a.appearancesCount ||
new Date(b.mostRecentAppearanceDate).getTime() - new Date(a.mostRecentAppearanceDate).getTime()
)
.slice(0, 10)
.map((item) => ({
name: item.name,
appearances: item.appearancesCount,
latestAppearance: item.mostRecentAppearanceDate,
sourcePodcast: podcast.title,
}));
if (summary.episodesCount === 0) {
console.info('No analyzed episodes. Try a wider window or another show.');
} else if (!shortlist.length) {
console.info('No sponsors returned from the analyzed episodes.');
} else {
console.table(shortlist);
} import os
from podengine import PodEngine
pe = PodEngine(
api_key=os.environ["PODENGINE_API_KEY"],
base_url=os.environ.get("PODENGINE_API_URL", "https://api.podengine.ai"),
)
podcast_id_or_slug = "this-week-in-startups"
data = pe.podcasts.get_podcast_sponsors(
podcast_id_or_slug=podcast_id_or_slug, since_days=90
).model_dump(by_alias=True, mode="json")
podcast, summary = data["podcast"], data["sponsors"]
print(
{
"podcast": podcast["title"],
"analyzedEpisodes": summary["episodesCount"],
"oldestAnalyzedEpisode": summary["oldestEpisodeDate"],
"newestAnalyzedEpisode": summary["mostRecentEpisodeDate"],
}
)
shortlist = sorted(
summary["sponsors"],
key=lambda item: (item["appearancesCount"], item["mostRecentAppearanceDate"]),
reverse=True,
)[:10]
if summary["episodesCount"] == 0:
print("No analyzed episodes. Try a wider window or another show.")
elif not shortlist:
print("No sponsors returned from the analyzed episodes.")
else:
for item in shortlist:
print(
{
"name": item["name"],
"appearances": item["appearancesCount"],
"latestAppearance": item["mostRecentAppearanceDate"],
"sourcePodcast": podcast["title"],
}
) import json
import os
from urllib.parse import urlencode, quote
from urllib.request import Request, urlopen
api_key = os.environ["PODENGINE_API_KEY"]
base_url = os.environ.get("PODENGINE_API_URL", "https://api.podengine.ai")
def request(path, body=None):
req = Request(
base_url + path,
data=json.dumps(body).encode() if body is not None else None,
headers={"Authorization": api_key, "Content-Type": "application/json"},
method="POST" if body is not None else "GET",
)
# urlopen raises HTTPError for non-success responses.
with urlopen(req, timeout=30) as response:
return json.load(response)["data"]
podcast_id_or_slug = "this-week-in-startups"
data = request(
f"/api/v1/podcasts/{quote(podcast_id_or_slug, safe='')}/sponsors?"
+ urlencode({"sinceDays": 90})
)
podcast, summary = data["podcast"], data["sponsors"]
print(
{
"podcast": podcast["title"],
"analyzedEpisodes": summary["episodesCount"],
"oldestAnalyzedEpisode": summary["oldestEpisodeDate"],
"newestAnalyzedEpisode": summary["mostRecentEpisodeDate"],
}
)
shortlist = sorted(
summary["sponsors"],
key=lambda item: (item["appearancesCount"], item["mostRecentAppearanceDate"]),
reverse=True,
)[:10]
if summary["episodesCount"] == 0:
print("No analyzed episodes. Try a wider window or another show.")
elif not shortlist:
print("No sponsors returned from the analyzed episodes.")
else:
for item in shortlist:
print(
{
"name": item["name"],
"appearances": item["appearancesCount"],
"latestAppearance": item["mostRecentAppearanceDate"],
"sourcePodcast": podcast["title"],
}
) Choose a show whose audience shares interests with yours. Brands mentioned as sponsors or advertisers on that show are a starting point for researching potential partners.
Choose your language and SDK or HTTP above. Run the setup first, then append each step to the same file. Replace the example podcast slug with your chosen show.
Request the Podcast Sponsors endpoint with sinceDays=90. In the HTTP response, the summary is at data.sponsors, with the brands at data.sponsors.sponsors. Results include both sponsors and advertisers.
const podcastIdOrSlug = 'this-week-in-startups';
const { podcast, sponsors: summary } = await pe.podcasts.getPodcastSponsors({ podcastIdOrSlug, sinceDays: 90 });
console.table([
{
podcast: podcast.title,
analyzedEpisodes: summary.episodesCount,
oldestAnalyzedEpisode: summary.oldestEpisodeDate,
newestAnalyzedEpisode: summary.mostRecentEpisodeDate,
},
]); const podcastIdOrSlug = 'this-week-in-startups';
const { podcast, sponsors: summary } = await request(
`/api/v1/podcasts/${encodeURIComponent(podcastIdOrSlug)}/sponsors?${new URLSearchParams({ sinceDays: '90' })}`
);
console.table([
{
podcast: podcast.title,
analyzedEpisodes: summary.episodesCount,
oldestAnalyzedEpisode: summary.oldestEpisodeDate,
newestAnalyzedEpisode: summary.mostRecentEpisodeDate,
},
]); podcast_id_or_slug = "this-week-in-startups"
data = pe.podcasts.get_podcast_sponsors(
podcast_id_or_slug=podcast_id_or_slug, since_days=90
).model_dump(by_alias=True, mode="json")
podcast, summary = data["podcast"], data["sponsors"]
print(
{
"podcast": podcast["title"],
"analyzedEpisodes": summary["episodesCount"],
"oldestAnalyzedEpisode": summary["oldestEpisodeDate"],
"newestAnalyzedEpisode": summary["mostRecentEpisodeDate"],
}
) podcast_id_or_slug = "this-week-in-startups"
data = request(
f"/api/v1/podcasts/{quote(podcast_id_or_slug, safe='')}/sponsors?"
+ urlencode({"sinceDays": 90})
)
podcast, summary = data["podcast"], data["sponsors"]
print(
{
"podcast": podcast["title"],
"analyzedEpisodes": summary["episodesCount"],
"oldestAnalyzedEpisode": summary["oldestEpisodeDate"],
"newestAnalyzedEpisode": summary["mostRecentEpisodeDate"],
}
) - sinceDays accepts whole numbers from 1 to 365. Without it, the endpoint uses the last 10 episodes and may run missing AI analysis on demand.
- Windowed requests only use existing analysis and do not trigger new AI analysis. episodesCount counts analyzed episodes, not every episode in the window.
- Only the 500 newest episodes in the window are considered. Episodes without analysis are skipped, so some sponsors may be missing.
Append this code to the same file. It ranks brands by their returned appearance counts, using the latest appearance to break ties, and keeps ten prospects.
Review the analyzed episode count and date range before comparing shows. A show with more analyzed episodes has more opportunities to surface sponsor mentions. An empty list does not establish that the show has no sponsors; when no analyzed episodes are included, the summary dates are null.
const shortlist = [...summary.sponsors]
.sort(
(a, b) =>
b.appearancesCount - a.appearancesCount ||
new Date(b.mostRecentAppearanceDate).getTime() - new Date(a.mostRecentAppearanceDate).getTime()
)
.slice(0, 10)
.map((item) => ({
name: item.name,
appearances: item.appearancesCount,
latestAppearance: item.mostRecentAppearanceDate,
sourcePodcast: podcast.title,
}));
if (summary.episodesCount === 0) {
console.info('No analyzed episodes. Try a wider window or another show.');
} else if (!shortlist.length) {
console.info('No sponsors returned from the analyzed episodes.');
} else {
console.table(shortlist);
} const shortlist = [...summary.sponsors]
.sort(
(a, b) =>
b.appearancesCount - a.appearancesCount ||
new Date(b.mostRecentAppearanceDate).getTime() - new Date(a.mostRecentAppearanceDate).getTime()
)
.slice(0, 10)
.map((item) => ({
name: item.name,
appearances: item.appearancesCount,
latestAppearance: item.mostRecentAppearanceDate,
sourcePodcast: podcast.title,
}));
if (summary.episodesCount === 0) {
console.info('No analyzed episodes. Try a wider window or another show.');
} else if (!shortlist.length) {
console.info('No sponsors returned from the analyzed episodes.');
} else {
console.table(shortlist);
} shortlist = sorted(
summary["sponsors"],
key=lambda item: (item["appearancesCount"], item["mostRecentAppearanceDate"]),
reverse=True,
)[:10]
if summary["episodesCount"] == 0:
print("No analyzed episodes. Try a wider window or another show.")
elif not shortlist:
print("No sponsors returned from the analyzed episodes.")
else:
for item in shortlist:
print(
{
"name": item["name"],
"appearances": item["appearancesCount"],
"latestAppearance": item["mostRecentAppearanceDate"],
"sourcePodcast": podcast["title"],
}
) shortlist = sorted(
summary["sponsors"],
key=lambda item: (item["appearancesCount"], item["mostRecentAppearanceDate"]),
reverse=True,
)[:10]
if summary["episodesCount"] == 0:
print("No analyzed episodes. Try a wider window or another show.")
elif not shortlist:
print("No sponsors returned from the analyzed episodes.")
else:
for item in shortlist:
print(
{
"name": item["name"],
"appearances": item["appearancesCount"],
"latestAppearance": item["mostRecentAppearanceDate"],
"sourcePodcast": podcast["title"],
}
) - Appearance dates refer to episode publication dates. They do not establish when an ad campaign ran or whether it is still active.
- Appearance counts are research signals, not ad spend, campaign budgets, or proof that a brand is buying new placements.
Repeat the request for a few comparable podcasts and keep each brand's source show and latest appearance in your research notes. Check brand identity before merging names from different shows.
For each promising brand, review the relevant podcast and the brand's current product offering. Write down why your listeners would benefit, then prepare a pitch with your audience profile, episode format, and a specific sponsorship idea.
Use the brand's public partnerships or advertising contact channel for outreach. The summary provides brand names, appearance counts, and dates; it does not include contact details, rates, or confirmation that the brand wants to sponsor your show.