The Podcast API PHP library provides convenient access to the Listen Notes Podcast API from applications written in the PHP language.
Simple and no-nonsense podcast search & directory API. Search the meta data of all podcasts and episodes by people, places, or topics. It's the same API that powers the best podcast search engine Listen Notes.
If you have any questions, please contact hello@listennotes.com
search—GET /searchtypeahead—GET /typeaheadsearchEpisodeTitles—GET /search_episode_titlesspellcheck—GET /spellcheckfetchRelatedSearches—GET /related_searchesfetchTrendingSearches—GET /trending_searchesfetchBestPodcasts—GET /best_podcastsfetchPodcastById—GET /podcasts/{id}deletePodcast—DELETE /podcasts/{id}fetchEpisodeById—GET /episodes/{id}batchFetchEpisodes—POST /episodesbatchFetchPodcasts—POST /podcastsfetchCuratedPodcastsListById—GET /curated_podcasts/{id}fetchPodcastGenres—GET /genresfetchPodcastRegions—GET /regionsfetchPodcastLanguages—GET /languagesjustListen—GET /just_listenfetchCuratedPodcastsLists—GET /curated_podcastsfetchRecommendationsForPodcast—GET /podcasts/{id}/recommendationsfetchRecommendationsForEpisode—GET /episodes/{id}/recommendationssubmitPodcast—POST /podcasts/submitfetchPlaylistById—GET /playlists/{id}fetchMyPlaylists—GET /playlistsfetchAudienceForPodcast—GET /podcasts/{id}/audiencefetchPodcastsByDomain—GET /podcasts/domains/{domain_name}createPlaylist—POST /playlistsupdatePlaylist—PUT /playlists/{id}deletePlaylist—DELETE /playlists/{id}addPlaylistItem—POST /playlists/{id}/itemsdeletePlaylistItem—DELETE /playlists/{id}/items/{item_id}updatePlaylistItemNotes—PUT /playlists/{id}/items/{item_id}
Install the official Composer package of the Listen Notes Podcast API:
composer require listennotes/podcast-apiTo use the bindings, use Composer's autoload:
require_once('vendor/autoload.php');- PHP 8.4+ with the cURL and JSON extensions
The library needs to be configured with your account's API key which is
available in your Listen API Dashboard. Set API_KEY to its
value:
<?php
require_once dirname( __FILE__ ) . '/vendor/autoload.php';
// Boilerplate to make an api call
try {
define( 'API_KEY', ( getenv( 'API_KEY' ) ? getenv( 'API_KEY' ) : null ) );
$objClient = new ListenNotes\PodcastApi\Client( API_KEY );
$strResponse = $objClient->typeahead( [ 'q' => 'startup', 'show_podcasts' => '1' ] );
$arrHeaders = $objClient->getHeaders();
print("\n=== Some account info ===\n");
printf( "Free Quota this month: %s requests\n" , $arrHeaders['x-listenapi-freequota'] );
printf( "Usage this month: %s requests\n" , $arrHeaders["x-listenapi-usage"] );
printf( "Next billing date: %s\n" , $arrHeaders["x-listenapi-nextbillingdate"] );
print("\n=== Response data ===\n");
print_r( json_decode( $strResponse ) );
} catch ( ListenNotes\PodcastApi\Exception\APIConnectionException $objException ) {
print("Failed to connect to Listen API servers");
} catch ( ListenNotes\PodcastApi\Exception\AuthenticationException $objException ) {
print("Wrong api key, or your account has been suspended!");
} catch ( ListenNotes\PodcastApi\Exception\InvalidRequestException $objException ) {
print("Wrong parameters!");
} catch ( ListenNotes\PodcastApi\Exception\NotFoundException $objException ) {
print("Endpoint not exist or the podcast / episode not exist!");
} catch ( ListenNotes\PodcastApi\Exception\RateLimitException $objException ) {
print("You have reached your quota limit or rate limit!");
} catch ( ListenNotes\PodcastApi\Exception\ListenApiException $objException ) {
print("Something wrong on Listen Notes servers");
} catch ( Exception $e ) {
print("Other errors that may not be related to Listen API");
}If API_KEY is null, then we'll connect to a mock server that returns fake data for testing purposes.
Unsuccessful requests raise exceptions. The class of the exception will reflect the sort of error that occurred.
| Exception Class | Description |
|---|---|
| AuthenticationException | wrong api key or your account is suspended |
| APIConnectionException | fail to connect to API servers |
| InvalidRequestException | something wrong on your end (client side errors), e.g., missing required parameters |
| RateLimitException | for FREE plan, exceeding the quota limit; or for all plans, sending too many requests too fast and exceeding the rate limit |
| NotFoundException | endpoint not exist, or podcast / episode not exist |
| ListenApiException | something wrong on our end (unexpected server errors) |
All exception classes can be found in this folder.
And you can see some sample code here.
Existing methods retain their array arguments and response-body strings.
Use getStatusCode() and getHeaders() to inspect the latest response. Version
3.0.0 added five playlist write methods; 3.1.0 adds deletePlaylist. PHP 8.4
remains the minimum supported version.
The default User-Agent is podcast-api-php 3.1.0. Requests have a 30-second total
timeout and a connection timeout of at most 10 seconds. Pass a positive timeout
in seconds as the second constructor argument to change the total timeout.
Redirects and automatic request retries are disabled. HTTP 201 and other 2xx
responses succeed; HTTP 403 raises PermissionDeniedException.
API exceptions include server error details in getMessage() and expose
getStatus(), getResponseBody(), and getResponseHeaders(). Response metadata
is reset before each request, including connection failures. Explicit empty
strings clear notes/descriptions; null fields are omitted.
Each method accepts an array and returns the response body as a string. Set LISTEN_API_KEY for real API requests; without it, these examples use the stateless mock server.
Full-text search
GET /search
Full-text search on episodes, podcasts, or curated lists of podcasts.
Use the offset parameter to paginate through search results.
The FREE plan allows to see up to 30 search results (or offset < 30) per query.
The PRO plan allows to see up to 300 search results (or offset < 300) per query.
The ENTERPRISE plan allows to see up to 10,000 search results (or offset < 10000) per query.
<?php
require 'vendor/autoload.php';
$client = new ListenNotes\PodcastApi\Client(getenv('LISTEN_API_KEY') ?: null);
$response = $client->search([
'q' => 'star wars',
'sort_by_date' => 0,
'type' => 'episode',
'offset' => 0,
'len_min' => 10,
'len_max' => 30,
'genre_ids' => '68,82',
'published_before' => 1580172454000,
'published_after' => 0,
'only_in' => 'title,description',
'language' => 'English',
'region' => '',
'safe_mode' => 0,
'unique_podcasts' => 0,
'interviews_only' => 0,
'sponsored_only' => 0,
'page_size' => 10
]);
print_r(json_decode($response, true, 512, JSON_THROW_ON_ERROR));Typeahead search
GET /typeahead
Suggest search terms, podcast genres, and podcasts.
<?php
require 'vendor/autoload.php';
$client = new ListenNotes\PodcastApi\Client(getenv('LISTEN_API_KEY') ?: null);
$response = $client->typeahead([
'q' => 'star wars',
'show_podcasts' => 1,
'show_genres' => 1,
'safe_mode' => 0
]);
print_r(json_decode($response, true, 512, JSON_THROW_ON_ERROR));Find individual episodes by searching for their titles
GET /search_episode_titles
Conduct targeted searches for individual episodes by title and refine results using the podcast id such as Listen Notes Podcast ID, Apple Podcasts ID, Spotify ID, or RSS feed URL. This endpoint is specially designed to streamline the import of specific episodes from platforms like Apple Podcasts and Spotify into your application. Compared to the GET /search endpoint, which performs full-text searches across multiple fields, this endpoint focuses solely on episode titles for enhanced accuracy and performance.
<?php
require 'vendor/autoload.php';
$client = new ListenNotes\PodcastApi\Client(getenv('LISTEN_API_KEY') ?: null);
$response = $client->searchEpisodeTitles([
'q' => 'Jerusalem Demsas on The Dispossessed'
]);
print_r(json_decode($response, true, 512, JSON_THROW_ON_ERROR));Spell check on a search term
GET /spellcheck
Suggest a list of words that correct the spelling errors of a search term. This endpoint is available only in the PRO/ENTERPRISE plan.
<?php
require 'vendor/autoload.php';
$client = new ListenNotes\PodcastApi\Client(getenv('LISTEN_API_KEY') ?: null);
$response = $client->spellcheck([
'q' => 'microsft stock'
]);
print_r(json_decode($response, true, 512, JSON_THROW_ON_ERROR));Fetch related search terms
GET /related_searches
Suggest related search terms. The results are more comprehensive than from GET /typeahead. This endpoint is available only in the PRO/ENTERPRISE plan.
<?php
require 'vendor/autoload.php';
$client = new ListenNotes\PodcastApi\Client(getenv('LISTEN_API_KEY') ?: null);
$response = $client->fetchRelatedSearches([
'q' => 'evergrande'
]);
print_r(json_decode($response, true, 512, JSON_THROW_ON_ERROR));Fetch trending search terms
GET /trending_searches
Fetch up to 10 most recent trending search terms on the Listen Notes platform.
<?php
require 'vendor/autoload.php';
$client = new ListenNotes\PodcastApi\Client(getenv('LISTEN_API_KEY') ?: null);
$response = $client->fetchTrendingSearches();
print_r(json_decode($response, true, 512, JSON_THROW_ON_ERROR));Fetch a list of best podcasts by genre
GET /best_podcasts
Get a list of curated best podcasts by genre,
which are curated by Listen Notes staffs based on various signals from the Internet, e.g.,
top charts on other podcast platforms, recommendations from mainstream media,
user activities on listennotes.com...
You can get the genre ids from GET /genres endpoint.
This endpoint returns same data as https://www.listennotes.com/best-podcasts/
<?php
require 'vendor/autoload.php';
$client = new ListenNotes\PodcastApi\Client(getenv('LISTEN_API_KEY') ?: null);
$response = $client->fetchBestPodcasts([
'genre_id' => 93,
'page' => 2,
'region' => 'us',
'sort' => 'listen_score',
'safe_mode' => 0
]);
print_r(json_decode($response, true, 512, JSON_THROW_ON_ERROR));Fetch detailed meta data and episodes for a podcast by id
GET /podcasts/{id}
Fetch detailed meta data and episodes for a specific podcast (up to 10 episodes each time). You can use the next_episode_pub_date parameter to do pagination and fetch more episodes. During pagination with next_episode_pub_date, an empty episodes array in the response signals that no more episodes are available.
<?php
require 'vendor/autoload.php';
$client = new ListenNotes\PodcastApi\Client(getenv('LISTEN_API_KEY') ?: null);
$response = $client->fetchPodcastById([
'id' => '4d3fe717742d4963a85562e9f84d8c79',
'next_episode_pub_date' => 1479154463000,
'sort' => 'recent_first'
]);
print_r(json_decode($response, true, 512, JSON_THROW_ON_ERROR));Request to delete a podcast
DELETE /podcasts/{id}
Podcast hosting services can use this endpoint to streamline the process of podcast deletion on behave of their users (podcasters). We will review the deletion request within 12 hours. If the podcast is already deleted, the "status" field in the response will be "deleted". Otherwise, the status field will be "in review". If you want to get a notification once the podcast is deleted, you can configure a webhook url in the dashboard: listennotes.com/api/dashboard/#webhooks
<?php
require 'vendor/autoload.php';
$client = new ListenNotes\PodcastApi\Client(getenv('LISTEN_API_KEY') ?: null);
$response = $client->deletePodcast([
'id' => '4d3fe717742d4963a85562e9f84d8c79',
'reason' => 'the podcaster wants to delete it'
]);
print_r(json_decode($response, true, 512, JSON_THROW_ON_ERROR));Fetch detailed meta data for an episode by id
GET /episodes/{id}
Fetch detailed meta data for a specific episode.
<?php
require 'vendor/autoload.php';
$client = new ListenNotes\PodcastApi\Client(getenv('LISTEN_API_KEY') ?: null);
$response = $client->fetchEpisodeById([
'id' => '6b6d65930c5a4f71b254465871fed370',
'show_transcript' => 1
]);
print_r(json_decode($response, true, 512, JSON_THROW_ON_ERROR));Batch fetch basic meta data for episodes
POST /episodes
Batch fetch basic meta data for up to 10 episodes. This endpoint could be used to implement custom playlists for individual episodes. For detailed meta data of an individual episode, you need to use GET /episodes/{id}. This endpoint is available only in the PRO/ENTERPRISE plan.
<?php
require 'vendor/autoload.php';
$client = new ListenNotes\PodcastApi\Client(getenv('LISTEN_API_KEY') ?: null);
$response = $client->batchFetchEpisodes([
'ids' => 'c577d55b2b2b483c969fae3ceb58e362,0f34a9099579490993eec9e8c8cebb82'
]);
print_r(json_decode($response, true, 512, JSON_THROW_ON_ERROR));Batch fetch basic meta data for podcasts
POST /podcasts
Batch fetch basic meta data for up to 10 podcasts.
This endpoint could be used to build something like OPML import,
allowing users to import a bunch of podcasts via rss urls.
For detailed meta data (including episodes) of an individual podcast, you need to use GET /podcasts/{id}. This endpoint is available only in the PRO/ENTERPRISE plan.
<?php
require 'vendor/autoload.php';
$client = new ListenNotes\PodcastApi\Client(getenv('LISTEN_API_KEY') ?: null);
$response = $client->batchFetchPodcasts([
'ids' => '3302bc71139541baa46ecb27dbf6071a,68faf62be97149c280ebcc25178aa731,37589a3e121e40debe4cef3d9638932a,9cf19c590ff0484d97b18b329fed0c6a',
'rsses' => 'https://rss.art19.com/recode-decode,https://rss.art19.com/the-daily,https://www.npr.org/rss/podcast.php?id=510331,https://www.npr.org/rss/podcast.php?id=510331',
'itunes_ids' => '1457514703,1386234384,659155419',
'spotify_ids' => '3DDfEsKDIDrTlnPOiG4ZF4,4qDNe5Gvl1XxdLinUGEXrC,23NZCM4ik6o3UYkM473Itz',
'show_latest_episodes' => 1,
'next_episode_pub_date' => 1557394247000
]);
print_r(json_decode($response, true, 512, JSON_THROW_ON_ERROR));Fetch a curated list of podcasts by id
GET /curated_podcasts/{id}
Get detailed meta data of all podcasts in a specific curated list. This endpoint returns same data as https://www.listennotes.com/curated-podcasts/
<?php
require 'vendor/autoload.php';
$client = new ListenNotes\PodcastApi\Client(getenv('LISTEN_API_KEY') ?: null);
$response = $client->fetchCuratedPodcastsListById([
'id' => 'SDFKduyJ47r'
]);
print_r(json_decode($response, true, 512, JSON_THROW_ON_ERROR));Fetch a list of podcast genres
GET /genres
Get a list of podcast genres that are supported in Listen Notes.
The genre id can be passed to other endpoints as a parameter to get podcasts in a specific genre,
e.g., GET /best_podcasts, GET /search...
You may want to cache the list of genres on the client side.
<?php
require 'vendor/autoload.php';
$client = new ListenNotes\PodcastApi\Client(getenv('LISTEN_API_KEY') ?: null);
$response = $client->fetchPodcastGenres([
'top_level_only' => 1
]);
print_r(json_decode($response, true, 512, JSON_THROW_ON_ERROR));Fetch a list of supported countries/regions for best podcasts
GET /regions
It returns a dictionary of country codes (e.g., us, gb...) & country names (United States, United Kingdom...). The country code is used in the query parameter region of GET /best_podcasts.
<?php
require 'vendor/autoload.php';
$client = new ListenNotes\PodcastApi\Client(getenv('LISTEN_API_KEY') ?: null);
$response = $client->fetchPodcastRegions();
print_r(json_decode($response, true, 512, JSON_THROW_ON_ERROR));Fetch a list of supported languages for podcasts
GET /languages
Get a list of languages that are supported in Listen Notes database. You can use the language string as query parameter in GET /search.
<?php
require 'vendor/autoload.php';
$client = new ListenNotes\PodcastApi\Client(getenv('LISTEN_API_KEY') ?: null);
$response = $client->fetchPodcastLanguages();
print_r(json_decode($response, true, 512, JSON_THROW_ON_ERROR));Fetch a random podcast episode
GET /just_listen
Recently published episodes are more likely to be fetched. Good luck!
<?php
require 'vendor/autoload.php';
$client = new ListenNotes\PodcastApi\Client(getenv('LISTEN_API_KEY') ?: null);
$response = $client->justListen();
print_r(json_decode($response, true, 512, JSON_THROW_ON_ERROR));Fetch curated lists of podcasts
GET /curated_podcasts
A bunch of curated lists from online media. For each list, you'll get basic info of up to 5 podcasts. To get detailed meta data of all podcasts in a specific list, you need to use GET /curated_podcasts/{id}. We add new curated lists to the database on a daily basis.
<?php
require 'vendor/autoload.php';
$client = new ListenNotes\PodcastApi\Client(getenv('LISTEN_API_KEY') ?: null);
$response = $client->fetchCuratedPodcastsLists([
'page' => 2
]);
print_r(json_decode($response, true, 512, JSON_THROW_ON_ERROR));Fetch recommendations for a podcast
GET /podcasts/{id}/recommendations
Fetch up to 8 podcast recommendations based on the given podcast id.
<?php
require 'vendor/autoload.php';
$client = new ListenNotes\PodcastApi\Client(getenv('LISTEN_API_KEY') ?: null);
$response = $client->fetchRecommendationsForPodcast([
'id' => '25212ac3c53240a880dd5032e547047b',
'safe_mode' => 0
]);
print_r(json_decode($response, true, 512, JSON_THROW_ON_ERROR));Fetch recommendations for an episode
GET /episodes/{id}/recommendations
Fetch up to 8 episode recommendations based on the given episode id.
<?php
require 'vendor/autoload.php';
$client = new ListenNotes\PodcastApi\Client(getenv('LISTEN_API_KEY') ?: null);
$response = $client->fetchRecommendationsForEpisode([
'id' => '254444fa6cf64a43a95292a70eb6869b',
'safe_mode' => 0
]);
print_r(json_decode($response, true, 512, JSON_THROW_ON_ERROR));Submit a podcast to Listen Notes database
POST /podcasts/submit
Podcast hosting services can use this endpoint to help your users directly submit a new podcast to Listen Notes database. If the podcast doesn't exist in the database, "status" in the response will be "in review", and we'll review it within 12 hours. If the podcast exists, "status" in the response will be "found". If this submission is rejected, "status" in the response will be "rejected". You can use POST /podcasts to check if multiple podcasts exist in the database. If you want to get a notification once the podcast is accepted, you can either specify the "email" parameter or configure a webhook url in the dashboard: listennotes.com/api/dashboard/#webhooks
<?php
require 'vendor/autoload.php';
$client = new ListenNotes\PodcastApi\Client(getenv('LISTEN_API_KEY') ?: null);
$response = $client->submitPodcast([
'rss' => 'https://feeds.megaphone.fm/committed',
'email' => 'hello@example.com'
]);
print_r(json_decode($response, true, 512, JSON_THROW_ON_ERROR));Fetch a playlist's info and items (i.e., episodes or podcasts).
GET /playlists/{id}
A playlist can contain both episodes and podcasts, shown in separate views, just like playlists created via listennotes.com/listen/. This endpoint fetches items from the saved default view unless type is specified. The response type and listennotes_url describe the selected view. You can use the last_pub_date_ms parameter to do pagination and fetch more items. A playlist can be public (discoverable on ListenNotes.com), unlisted (accessible to anyone who knows the playlist id), or private (accessible when the API admin has active playlist membership). Public and unlisted playlists can also be fetched by ID regardless of their owner.
<?php
require 'vendor/autoload.php';
$client = new ListenNotes\PodcastApi\Client(getenv('LISTEN_API_KEY') ?: null);
$response = $client->fetchPlaylistById([
'id' => 'm1pe7z60bsw',
'type' => 'episode_list',
'last_timestamp_ms' => 0,
'sort' => 'recent_added_first'
]);
print_r(json_decode($response, true, 512, JSON_THROW_ON_ERROR));Fetch a list of your playlists.
GET /playlists
This endpoint lists playlists with an active membership for the API admin, including playlists they created or joined. Each playlist includes its saved default type and a listennotes_url for that view. You can use the page parameter to do pagination and fetch more playlists.
<?php
require 'vendor/autoload.php';
$client = new ListenNotes\PodcastApi\Client(getenv('LISTEN_API_KEY') ?: null);
$response = $client->fetchMyPlaylists([
'sort' => 'recent_added_first',
'page' => 1
]);
print_r(json_decode($response, true, 512, JSON_THROW_ON_ERROR));Fetch audience demographics for a podcast
GET /podcasts/{id}/audience
Fetch audience demographics for a podcast - 1) directly measured on the Listen Notes platform; 2) only supports audience breakdown by regions for now; 3) not every podcast has data.
<?php
require 'vendor/autoload.php';
$client = new ListenNotes\PodcastApi\Client(getenv('LISTEN_API_KEY') ?: null);
$response = $client->fetchAudienceForPodcast([
'id' => '25212ac3c53240a880dd5032e547047b'
]);
print_r(json_decode($response, true, 512, JSON_THROW_ON_ERROR));Fetch podcasts by a publisher's domain name
GET /podcasts/domains/{domain_name}
Fetch podcasts by a publisher's domain name, e.g., nytimes.com, wondery.com, npr.org...
Each request will return up to 10 podcasts. You can use the page parameter to paginate.
<?php
require 'vendor/autoload.php';
$client = new ListenNotes\PodcastApi\Client(getenv('LISTEN_API_KEY') ?: null);
$response = $client->fetchPodcastsByDomain([
'domain_name' => 'nytimes.com',
'page' => 1
]);
print_r(json_decode($response, true, 512, JSON_THROW_ON_ERROR));Create a playlist.
POST /playlists
Create an empty playlist owned by the API admin. Name is required; description defaults to an empty string, visibility defaults to public, and type defaults to episode_list. Set type to podcast_list to make podcasts the default view. The response includes the saved type and its listennotes_url.
Only playlists owned by your admin API account can be modified; contributor membership does not grant write access.
<?php
require 'vendor/autoload.php';
$client = new ListenNotes\PodcastApi\Client(getenv('LISTEN_API_KEY') ?: null);
$response = $client->createPlaylist([
'name' => 'My favorite podcasts',
'description' => 'Podcasts and episodes to revisit.',
'visibility' => 'public',
'type' => 'episode_list'
]);
print_r(json_decode($response, true, 512, JSON_THROW_ON_ERROR));Update playlist metadata.
PUT /playlists/{id}
Update any subset of name, description, visibility, and type. Omitted fields remain unchanged; at least one field is required. Switching to private rotates the playlist RSS secret. Type selects the saved default view (episode_list or podcast_list) and the returned listennotes_url; changing it preserves all existing episodes and podcasts.
Only playlists owned by your admin API account can be modified; contributor membership does not grant write access.
<?php
require 'vendor/autoload.php';
$client = new ListenNotes\PodcastApi\Client(getenv('LISTEN_API_KEY') ?: null);
$response = $client->updatePlaylist([
'id' => 'm1pe7z60bsw',
'name' => 'My favorite podcasts',
'description' => 'Podcasts and episodes to revisit.',
'visibility' => 'public',
'type' => 'podcast_list'
]);
print_r(json_decode($response, true, 512, JSON_THROW_ON_ERROR));Delete a playlist.
DELETE /playlists/{id}
Permanently delete a playlist, including all episode and podcast references saved in this specific playlist and their notes. The actual episodes and podcasts remain in the Listen Notes podcast database.
Warning: Deletion cannot be undone. Once deleted, the playlist is gone, regardless of how many episodes or podcasts it contains. You, the developer, are responsible for adding a confirmation step in your app's UI before calling this endpoint to prevent accidental deletion.
Only playlists owned by your admin API account can be modified; contributor membership does not grant write access.
<?php
require 'vendor/autoload.php';
$client = new ListenNotes\PodcastApi\Client(getenv('LISTEN_API_KEY') ?: null);
$response = $client->deletePlaylist([
'id' => 'm1pe7z60bsw'
]);
print_r(json_decode($response, true, 512, JSON_THROW_ON_ERROR));Add an episode or podcast to a playlist.
POST /playlists/{id}/items
Provide exactly one non-empty episode_id or podcast_id; an empty unused ID field is ignored. Invalid ID formats return 400 and identify the field. A missing episode or podcast returns 404 with an error such as "Episode not found: {episode_id}." or "Podcast not found: {podcast_id}.". Existing active items are reused (200); new or restored items return 201. Omitted notes preserve existing notes, including when restoring a deleted item; supplied notes replace them.
<?php
require 'vendor/autoload.php';
$client = new ListenNotes\PodcastApi\Client(getenv('LISTEN_API_KEY') ?: null);
$response = $client->addPlaylistItem([
'id' => 'm1pe7z60bsw',
'episode_id' => 'e53e6992a5b7492f9ea6fcd85d9ad95f',
'notes' => 'Worth a listen.'
]);
print_r(json_decode($response, true, 512, JSON_THROW_ON_ERROR));Remove an item from a playlist.
DELETE /playlists/{id}/items/{item_id}
Delete a playlist item. Repeating deletion of the same item succeeds. This does not delete the episode or podcast from the podcast database.
Only playlists owned by your admin API account can be modified; contributor membership does not grant write access.
<?php
require 'vendor/autoload.php';
$client = new ListenNotes\PodcastApi\Client(getenv('LISTEN_API_KEY') ?: null);
$response = $client->deletePlaylistItem([
'id' => 'm1pe7z60bsw',
'item_id' => 23
]);
print_r(json_decode($response, true, 512, JSON_THROW_ON_ERROR));Update notes for a playlist item.
PUT /playlists/{id}/items/{item_id}
Replace item notes, or send an empty string to clear them. The item ID and added_at_ms remain unchanged.
Only playlists owned by your admin API account can be modified; contributor membership does not grant write access.
<?php
require 'vendor/autoload.php';
$client = new ListenNotes\PodcastApi\Client(getenv('LISTEN_API_KEY') ?: null);
$response = $client->updatePlaylistItemNotes([
'id' => 'm1pe7z60bsw',
'item_id' => 23,
'notes' => ''
]);
print_r(json_decode($response, true, 512, JSON_THROW_ON_ERROR));Use Composer 2 with PHP 8.4 or 8.5:
composer install
composer validate --strict
composer lint
composer test
composer test-integration
composer archive --format=tar --dir=/tmpThe default suite uses a local HTTP fixture bound to loopback; it never calls production or the public mock API. The separate integration suite calls only https://listen-api-test.listennotes.com without credentials. The mock is stateless.
PHPUnit is pinned to 13.3.3, the second-latest stable release at this upgrade. The SDK has no third-party runtime dependencies. The lockfile pins development dependencies. CI tests PHP 8.4 and 8.5, with public-mock integration in a separate job.
listennotes/ApiMethods.php, listennotes/api-contract.json, and the two marked
README sections are generated by the Listen Notes monorepo's
devtools/api-sdks/sync.py php. Edit the canonical spec/registry there, not these
outputs. The SDK, tests, and packaged distribution work independently.
Packagist derives package versions from Git tags. Client::VERSION is 3.1.0;
publication/tagging is a separate release step after review and CI.
