View on GitHub

docs-api

Developer documentation for the podcastindex.org api.

Podcast Index banner

Podcast Index API Documentation

v1.3.5 - 2020.09.16


Homepage Developers Documentation Example Code

Basics

Sending an api request is easy. We use an Amazon style request authorization token to secure each request.

These are the required headers for each request:



Endpoints

Note that all parameters passed should be url encoded where necessary. There is a default count of 40 items returned for most calls if the “max” param isn’t used.


Searching

/api/1.0/search/byterm” - Pass a search term to look for with ?q=[search terms].

Example: GET https://api.podcastindex.org/api/1.0/search/byterm?q=batman+university

This call returns all of the feeds that match the search terms in the title of the feed.

This is ordered by the last-released episode, with the latest at the top of the results.


Podcasts

/api/1.0/podcasts/byfeedurl” - Pass a feed url with ?url=[feed url].

Example: GET https://api.podcastindex.org/api/1.0/podcasts/byfeedurl?url=https://feeds.theincomparable.com/batmanuniversity

This call returns everything we know about the feed.


/api/1.0/podcasts/byfeedid” - Pass a feed id with ?id=[feed id].

Example: GET https://api.podcastindex.org/api/1.0/podcasts/byfeedid?id=75075

This call returns everything we know about the feed.


/api/1.0/podcasts/byitunesid” - Pass an itunes id with ?id=[itunes id].

Example: GET https://api.podcastindex.org/api/1.0/podcasts/byitunesid?id=1441923632

If we have an itunes id on file for a feed, then this call returns everything we know about that feed.


Episodes

/api/1.0/episodes/byfeedid” - Pass a feed id with ?id=[id]. This can be a list of multiple feed ids separated with a comma.

Example: GET https://api.podcastindex.org/api/1.0/episodes/byfeedid?id=75075

This call returns all the episodes we know about for this feed, in reverse chronological order.


/api/1.0/episodes/byfeedurl” - Pass a feed url with ?url=[feed url].

Example: GET https://api.podcastindex.org/api/1.0/episodes/byfeedurl?url=https://feeds.theincomparable.com/batmanuniversity

This call returns all the episodes we know about for this feed, in reverse chronological order.


/api/1.0/episodes/byitunesid” - Pass an itunes id with ?id=[itunes id].

Example: GET https://api.podcastindex.org/api/1.0/episodes/byitunesid?id=1441923632

If we have an itunes id on file for a feed, then this call returns all the episodes we know about for the feed, in reverse chronological order.


/api/1.0/episodes/byid” - Pass an episode id with ?id=[id].

Example: GET https://api.podcastindex.org/api/1.0/episodes/byid?id=16795090

Get all the metadata for a single episode by passing its id.


/api/1.0/episodes/random” - Pass the count you want with ?max=[count].

Example: GET https://api.podcastindex.org/api/1.0/episodes/random?notcat=News,Religion&lang=en,es

This call returns a random batch of [max] episodes, in no specific order.


Recent

/api/1.0/recent/episodes” - Pass the count you want with ?max=[count].

Example: GET https://api.podcastindex.org/api/1.0/recent/episodes?max=7

This call returns the most recent [max] number of episodes globally across the whole index, in reverse chronological order.


/api/1.0/recent/feeds” - Pass the count you want with ?max=[count].

Example: GET https://api.podcastindex.org/api/1.0/recent/feeds?max=20&cat=102,health&lang=de,ja

This call returns the most recent [max] feeds, in reverse chronological order.


/api/1.0/recent/newfeeds

Example: GET https://api.podcastindex.org/api/1.0/recent/newfeeds

This call returns every new feed added to the index over the past 24 hours in reverse chronological order.


/api/1.0/recent/soundbites

Example: GET https://api.podcastindex.org/api/1.0/recent/soundbites

This call returns the most recent 60 soundbites that the index has discovered. A soundbite consists of an enclosure url, a start time and a duration. It is documented in the “podcast” namespace here.


Adding

/api/1.0/add/byfeedurl” - POST/GET - Pass a feed url with ?url=[feed url].

Example: POST/GET https://api.podcastindex.org/api/1.0/add/byfeedurl?url=https://feeds.theincomparable.com/batmanuniversity

**This call requires a read-write api key.

This call adds a podcast to the index using its feed url. If a feed already exists, you will get its existing feed id returned.


/api/1.0/add/byitunesid” - POST/GET - Pass an itunes id with ?id=[id].

Example: POST/GET https://api.podcastindex.org/api/1.0/add/byitunesid?id=1441923632

**This call requires a read-write api key.

This call adds a podcast to the index using its itunes id. If a feed already exists, it will be noted in the response.


/api/1.0/add/batch/byfeedurl” - POST - Pass an array of urls in a form encoded post request.

Example: POST https://api.podcastindex.org/api/1.0/add/batch/byfeedurl

Form data:

**This call requires a publisher api key. Available by request/approval.

This call adds multiple feed urls at once. It returns an array listing the results of each one. If the feed existed already, or if it was added, you will get back its podcastindex.org feed id. If we have linkage to an itunes id for this feed it will be returned as well. There are also “error” and “valid” properties returned. A false in the “valid” property indicates the feed url was structurally invalid. A true in the “error” property indicates something went wrong internally while adding the feed.



Return Values

By default, all responses are in JSON format if nothing different is specified. You can ask for a different data type by adding responseType=[type] where [type] is one of the values listed below.

These are the response data types we support:



Optional Parameters

There are various optional parameters you can pass when calling API endpoints to modify the reponses. Some are boolean true by their presence (like “itunes”), while others require a value to be passed.

Here is the current list:



Response Structure (Podcasts/Feeds)

We give you everything we know about the feed. Here is a breakdown of the different values and their meaning. You can expect additional properties to be added going forward. We attempt to “normalize” podcast feeds into a predictable property set, to minimize the need for vendor specifics and namespaces.

{
    "status": "true",
    "feeds": [
    {
        "id": 75075,
        "title": "Batman University",
        "url": "https:\/\/feeds.theincomparable.com\/batmanuniversity",
        "originalUrl": "https:\/\/feeds.theincomparable.com\/batmanuniversity",
        "link": "https:\/\/www.theincomparable.com\/batmanuniversity\/",
        "description": "Batman University is a seasonal podcast about you know who...",
        "author": "Tony Sindelar",
        "ownerName": "The Incomparable",
        "image": "https:\/\/www.theincomparable.com\/imgs\/logos\/logo-batmanuniversity-3x.jpg",
        "artwork": "https:\/\/www.theincomparable.com\/imgs\/logos\/logo-batmanuniversity-3x.jpg",
        "lastUpdateTime": 1546399813,
        "lastCrawlTime": 1599328949,
        "lastParseTime": 1599012694,
        "lastGoodHttpStatusTime": 1599328949,
        "lastHttpStatus": 200,
        "contentType": "application\/x-rss+xml",
        "itunesId": 1441923632,
        "generator": null,
        "language" : "en-us",
        "type": 0,
        "dead": 0,
        "crawlErrors": 0,
        "parseErrors": 0,
        "categories": {
            "104": "TV",
            "105": "Film",
            "107": "Reviews"
        }
    }
    ],
    "count": 1,
    "query": "batman university",
    "description": "Found matching feeds."
}

** Note that when we return properties for episodes, we also send back some of what we consider critical info about the feed the episode came from. For these properies, we just prepend “feed” to the front of the camel-cased version of the property name. For instance, “language” becomes “feedLanguage”.



Example code

Here are some examples to get you started.

PHP

//Required values
$apiKey = "UXKCGDSYGUUEVQJSYDZH";
$apiSecret = "yzJe2eE7XV-3eY576dyRZ6wXyAbndh6LUrCZ8KN|";
$apiHeaderTime = time();

//Hash them to get the Authorization token
$hash = sha1($apiKey.$apiSecret.$apiHeaderTime);

//Set the required headers
$headers = [
    "User-Agent: SuperPodcastPlayer/1.3",
    "X-Auth-Key: $apiKey",
    "X-Auth-Date: $apiHeaderTime",
    "Authorization: $hash"
];

//Make the request to an API endpoint
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,"https://api.podcastindex.org/api/1.0/search/byterm?q=bastiat");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

//Collect and show the results
$response = curl_exec ($ch);
curl_close ($ch);
echo print_r(json_decode($response), TRUE);

C#

//Required values
string apiKey = "UXKCGDSYGUUEVQJSYDZH";
string apiSecret = "yzJe2eE7XV-3eY576dyRZ6wXyAbndh6LUrCZ8KN|";
TimeSpan t = DateTime.UtcNow - new DateTime(1970, 1, 1);
int apiHeaderTime = (int)t.TotalSeconds;

//Hash them to get the Authorization token
string hash = "";
using (SHA1Managed sha1 = new SHA1Managed())
{
    var hashed = sha1.ComputeHash(Encoding.UTF8.GetBytes(apiKey + apiSecret + apiHeaderTime));
    var sb = new StringBuilder(hashed.Length * 2);

    foreach (byte b in hashed)
    {
        // can be "x2" if you want lowercase
        sb.Append(b.ToString("x2"));
    }

    hash = sb.ToString();
}

//Create the web request and add the required headers
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://api.podcastindex.org/api/1.0/search/byterm?q=bastiat");
request.Headers.Add("User-Agent", "SuperPodcastPlayer/1.3");
request.Headers.Add("X-Auth-Date", apiHeaderTime.ToString());
request.Headers.Add("X-Auth-Key", apiKey);
request.Headers.Add("Authorization", hash);

//Send the request and collect/show the results
try
{
    WebResponse webResponse2 = request.GetResponse();
    Stream stream2 = webResponse2.GetResponseStream();
    StreamReader reader2 = new StreamReader(stream2);

    Console.WriteLine(reader2.ReadToEnd());

    webResponse2.Close();
}
catch (Exception e)
{
    Console.WriteLine("Error.");
}

Swift

import Foundation
import CommonCrypto

extension String {
    func sha1() -> String {
        let data = Data(self.utf8)
        var digest = [UInt8](repeating: 0, count:Int(CC_SHA1_DIGEST_LENGTH))
        data.withUnsafeBytes {
            _ = CC_SHA1($0.baseAddress, CC_LONG(data.count), &digest)
        }
        let hexBytes = digest.map { String(format: "%02hhx", $0) }
        return hexBytes.joined()
    }
}

let apiKey = "UXKCGDSYGUUEVQJSYDZH"
let apiSecret = "yzJe2eE7XV-3eY576dyRZ6wXyAbndh6LUrCZ8KN|"
let apiHeaderTime = String(Int(Date().timeIntervalSince1970))
let hash = (apiKey + apiSecret + apiHeaderTime).sha1()

var semaphore = DispatchSemaphore (value: 0)
var request = URLRequest(url: URL(string: "https://api.podcastindex.org/api/1.0/search/byterm?q=bastiat")!,timeoutInterval: Double.infinity)
request.addValue("SuperPodcastPlayer/1.3", forHTTPHeaderField: "User-Agent")
request.addValue(apiKey, forHTTPHeaderField: "X-Auth-Key")
request.addValue(apiHeaderTime, forHTTPHeaderField: "X-Auth-Date")
request.addValue(hash, forHTTPHeaderField: "Authorization")

request.httpMethod = "GET"

let task = URLSession.shared.dataTask(with: request) { data, response, error in
    guard let data = data else {
        print(String(describing: error))
        return
    }
    print(String(data: data, encoding: .utf8)!)
    semaphore.signal()
}

task.resume()
semaphore.wait()

Postman


1) Download the contents of the Postman Docs folder. 2) Import the PodcastIndex.postman_collection.json collection to Postman 3) Import the PodcastIndexOrgEnvironment.postman_environment.json to Postman 4) Set the AuthKey environment variable 5) Set the SecretKey environment variable 6) Hit the Send button (⌘ + return)



Libraries

Javascript (Node.js)