Appearance
API reference · API keys · Analytics API guide
Downloads for an episode over time
- Method:
GET - Path:
/v1/me/episodes/{episode_id}/analytics/downloads - Operation ID:
getEpisodeDownloads - Tags: Analytics
As the podcast series, for one episode, plus its all-time and first-week totals. Requires permission to see live analytics and use the analytics API (analytics.view). Every analytics response carries meta.range (the window used, after your plan's history limit), meta.freshness (how complete the figures are) and meta.methodology.
Scope: analytics:read.
Make a request
Set these environment variables before running a sample. Each language reads the same values; no identifier needs replacing inside the code.
| Variable | Value to supply |
|---|---|
SHOWFM_API_KEY | Your API key. Keep it on your server. |
EPISODE_ID | An episode UUID returned by your episode list, or the public episode list for a public request. |
Samples run on your server: curl 7.76+, Node.js 22+ (TypeScript via your TypeScript runner), Python 3, or PHP 8 with the cURL extension. Never put your API key in browser code.
bash
: "${SHOWFM_API_KEY:?Set SHOWFM_API_KEY in your environment}"
: "${EPISODE_ID:?Set EPISODE_ID in your environment}"
curl --fail-with-body --silent --show-error --get \
"https://api.show.fm/v1/me/episodes/${EPISODE_ID}/analytics/downloads" \
--header "Authorization: Bearer ${SHOWFM_API_KEY}"ts
function env(name: string): string {
const value = process.env[name];
if (!value) throw new Error(`Set ${name} in your environment`);
return value;
}
async function main() {
const url = new URL(`https://api.show.fm/v1/me/episodes/${encodeURIComponent(env("EPISODE_ID"))}/analytics/downloads`);
const response = await fetch(url, {
headers: { Authorization: `Bearer ${env("SHOWFM_API_KEY")}` },
signal: AbortSignal.timeout(30_000)
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${await response.text()}`);
}
console.log(JSON.stringify(await response.json(), null, 2));
}
main().catch(error => {
console.error(error);
process.exitCode = 1;
});js
function env(name) {
const value = process.env[name];
if (!value) throw new Error(`Set ${name} in your environment`);
return value;
}
async function main() {
const url = new URL(`https://api.show.fm/v1/me/episodes/${encodeURIComponent(env("EPISODE_ID"))}/analytics/downloads`);
const response = await fetch(url, {
headers: { Authorization: `Bearer ${env("SHOWFM_API_KEY")}` },
signal: AbortSignal.timeout(30_000)
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${await response.text()}`);
}
console.log(JSON.stringify(await response.json(), null, 2));
}
main().catch(error => {
console.error(error);
process.exitCode = 1;
});python
import os
import json
from urllib.parse import quote, urlencode
from urllib.request import Request, urlopen
from urllib.error import HTTPError
url = f'https://api.show.fm/v1/me/episodes/{quote(os.environ["EPISODE_ID"], safe="")}/analytics/downloads'
request = Request(url, headers={
"Authorization": "Bearer " + os.environ["SHOWFM_API_KEY"]
})
try:
with urlopen(request, timeout=30) as response:
print(json.dumps(json.load(response), indent=2))
except HTTPError as error:
raise RuntimeError(f"HTTP {error.code}: {error.read().decode()}") from errorphp
<?php
function requiredEnv(string $name): string {
$value = getenv($name);
if ($value === false || $value === '') {
throw new RuntimeException("Set $name in your environment");
}
return $value;
}
$url = "https://api.show.fm" . "/v1/me/episodes/" . rawurlencode(requiredEnv("EPISODE_ID")) . "/analytics/downloads";
$curl = curl_init($url);
curl_setopt_array($curl, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTPHEADER => ["Authorization: Bearer " . requiredEnv("SHOWFM_API_KEY")],
]);
$body = curl_exec($curl);
if ($body === false) {
throw new RuntimeException(curl_error($curl));
}
$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
if ($status < 200 || $status >= 300) {
throw new RuntimeException("HTTP $status: $body");
}
echo json_encode(json_decode($body, false, 512, JSON_THROW_ON_ERROR), JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR) . PHP_EOL;Base URL
https://api.show.fm
Authentication
apiKey: HTTP bearer
An API key from Settings → API keys.
showfm_live_in production.
Path parameters
episode_id(required):string, format:uuidThe episode id (UUID).
Query parameters
preset:string, possible values:"7d", "30d", "90d", "12m", "all"A named range ending today (UTC):
7d,30d,90d,12morall. Default30d. Do not combine withfromorto.from:string, format:dateFirst UTC day,
YYYY-MM-DD. Not after today.to:string, format:dateLast UTC day,
YYYY-MM-DD. Needsfrom. Default today.interval:string, possible values:"day", "week", "month", default:"day"day(default),week(ISO weeks, Monday start) ormonth, in UTC. A daily series is limited to 1,100 days.
Responses
Browse the documented response statuses, headers and body fields.
200 OK
Response headers
RateLimit-PolicyThe bucket that applied, e.g.
"account";q=60;w=60.stringRateLimitRequests left and seconds to reset, e.g.
"account";r=59;t=42.stringETagstring
Response body
Content type: application/json
no additional properties
data(required): EpisodeDownloadsmeta(required): AnalyticsMeta
304 Not modified (matching If-None-Match).
If-None-Match). This response has no body.
400, 401, 403, 404, 500, 503
400invalid_request: a bad parameter, or a key sent in the URL.401unauthorized(no Bearer key) orinvalid_api_key.403insufficient_scope,forbidden(role or team-key setting) orplan_upgrade_required.404not_found: the key cannot reach this resource.500internal_error. Retry; quoteX-Request-Idif it persists.503service_unavailable. Retry shortly.
Response body
Content type: application/json
schema: Error, no additional properties
error(required):object, no additional propertiescode(required):string, possible values:"invalid_request", "not_found", "unavailable", "unauthorized", "invalid_api_key", "insufficient_scope", "forbidden", "plan_upgrade_required", "rate_limited", "service_unavailable", "internal_error", "not_implemented"message(required):stringdetails:arrayItems:
no additional properties
field(required):stringmessage(required):stringreason:stringA stable reason a client may branch on, for example
outside_retention.
docs_url:stringrequest_id:string
429 rate_limited. Wait for Retry-After seconds.
rate_limited. Wait for Retry-After seconds. Response headers
Retry-AfterintegerRateLimit-PolicyThe bucket that applied, e.g.
"account";q=60;w=60.stringRateLimitRequests left and seconds to reset, e.g.
"account";r=59;t=42.string
Response body
Content type: application/json
Uses the shared Error schema. View response fields.