> ## Documentation Index
> Fetch the complete documentation index at: https://docs.particle.pro/llms.txt
> Use this file to discover all available pages before exploring further.

# Lookup by external identifier

> Resolve Apple, Spotify, YouTube, and other platform identifiers to Particle podcasts — deterministically, in bulk, with each result echoing the input you sent.

If you already have a corpus of podcasts identified by their **Apple
collection ID**, **Spotify show ID**, **YouTube channel ID**, **RSS
feed URL**, or any other platform-native identifier, the regular
catalog endpoints aren't the right tool to reconcile them with
Particle's catalog:

* `GET /v1/podcasts/search?q=…` is a fuzzy *name* search. It can't find
  a show whose title you're spelling differently than we do — and
  there's no guarantee the top hit is the right podcast even when names
  look similar.
* `GET /v1/podcasts/{id}` accepts our internal ID, the Particle slug, or
  a numeric Apple/iTunes collection ID — but not Spotify, YouTube, or
  other third-party IDs.

The **lookup** endpoint closes that gap. Send it a `platform` plus up
to 100 platform-native identifiers, and it returns one record per
input — each echoing the identifier you sent alongside the matched
Particle podcast (or omitting the `podcast` key when the identifier
doesn't resolve). The same data backs [external links](/podcasts/external-links);
this endpoint lets you query it in the opposite direction — from
platform identifier to podcast.

Use this endpoint when you want to:

* Reconcile an existing corpus of podcasts (a CMS export, a chart
  scrape, a partner feed) with Particle's catalog by Apple/Spotify/etc.
  IDs.
* Map a **Spotify show ID**, **YouTube channel ID**, or other
  third-party identifier into our `podcast.id` before calling any other
  Particle endpoint. (A numeric Apple/iTunes collection ID can be passed
  straight into the `{id}` slot of any podcast endpoint — no lookup
  needed.)
* Bulk-resolve a list of identifiers without losing the input → output
  correlation that a fuzzy filter on `/v1/podcasts` can't give you.

## Look up by Apple Podcasts ID

<CodeGroup>
  ```bash curl theme={"dark"}
  curl -G "https://api.particle.pro/v1/podcasts/lookup" \
    -H "X-API-Key: $PARTICLE_API_KEY" \
    --data-urlencode "platform=apple" \
    --data-urlencode "identifier=1535809341,1200361736"
  ```

  ```js JavaScript theme={"dark"}
  const params = new URLSearchParams({
    platform: "apple",
    identifier: "1535809341,1200361736",
  });
  const res = await fetch(
    `https://api.particle.pro/v1/podcasts/lookup?${params}`,
    { headers: { "X-API-Key": process.env.PARTICLE_API_KEY } },
  );
  const { results } = await res.json();
  ```

  ```python Python theme={"dark"}
  res = httpx.get(
      "https://api.particle.pro/v1/podcasts/lookup",
      params={"platform": "apple", "identifier": "1535809341,1200361736"},
      headers={"X-API-Key": os.environ["PARTICLE_API_KEY"]},
  )
  results = res.json()["results"]
  ```
</CodeGroup>

```jsonc Response theme={"dark"}
{
  "results": [
    {
      "identifier": "1535809341",
      "podcast": {
        "id": "QpMz7GYKfSNuUa6zKXA4Q",
        "title": "All-In with Chamath, Jason, Sacks & Friedberg",
        "slug": "all-in-with-chamath-jason-sacks-friedberg",
        "image_url": "https://cdn.particle.pro/podcasts/all-in.jpg"
      }
    },
    {
      "identifier": "1200361736"
      // no `podcast` key — this Apple ID didn't resolve
    }
  ]
}
```

That's the whole shape. Each result echoes the input `identifier` so
you can join the response back to your input list by position *or* by
key — your call. Unresolved identifiers omit the `podcast` field
entirely; clients should test for key presence rather than a `null`
value, matching the convention used elsewhere in the API for nullable
nested resources.

## Look up by RSS feed URL

The `rss` platform is the odd one out: it doesn't live in
`external-links` because every podcast already carries its own
canonical feed URL on the podcast itself. Pass the URL exactly as it
appears on the podcast's RSS feed:

<CodeGroup>
  ```bash curl theme={"dark"}
  curl -G "https://api.particle.pro/v1/podcasts/lookup" \
    -H "X-API-Key: $PARTICLE_API_KEY" \
    --data-urlencode "platform=rss" \
    --data-urlencode "identifier=https://feeds.simplecast.com/54nAGcIl"
  ```

  ```js JavaScript theme={"dark"}
  const params = new URLSearchParams({
    platform: "rss",
    identifier: "https://feeds.simplecast.com/54nAGcIl",
  });
  const res = await fetch(
    `https://api.particle.pro/v1/podcasts/lookup?${params}`,
    { headers: { "X-API-Key": process.env.PARTICLE_API_KEY } },
  );
  const { results } = await res.json();
  ```

  ```python Python theme={"dark"}
  res = httpx.get(
      "https://api.particle.pro/v1/podcasts/lookup",
      params={"platform": "rss", "identifier": "https://feeds.simplecast.com/54nAGcIl"},
      headers={"X-API-Key": os.environ["PARTICLE_API_KEY"]},
  )
  results = res.json()["results"]
  ```
</CodeGroup>

Comparison is **byte-exact**: a `?param` suffix, a trailing slash, or
`http://` vs `https://` will not match if our stored URL is the other
form. If you don't have the URL exactly as the publisher serves it,
fall back to looking up by Apple/Spotify/YouTube ID instead — those
are more forgiving to normalise.

## Parameters

| Field        | Description                                                                                                                                                                                                                                                                                                  |
| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `platform`   | **Required.** Platform slug — any value from the [external-links platform reference](/podcasts/external-links#platform-reference), plus two in-house aliases: `itunes` (treated as `apple`) and **`rss`** (match by canonical RSS feed URL — see [Look up by RSS feed URL](#look-up-by-rss-feed-url) above). |
| `identifier` | **Required.** One or more platform-native identifiers, comma-separated. Up to **100 per call**. Duplicates in your input are deduped silently — you'll get one result per unique input.                                                                                                                      |

A few details worth knowing up front:

* **Order is preserved.** Results appear in the request order of their
  first occurrence. If you send `?identifier=A,B,A`, you get two
  results — A then B — not three.
* **Exact matching only.** Identifiers are compared exactly; case
  differences and prefix mismatches do not resolve. Leading and
  trailing whitespace is stripped automatically so a copy-pasted ID
  with stray spaces still works.
* **`platform=bogus` is a 400.** Unknown platform slugs return an
  error listing every accepted slug — same vocabulary as the
  external-links responses.

## Looking up the same podcast across platforms

The endpoint takes one platform at a time. To resolve a multi-platform
corpus, fan out one call per platform — each call covers up to 100
identifiers and the responses are independent:

<CodeGroup>
  ```bash curl theme={"dark"}
  # Apple
  curl -G "https://api.particle.pro/v1/podcasts/lookup" \
    -H "X-API-Key: $PARTICLE_API_KEY" \
    --data-urlencode "platform=apple" \
    --data-urlencode "identifier=1535809341"

  # Spotify
  curl -G "https://api.particle.pro/v1/podcasts/lookup" \
    -H "X-API-Key: $PARTICLE_API_KEY" \
    --data-urlencode "platform=spotify" \
    --data-urlencode "identifier=5BiqcD1FSCwlgZTcljpAYi"

  # YouTube
  curl -G "https://api.particle.pro/v1/podcasts/lookup" \
    -H "X-API-Key: $PARTICLE_API_KEY" \
    --data-urlencode "platform=youtube" \
    --data-urlencode "identifier=UCESLZhusAkFfsNsApnjF_Cg"

  # RSS feed URL (matches against the canonical podcast feed URL)
  curl -G "https://api.particle.pro/v1/podcasts/lookup" \
    -H "X-API-Key: $PARTICLE_API_KEY" \
    --data-urlencode "platform=rss" \
    --data-urlencode "identifier=https://feeds.simplecast.com/54nAGcIl"
  ```
</CodeGroup>

Once you have the resolved `podcast.id` for each input, hit
[`GET /v1/podcasts/{id}/external-links`](/podcasts/external-links) to
see every other platform that podcast also lives on. That's the natural
follow-up when you want to enrich rather than reconcile.

## Behavior and edge cases

### Apple Podcasts and iTunes share IDs

Apple Podcasts uses a single numeric collection ID across both its
modern and iTunes-era surfaces. The lookup endpoint reflects that:
`platform=apple` and `platform=itunes` are aliases that behave
identically — either form finds the same matches.

<Note>
  Because Apple/iTunes IDs are always numeric, you can also pass one
  **straight into the `{id}` slot** of any podcast endpoint — e.g.
  `GET /v1/podcasts/1535809341` — and skip this lookup entirely. The
  `{id}` slot resolves iTunes IDs the same way this lookup does —
  including the [highest-charting tiebreaker](#ambiguous-identifiers-resolve-to-the-highest-charting-podcast)
  for shared identifiers — so both always return the same podcast.
</Note>

### Misses omit the `podcast` field

Unmatched identifiers come back as `{"identifier": "…"}` with no
`podcast` key. This is intentional — OpenAPI clients now see an
accurate schema where `podcast` is optional, and absence is a single
sentinel for "no match" without the ambiguity of explicit `null`.

```jsonc theme={"dark"}
// Matched
{ "identifier": "1535809341", "podcast": { "id": "…", "title": "…", "slug": "…", "image_url": "…" } }

// Unmatched
{ "identifier": "9999999999" }
```

### Duplicates collapse

If your input list contains duplicates, the response contains one
entry per unique identifier — in the order each one first appeared. We
do this silently rather than echoing duplicates back, so your client
doesn't have to dedupe twice.

### Compact response only

The matched podcast is returned in the compact shape (`id`, `title`,
`slug`, `image_url`) — enough to pivot to any other endpoint, but
without the fuller metadata that
[`GET /v1/podcasts/{id}`](/podcasts/overview) returns. For each
identifier you actually care about, follow up with the detail endpoint
using the returned `id` (or `slug`).

### Ambiguous identifiers resolve to the highest-charting podcast

A few platform identifiers in the wild are claimed by more than one
podcast — most often when a publisher exposes the *same* YouTube
channel as the video presence for several shows (e.g. the parent New
York Times YouTube channel is listed under The Daily, Serial, The
Headlines, Matter of Opinion, The Book Review, and others). When that
happens, the lookup returns the podcast with the highest current
Apple Podcasts / Spotify chart ranking, so the same input always
resolves to the same output across calls.

If you need to find *every* podcast a shared identifier belongs to,
that's an [external-links](/podcasts/external-links) question, not a
lookup one — start from each candidate podcast and inspect its
external-link rows.

### 100-identifier cap

Calls with more than 100 identifiers are rejected with a 400. The cap
is generous enough that most reconciliations fit in a single round-trip;
if you need more, fan out in chunks of 100. (The cap is per platform —
you can do multiple platform calls in parallel.)

## Choosing the right endpoint

| You want to…                                                                                        | Use this                                                           |
| --------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
| Resolve a known **Apple / Spotify / YouTube / …** ID to a Particle podcast                          | **`GET /v1/podcasts/lookup`** *(this page)*                        |
| Resolve a **RSS feed URL** to a Particle podcast                                                    | **`GET /v1/podcasts/lookup?platform=rss`** *(this page)*           |
| Search by podcast **name** (fuzzy text match)                                                       | [`GET /v1/podcasts/search?q=…`](/podcasts/search)                  |
| Get the **full** podcast detail object (publisher, language, episode count, bias, suitability tier) | [`GET /v1/podcasts/{id}`](/podcasts/overview)                      |
| Enumerate every platform a Particle podcast lives on                                                | [`GET /v1/podcasts/{id}/external-links`](/podcasts/external-links) |
| Search **dialogue** inside episodes (not podcasts)                                                  | [`GET /v1/podcasts/episodes/search`](/podcasts/episode-search)     |

## Related

* [External links](/podcasts/external-links) — given a Particle podcast, list every third-party platform identifier we have for it; the opposite direction of this endpoint.
* [Podcasts overview](/podcasts/overview) — full Podcast object and all sub-resources.
* [Concepts](/concepts) — pagination, pricing weights, and authentication.
