---
title: "Look up episodes by external identifier"
method: GET
path: "/v1/podcasts/episodes/lookup"
tags: ["Podcast Episodes", "tier:standard"]
---

# Look up episodes by external identifier

`GET /v1/podcasts/episodes/lookup`

## Request

- Base URL: `https://api.particle.pro`
- URL: `https://api.particle.pro/v1/podcasts/episodes/lookup`
- Auth: one of:
  - API key in header `X-API-Key`
  - HTTP bearer

Resolves one or more external episode identifiers or links to Particle episodes. Paste a Spotify, Apple Podcasts or YouTube episode link as it is and it is resolved by the platform it points to; links from different platforms may share a call, and `platform` is then optional. Bare identifiers need `platform`: Apple Podcasts episode IDs (the `?i=` value in an Apple Podcasts URL), Spotify episode IDs and YouTube video IDs; the episode's RSS `guid` — the identifier the publisher's own feed carries, and the one most podcast tooling keys on — and a `podcastindex` episode ID; and hosting-platform IDs read from the episode's audio URL: `megaphone`, `omny`, `acast` and `art19`. Pass a comma-separated list (up to 100 per call). Guids and hosting-platform IDs are matched exactly as supplied and never read as links, since a guid is whatever string the feed carries and is often itself a URL. Because identifiers are comma-separated, a guid that itself contains a comma cannot be expressed here — about 1.2% of episodes, almost all of them SoundCloud-hosted, whose guids take the form `tag:soundcloud,2010:tracks/123`; look those episodes up by another identifier. Each result echoes the input identifier alongside the matched episode and its podcast; unresolved identifiers omit the `episode` field entirely so bulk callers can correlate inputs and outputs by key presence without doing a separate join. This is the episode-level counterpart to GET /v1/podcasts/lookup. Coverage is partial and differs by identifier, so a miss is not an error: Apple exposes only the most recent episodes of each show, so older back-catalogue episodes may not resolve; the first lookup of a Spotify episode can take a few seconds, and a call resolves at most 10 Spotify episodes not looked up before — retry the rest; YouTube resolves any video already discovered for an episode; `guid` is the broadest at roughly 89% of episodes; and a hosting-platform ID resolves only for episodes served by that host.

## Query parameters

- `platform` string: What kind of identifier you are resolving. Optional when every identifier is a link: a Spotify, Apple Podcasts or YouTube episode URL, or a spotify:episode: URI, is always resolved by the platform it points to. Needed for bare identifiers: 'apple' (alias 'itunes') resolves Apple Podcasts episode IDs — the ?i= value in an Apple Podcasts URL. 'spotify' resolves Spotify episode IDs. 'youtube' resolves YouTube video IDs against the videos discovered for each episode. 'guid' resolves the episode's RSS guid, the identifier carried in the publisher's own feed and the one most podcast tooling keys on. 'podcastindex' resolves a PodcastIndex episode ID. 'megaphone', 'omny', 'acast' and 'art19' resolve a hosting platform's own episode ID, read from the episode's audio URL. Platform slugs must be ones reported on external-links responses; 'rss' is not accepted here because a feed URL identifies a show, not an episode.
- `identifier` string[], nullable, required: One or more episode identifiers or links to resolve. Pass a comma-separated list to look up many at once (max 100 per call); links from different platforms may be mixed. Spotify, Apple Podcasts and YouTube episode links are understood in their common forms (share links with a locale or ?si= token, embed URLs, youtu.be, /live/, /shorts/). guid, podcastindex and hosting-platform values are used exactly as given — a guid is whatever string the feed carries, which is often itself a URL, so it is never read as a link. The identifier is echoed back exactly as supplied, not normalized.

## Response `200`

OK

- EpisodeLookup
  - `results` EpisodeLookupResult[], nullable, required: One result per unique input identifier, in request order
    - `episode` LookedUpEpisode
      - `has_transcript` boolean, required: Whether a transcript is available
      - `id` string, required: Episode ID
      - `podcast` PodcastCompact
        - `best_rank` PodcastRankingHandle
          - `captured_at` string, date-time, required
          - `category_slug` string
          - `chart_type` 'top_podcasts', required
          - `country` string
          - `rank` integer, required
          - `source` 'apple' | 'spotify', required
        - `id` string, required: Podcast ID
        - `image_url` string: Cover image URL
        - `popularity` number, double: Global popularity percentile in (0,1], a cume_dist ranking over all currently-charting podcasts (Apple Podcasts charts). Higher is more popular. Omitted when the podcast is not currently charting, on endpoints that build this resource from a projection rather than the full podcast row, and in episode stream, feed and archive payloads, which are stored and replayed: read it live from the podcast endpoints.
        - `publisher` PodcastPublisherCompact
          - `id` string, required: Publisher ID
          - `name` string, required: Publisher name
          - `slug` string: Human-readable slug identifier (e.g., 'goalhanger', 'iheartpodcasts'). When present, accepted in place of the ID anywhere a publisher reference is taken in the API. Occasionally absent on publishers whose name doesn't slugify (e.g., scripts not representable in ASCII URL slugs).
        - `slug` string: Human-readable slug identifier
        - `title` string, required: Podcast title
      - `published_at` string, date-time: Publication date
      - `slug` string: Human-readable slug identifier
      - `title` string, required: Episode title
      - `transcript_status` 'transcribed' | 'processing' | 'queued' | 'requestable' | 'unavailable', required: Where the episode stands on the way to a transcript; see Episode.transcript_status.
      - `web_url` string: The episode's page on Radar, where it plays beside its transcript: https://radar.particle.pro/podcasts/{podcast}/episodes/{episode}, each segment the slug or, when there is none, the raw UUID. Append ?t={seconds} to start at a moment; the hit's own url field already does. Omitted for back-catalogue episodes we have not ingested, which have no page, and in episode stream, feed and archive payloads stored before this field shipped (they are replayed as stored): build it from the slugs, or fetch the episode.
    - `identifier` string, required: The platform-native identifier as supplied in the request

## Other responses

- `402`: Payment Required. Read error_code. payment_required is the x402 path: either a keyless request being challenged — pay $0.01 in USDC per request (requirements in the PAYMENT-REQUIRED header) or send a pp_ API key — or a supplied payment that failed settlement (details in the PAYMENT-RESPONSE header; retry the same signature before signing a new one). See https://docs.particle.pro/x402. Any other code means the credential was accepted but does not cover this request (a plan or session gate such as premium_required or paid_plan_confirmation_required); its resolve says how to obtain access, and no payment header is sent.
- `default`: Error

---

[API](https://skmtc.dev/particle/apis/particle-api.md) · [All operations](https://skmtc.dev/particle/apis/particle-api/llms.txt) · [OpenAPI document](https://skmtc.dev/particle/apis/particle-api/revisions/416ba82ab9d7?raw)
