Spotify Podcast Search API. Podcasts matching your search.
Podcasts by keyword, publisher or topic. We handle the proxies, blocks and platform changes.
Spotify Podcast Search API at a glance
Searches Spotify podcasts by keyword in any language and returns them a page at a time, in Spotify's order. Each has its ID, link, name, publisher, largest cover, whether its episodes are audio or video, and its categories. The Spotify Podcast API adds the description, rating, episode count and latest episode's date.
GET /v1/spotify/search_podcasts
- 1 credit per page, $0.75–$1.97 per 1,000 pages
- 17 typed fields null when unknown
- 100 podcasts per page, Spotify's own ranking for the query
queryis all it needs, e.g.true crime
Send one request. Get up to 100 podcasts back.
Copy the request in your language, or hand it to your agent. Sign up for an API key and your first 100 credits are free.
$ npm install socialtapquery = true crimeconst params = new URLSearchParams({
query: "true crime",
});
const res = await fetch(`https://socialtap.dev/v1/spotify/search_podcasts?${params}`, {
headers: { "x-api-key": process.env.SOCIALTAP_API_KEY ?? "" },
});
const body = await res.json();
if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
const { data, page, meta } = body;
console.log(data, meta.credits_charged);import os
import requests
res = requests.get(
"https://socialtap.dev/v1/spotify/search_podcasts",
params={"query": "true crime"},
headers={"x-api-key": os.environ["SOCIALTAP_API_KEY"]},
)
body = res.json()
if not res.ok:
raise RuntimeError(f"{body['error']['code']}: {body['error']['message']}")
data, page, meta = body["data"], body["page"], body["meta"]
print(data, meta["credits_charged"])require "json"
require "net/http"
uri = URI("https://socialtap.dev/v1/spotify/search_podcasts")
uri.query = URI.encode_www_form('query' => 'true crime')
req = Net::HTTP::Get.new(uri)
req["x-api-key"] = ENV.fetch("SOCIALTAP_API_KEY")
res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == "https") { |http| http.request(req) }
body = JSON.parse(res.body)
raise "#{body["error"]["code"]}: #{body["error"]["message"]}" unless res.is_a?(Net::HTTPSuccess)
pp body["data"]
puts body["meta"]["credits_charged"]<?php
$query = http_build_query([
'query' => 'true crime',
]);
$ch = curl_init('https://socialtap.dev/v1/spotify/search_podcasts?' . $query);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['x-api-key: ' . getenv('SOCIALTAP_API_KEY')],
]);
$body = json_decode(curl_exec($ch), true);
if (curl_getinfo($ch, CURLINFO_RESPONSE_CODE) >= 400) {
throw new RuntimeException($body['error']['code'] . ': ' . $body['error']['message']);
}
print_r($body['data']);
echo $body['meta']['credits_charged'], PHP_EOL;package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"net/url"
"os"
)
func main() {
q := url.Values{}
q.Set("query", "true crime")
req, err := http.NewRequest("GET", "https://socialtap.dev/v1/spotify/search_podcasts?"+q.Encode(), nil)
if err != nil {
log.Fatal(err)
}
req.Header.Set("x-api-key", os.Getenv("SOCIALTAP_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer res.Body.Close()
var body struct {
Data json.RawMessage `json:"data"`
Page json.RawMessage `json:"page"`
Meta map[string]any `json:"meta"`
Error *struct {
Code string `json:"code"`
Message string `json:"message"`
} `json:"error"`
}
if err := json.NewDecoder(res.Body).Decode(&body); err != nil {
log.Fatal(err)
}
if body.Error != nil {
log.Fatalf("%s: %s", body.Error.Code, body.Error.Message)
}
fmt.Println(string(body.Data), body.Meta["credits_charged"])
}curl -G 'https://socialtap.dev/v1/spotify/search_podcasts' \
--data-urlencode 'query=true crime' \
-H "x-api-key: $SOCIALTAP_API_KEY"{
"data": [
{
"approximate_fields": [],
"categories": [
"True crime"
],
"cover_url": "https://i.scdn.co/image/ab6765630000ba8abe2cc3efd92b817b54d9bcb2",
"description": null,
"id": "3DgfoleqaW61T2amZQKINx",
"is_explicit": null,
"latest_episode_at": null,
"media_type": "audio",
"metrics": {
"episode_count": null,
"rating_count": null
},
"platform": "spotify",
"platform_specific": {},
"publisher": null,
"publisher_name": "Audiochuck",
"rating": null,
"show_type": null,
"title": "Crime Junkie",
"unknown_fields": [],
"url": "https://open.spotify.com/show/3DgfoleqaW61T2amZQKINx"
},
{
"approximate_fields": [],
"categories": [
"True crime"
],
"cover_url": "https://i.scdn.co/image/ab6765630000ba8a6f26a1be3d27a21d83e7cd2f",
"description": null,
"id": "48GaWhr2cdtOGjF3dF9rLy",
"is_explicit": null,
"latest_episode_at": null,
"media_type": "mixed",
"metrics": {
"episode_count": null,
"rating_count": null
},
"platform": "spotify",
"platform_specific": {},
"publisher": null,
"publisher_name": "True Crime Stories",
"rating": null,
"show_type": null,
"title": "True Crime Stories",
"unknown_fields": [],
"url": "https://open.spotify.com/show/48GaWhr2cdtOGjF3dF9rLy"
},
{
"approximate_fields": [],
"categories": [
"True crime"
],
"cover_url": "https://i.scdn.co/image/ab6765630000ba8a92b95c1495e411e3fb99659b",
"description": null,
"id": "2gknS4WovSnrJupP8BVKNe",
"is_explicit": null,
"latest_episode_at": null,
"media_type": "audio",
"metrics": {
"episode_count": null,
"rating_count": null
},
"platform": "spotify",
"platform_specific": {},
"publisher": null,
"publisher_name": "Crime House",
"rating": null,
"show_type": null,
"title": "Serial Killers & Murderous Minds",
"unknown_fields": [],
"url": "https://open.spotify.com/show/2gknS4WovSnrJupP8BVKNe"
}
],
"page": {
"has_more": true,
"next_cursor": "c1.EXAMPLE_CURSOR",
"next_cursor_expires_at": "2026-10-26T12:00:00Z",
"end_reason": null
},
"meta": {
"request_id": "req_3f9c2a7d1e8b4c6a9f0e2d4b6a8c0e1f",
"platform": "spotify",
"source": "api",
"is_cached": false,
"credits_charged": 1,
"latency_ms": 627,
"fetched_at": "2026-10-25T12:00:00Z",
"input": null,
"credits_remaining": 9999,
"client_request_id": null,
"warnings": []
}
}import { SocialTap } from "socialtap";
const client = new SocialTap(); // apiKey defaults to process.env.SOCIALTAP_API_KEY
const res = await client.spotify.searchPodcasts.list({ query: "true crime" });
console.log(res.data);
console.log(res.credits.charged, res.meta.request_id);import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
public class Main {
public static void main(String[] args) throws Exception {
String query = "query=" + encode("true crime");
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://socialtap.dev/v1/spotify/search_podcasts?" + query))
.header("x-api-key", System.getenv("SOCIALTAP_API_KEY"))
.GET()
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
// An error is {"error": {"code", "message", ...}}; success is {data, meta}, meta.credits_charged its price.
if (response.statusCode() >= 400) throw new RuntimeException(response.body());
System.out.println(response.body());
}
static String encode(String value) {
return URLEncoder.encode(value, StandardCharsets.UTF_8);
}
}using System.Text.Json;
using var http = new HttpClient();
http.DefaultRequestHeaders.Add("x-api-key", Environment.GetEnvironmentVariable("SOCIALTAP_API_KEY"));
var query = string.Join("&",
"query=" + Uri.EscapeDataString("true crime"));
var res = await http.GetAsync("https://socialtap.dev/v1/spotify/search_podcasts?" + query);
using var body = JsonDocument.Parse(await res.Content.ReadAsStringAsync());
if (!res.IsSuccessStatusCode)
{
var error = body.RootElement.GetProperty("error");
throw new Exception($"{error.GetProperty("code")}: {error.GetProperty("message")}");
}
Console.WriteLine(body.RootElement.GetProperty("data"));
Console.WriteLine(body.RootElement.GetProperty("meta").GetProperty("credits_charged"));// Cargo.toml: reqwest = { version = "0.12", features = ["blocking", "json"] }, serde_json = "1"
use std::env;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let res = reqwest::blocking::Client::new()
.get("https://socialtap.dev/v1/spotify/search_podcasts")
.query(&[("query", "true crime")])
.header("x-api-key", env::var("SOCIALTAP_API_KEY")?)
.send()?;
let ok = res.status().is_success();
let body: serde_json::Value = res.json()?;
if !ok {
return Err(format!("{}: {}", body["error"]["code"], body["error"]["message"]).into());
}
println!("{} {}", body["data"], body["meta"]["credits_charged"]);
Ok(())
}200 OK · GET https://socialtap.dev/v1/spotify/search_podcastsLong arrays and strings are shortened here. Real responses are complete.Docs What you send and what comes back.
The response reference lists every field, its type and when it is null. See the full schema.
Null means unknown
A field Spotify doesn't show is null, never zero or an empty string, so a real zero always means zero.
What it accepts
What to search for, as in Spotify's search box: a show's name, who publishes it or a topic, in any language.
What comes back
Podcasts with their publisher, description, cover, rating, categories, episode count and when the latest episode came out.
platformstring- Platform ID (spotify, youtube, …).
idstring- Platform-native show ID (string), the one in its page's URL.
urlstring- Canonical show page URL.
titlestring- The show's name as the platform lists it.
descriptionstring- About the show, as plain text; null when it has none or the platform shows none.
publisher_namestring- Who publishes the show, as the platform names them; null when it does not.
publisherobject- The platform account of the publisher; null when the platform names them without an account (always on Spotify).
cover_urlstring- Cover art URL at the largest size the platform serves; null when it has none. Platform CDN URLs can expire within hours.
Live data from 33 platforms.
What teams build with the Spotify Podcast Search API.
Turn a show's name into its Spotify ID
Find podcasts on a topic in any language
Find shows to pitch a guest to
Match a list of shows against Spotify
Good to know before you build.
- Results are podcasts only: the audiobooks, episodes, tracks and artists a query matches aren't in the list.
- Search lists no description, rating, episode count, latest episode date, order or explicit flag, so those are null: the Spotify Podcast API returns them.
- Spotify drops a show's categories from some answers to identical requests, so an empty categories listed in unknown_fields doesn't mean the show has none, and asking again can fill it.
- Results are in Spotify's order, which depends on the page size, so a smaller limit isn't always the top of a larger one. A walk ends with page.end_reason platform_limit where Spotify stops serving, however many shows it matched.
- Spotify can repeat a show on a later page. One from the page before is dropped, so a page can hold fewer shows than its limit while next_cursor goes on, and one from further back can appear twice in a walk.
- Spotify answers a weak query with its nearest guesses, so an empty page is rare and any result may be a loose match.
- When Spotify's search doesn't answer, the first pages come from a web search engine's index, each show read from Spotify, with a partial_data warning, Spotify's filters are read as plain words, and media_type and categories are unknown. That list holds only what the index has, often a small part of Spotify's, in the engine's order. A next_cursor stays on the list it came from: if Spotify's search stops answering mid-walk, the next page fails with a retryable error instead of switching lists.
- An empty query, a Spotify URI or a link to a Spotify page returns invalid_input, naming the endpoint that takes it where there is one. For a link to Spotify's search page, send its words instead.
1 credit per page. Failed requests are free.
Buy credits once and spend them on any endpoint, on any platform.
| Source | Price per successful page | Per 1,000 pages |
|---|---|---|
| Any source | 1 credit | $0.75–$1.97 |
- Cache hits are free.
- Credits from packs and top-ups never expire.
- A monthly plan's credits are spent first, and what is left of them ends at each renewal.
- Prices exclude tax: sales tax is added at checkout where it applies.
- Outside the US, plans and packs are sold to businesses: checkout asks for your VAT, GST or other business tax ID.
Questions about the Spotify Podcast Search API.
More in the API reference.
How much does the Spotify Podcast Search API cost?
How do I get the next page?
Try it with your own search.
Type it in the playground, or copy the request into your code.
- No credit card
- Failed requests are free
- Works on all 218 endpoints