Streaming Availability API & Scraper
The Streaming Availability API returns where-to-watch data as clean JSON.
🤖 Using an AI assistant? Copy this link into ChatGPT / Claude / Cursor — it reads every endpoint and parameter instantly and tells you if this API fits your use case.
The primary search endpoint returns titles with offers (provider, type, quality, price, URL) and external ids, and you can browse, see trending, pull a title, check availability, list new titles and countries. It is built for streaming-guide apps and media tools that need cross-service availability without a scraper. One ReefAPI key, one shared credit pool, the standard envelope.
Provider codes the packages filter actually accepts
packages does not take the technical_name that the providers action returns. It takes JustWatch's short package codes, and an unrecognized code is silently ignored rather than rejected, so a wrong value looks like a working call over the entire catalog. Each code below was verified by browsing US movies and checking that every returned title carried an offer from that provider. The last column is the US movie count that code filtered down to.
| packages code | Provider every result carried | US movie catalog size |
|---|---|---|
| nfx | Netflix, including Netflix Standard with Ads | 4,570 |
| amp | Amazon Prime Video, including Prime Video with Ads | 22,777 |
| dnp | Disney Plus | 1,405 |
| hlu | Hulu | 1,233 |
| mxx | HBO Max, including HBO Max Amazon Channel | 1,871 |
| pmp | Paramount Plus Essential and Premium | 811 |
| pct | Peacock Premium and Premium Plus | 873 |
| atp | Apple TV, the subscription service | 123 |
| itu | Apple TV Store, the rent and buy storefront | 49,456 |
| cru | Crunchyroll | 252 |
| any unrecognized code | no filter is applied at all | 162,472, the unfiltered total |
packages filters which titles come back, not which offers hang off them. A browse restricted to nfx still returns each title's full offer list, Amazon and Apple TV Store rows included. The only way to confirm the filter took effect is to compare meta.total against the unfiltered 162,472.
Real request and response JSON
Captured from the indexed primary action, search, on .
{
"method": "POST",
"url": "https://api.reefapi.com/streaming/v1/search",
"headers": {
"x-api-key": "$REEF_KEY",
"content-type": "application/json"
},
"body": {
"query": "Inception",
"country": "US"
}
}{
"ok": true,
"meta": {
"api": "streaming",
"endpoint": "search",
"mode": "live",
"latency_ms": 745.6,
"record_count": 4,
"bytes": 16394,
"cache_hit": false,
"total": 4,
"has_more": false,
"next_cursor": "NA=="
},
"data": {
"results": [
{
"id": "tm92641",
"object_id": 92641,
"object_type": "MOVIE",
"title": "Inception",
"year": 2010,
"release_date": null,
"path": "/us/movie/inception",
"description": "A thief who steals corporate secrets through the use of dream-sharing technology is given the inverse task of planting an idea into the mind of a CEO, but his tragic past may doom the project and his team to disaster.",
"poster_url": "/poster/[redacted-phone]/{profile}/inception.{format}",
"runtime": 148,
"age_certification": "TV-14",
"season_number": null,
"episode_number": null,
"genres": [
"act",
"trl",
"scf"
],
"external_ids": {
"imdb": "tt1375666",
"tmdb": "27205"
},
"scoring": {
"imdb_score": 8.8,
"imdb_votes": 2827843,
"tmdb_popularity": 44.1872,
"tmdb_score": null,
"tomato_meter": null,
"jw_rating": null
},
"offers": [
{
"provider": "[trimmed-depth]",
"provider_id": "[trimmed-depth]",
"provider_technical_name": "[trimmed-depth]",
"type": "[trimmed-depth]",
"quality": "[trimmed-depth]",
"price": "[trimmed-depth]",
"price_value": "[trimmed-depth]",
"currency": "[trimmed-depth]",
"url": "[trimmed-depth]",
"element_count": "[trimmed-depth]",
"available_to": "[trimmed-depth]",
"icon": "[trimmed-depth]"
},
{
"provider": "[trimmed-depth]",
"provider_id": "[trimmed-depth]",
"provider_technical_name": "[trimmed-depth]",
"type": "[trimmed-depth]",
"quality": "[trimmed-depth]",
"price": "[trimmed-depth]",
"price_value": "[trimmed-depth]",
"currency": "[trimmed-depth]",
"url": "[trimmed-depth]",
"element_count": "[trimmed-depth]",
"available_to": "[trimmed-depth]",
"icon": "[trimmed-depth]"
},
{
"provider": "[trimmed-depth]",
"provider_id": "[trimmed-depth]",
"provider_technical_name": "[trimmed-depth]",
"type": "[trimmed-depth]",
"quality": "[trimmed-depth]",
"price": "[trimmed-depth]",
"price_value": "[trimmed-depth]",
"currency": "[trimmed-depth]",
"url": "[trimmed-depth]",
"element_count": "[trimmed-depth]",
"available_to": "[trimmed-depth]",
"icon": "[trimmed-depth]"
}
],
"total_season_count": null,
"total_episode_count": null,
"cursor": "MQ=="
},
{
"id": "tm818540",
"object_id": 818540,
"object_type": "MOVIE",
"title": "The Crack: Inception",
"year": 2019,
"release_date": null,
"path": "/us/movie/the-crack-inception",
"description": "Madrid, Spain, 1975; shortly after the end of the Franco dictatorship. Six months after the mysterious death of his lover, a prestigious tailor, a married woman visits the office of the young Germán Areta, a former police officer turned private detective, to request his professional services.",
"poster_url": "/poster/[redacted-phone]/{profile}/the-crack-inception.{format}",
"runtime": 117,
"age_certification": "PG-13",
"season_number": null,
"episode_number": null,
"genres": [
"crm",
"drm",
"trl"
],
"external_ids": {
"imdb": "tt6793710",
"tmdb": "613092"
},
"scoring": {
"imdb_score": 6.6,
"imdb_votes": 985,
"tmdb_popularity": 1.4716,
"tmdb_score": null,
"tomato_meter": null,
"jw_rating": null
},
"offers": [
{
"provider": "[trimmed-depth]",
"provider_id": "[trimmed-depth]",
"provider_technical_name": "[trimmed-depth]",
"type": "[trimmed-depth]",
"quality": "[trimmed-depth]",
"price": "[trimmed-depth]",
"price_value": "[trimmed-depth]",
"currency": "[trimmed-depth]",
"url": "[trimmed-depth]",
"element_count": "[trimmed-depth]",
"available_to": "[trimmed-depth]",
"icon": "[trimmed-depth]"
}
],
"total_season_count": null,
"total_episode_count": null,
"cursor": "Mg=="
},
{
"id": "tm429177",
"object_id": 429177,
"object_type": "MOVIE",
"title": "Bikini Inception",
"year": 2015,
"release_date": null,
"path": "/us/movie/bikini-inception",
"description": "Two flunky Janitors in an Arctic Lab perform unauthorized experiments transporting them to a beach dream world in Malibu California w/50 beautiful young girls and a female Brazilian PhD Student wearing only a bra and panties. A '67 Muscle car races chases horses guns fights surfing, sumo wrestler, wolf monster, underwater scenes tons of gorgeous models. Sexy sci-fi fun.",
"poster_url": "/poster/[redacted-phone]/{profile}/bikini-inception.{format}",
"runtime": 106,
"age_certification": "",
"season_number": null,
"episode_number": null,
"genres": [
"cmy"
],
"external_ids": {
"imdb": "tt8269586",
"tmdb": "542438"
},
"scoring": {
"imdb_score": 4.4,
"imdb_votes": 29,
"tmdb_popularity": 0.7654,
"tmdb_score": null,
"tomato_meter": null,
"jw_rating": null
},
"offers": [
{
"provider": "[trimmed-depth]",
"provider_id": "[trimmed-depth]",
"provider_technical_name": "[trimmed-depth]",
"type": "[trimmed-depth]",
"quality": "[trimmed-depth]",
"price": "[trimmed-depth]",
"price_value": "[trimmed-depth]",
"currency": "[trimmed-depth]",
"url": "[trimmed-depth]",
"element_count": "[trimmed-depth]",
"available_to": "[trimmed-depth]",
"icon": "[trimmed-depth]"
},
{
"provider": "[trimmed-depth]",
"provider_id": "[trimmed-depth]",
"provider_technical_name": "[trimmed-depth]",
"type": "[trimmed-depth]",
"quality": "[trimmed-depth]",
"price": "[trimmed-depth]",
"price_value": "[trimmed-depth]",
"currency": "[trimmed-depth]",
"url": "[trimmed-depth]",
"element_count": "[trimmed-depth]",
"available_to": "[trimmed-depth]",
"icon": "[trimmed-depth]"
},
{
"provider": "[trimmed-depth]",
"provider_id": "[trimmed-depth]",
"provider_technical_name": "[trimmed-depth]",
"type": "[trimmed-depth]",
"quality": "[trimmed-depth]",
"price": "[trimmed-depth]",
"price_value": "[trimmed-depth]",
"currency": "[trimmed-depth]",
"url": "[trimmed-depth]",
"element_count": "[trimmed-depth]",
"available_to": "[trimmed-depth]",
"icon": "[trimmed-depth]"
}
],
"total_season_count": null,
"total_episode_count": null,
"cursor": "Mw=="
}
]
}
}What the Streaming Availability API does
| Action | Description | Concrete use case | Key params |
|---|---|---|---|
| search | search movies/shows with current offers | Content platforms call search to search movies/shows with current offers. | query, country, language, page_size, cursor |
| browse | browse a provider/country catalog by genre/type/year, ranked (sort_by), with pagination | Research tools call browse to get browse a provider/country catalog by genre/type/year, ranked (sort_by), with pagination. | country, language, object_types, packages, genres, ... |
| trending | trending titles right now (with where-to-watch offers), filterable by provider/type/genre | Community analysts call trending to get trending titles right now (with where-to-watch offers), filterable by provider/type/genre. | country, language, sort_by, object_types, packages, ... |
| title | title metadata and offers by JustWatch node id | Media monitors call title to get title metadata and offers by JustWatch node id. | id, query, url, country, language |
| availability | where-to-watch offers for one title across multiple countries (the core comparison call) | Content platforms call availability to get where-to-watch offers for one title across multiple countries (the core comparison call). | id, query, url, countries, country, ... |
| new | what's new / coming soon / leaving soon on a provider — by country/provider/type | Research tools call new to get what's new / coming soon / leaving soon on a provider. | country, language, packages, object_types, date, ... |
| countries | supported country codes | Community analysts call countries to get supported country codes. | none |
| genres | JustWatch genre reference for a country/language | Media monitors call genres to get justWatch genre reference for a country/language. | country, language |
| providers | streaming providers available in a country | Content platforms call providers to get streaming providers available in a country. | country |
| country | one country plus live supported provider/service details | Research tools call country to get one country plus live supported provider/service details. | country |
| seasons | show seasons with offers | Community analysts call seasons to get show seasons with offers. | id, country, language |
| episodes | season episodes with offers; show id + season_number resolves first | Media monitors call episodes to get season episodes with offers; show id + season_number resolves first. | id, season_id, season_number, country, language, ... |
Call search from your stack
curl -X POST https://api.reefapi.com/streaming/v1/search \
-H "x-api-key: $REEF_KEY" \
-H "content-type: application/json" \
-d '{"query":"Inception","country":"US"}'import requests
r = requests.post(
"https://api.reefapi.com/streaming/v1/search",
headers={"x-api-key": REEF_KEY},
json={
"query": "Inception",
"country": "US"
},
)
print(r.json()["data"])const res = await fetch("https://api.reefapi.com/streaming/v1/search", {
method: "POST",
headers: {
"x-api-key": process.env.REEF_KEY,
"content-type": "application/json",
},
body: JSON.stringify({
"query": "Inception",
"country": "US"
}),
});
const { ok, data, meta, error } = await res.json();Ask your MCP-connected assistant: call reefapi.streaming.search with {"query":"Inception","country":"US"}.Who uses this API and why
- Streaming-guide apps call search and availability to show where a title streams.
- Media apps use new and trending to surface what just landed on services.
- Regional tools use countries to localize availability for a user.
Questions developers ask before integrating
Why does packages with the value netflix return the whole catalog?
Because netflix is the technical_name from the providers action, not a packages code, and unrecognized package values are dropped instead of rejected. Measured side by side on US movies: packages nfx reported meta.total 4,570 and every row carried a Netflix offer, while packages netflix reported 162,472 and the first rows were Peacock and Amazon rentals. Both returned ok true. Compare meta.total against the unfiltered count before trusting a filtered feed.
Why is price null on a Netflix offer but a real number on a rental?
Subscription offers have no per-title price, so type FLATRATE comes back with price null and price_value null while currency is still filled in from the market. Rent and buy offers carry both: a measured RENT offer in the US returned price $3.99 and price_value 3.99, and the same film in Turkey returned price TRY 24.99 and price_value 24.99. Use price_value for arithmetic and price only for display, since its formatting follows the market.
Which countries are covered, and does the provider list change between them?
The countries action returns 147 ISO-2 markets and reports its source as a static market reference, so treat it as the list of markets you may ask for rather than a live health check. Mainland China is not in it. Provider coverage varies sharply by market: the providers action returned 347 entries for US and 72 for TR. Ask providers per country instead of assuming a service exists there.
Why does Prime Video have two different technical names?
JustWatch registers a service per market, so the same brand can carry a different id and technical_name in each. Prime Video came back as technical_name amazonprime with provider_id 9 in the US, and as amazonprimevideo with provider_id 119 in Turkey. Match offers on the human-readable provider field or on a per-country id map, never on a technical_name you hardcoded from one market.
What is a node id, and where do I get one?
Every JustWatch object has a prefixed node id: tm for a movie, ts for a show, tse for a season. Breaking Bad is ts4 and Inception is tm92641. Search and browse rows return it as id, with the numeric part repeated as object_id. title, availability, seasons and episodes all take it directly, which skips the resolve-by-name step and removes the risk of matching the wrong title.
Why do results from the new action have null ids and no offers?
new is a change feed, not a metadata feed. A measured leaving-soon call on Netflix US returned rows where external_ids.imdb, external_ids.tmdb, every scoring field, runtime and age_certification were all null and offers was an empty list. The only populated block is new_offer, which carries the provider, the type, available_to and date_created. Take the node id from the row and call title if you need the rest.
How current is availability, and what does available_to mean?
Offers are fetched at call time, so what you get is the state right then and there is no as-of timestamp in the response. available_to is the forward-looking part: the date an offer is scheduled to expire, null when no end has been announced. Measured examples: an HBO Max Amazon Channel offer in GB carried available_to 2026-12-31, and a Netflix US title on the leaving feed carried available_to 2026-08-31 with date_created 2026-08-03, the day that offer first appeared.
Do title fields change with the country I ask for?
Some do. Requesting ts4 with country GB returned path /uk/tv-series/breaking-bad and age_certification 18, while the US call returned the US path and TV-MA. Age ratings are per-market strings with no shared scale, and an empty string turns up where a title is unrated, so test for both the empty string and null. Title, year, runtime and the imdb and tmdb external ids stay the same across markets.
What is the Streaming Availability API?
Streaming Availability API is a ReefAPI endpoint group for streaming availability It returns live JSON through POST requests under /streaming/v1.
Is the Streaming Availability API free to try?
Yes. ReefAPI starts with 1,000 free credits, no card required. Streaming Availability calls use the same shared credit balance as every other ReefAPI engine.
Do I need a Streaming Availability login or account?
No login to Streaming Availability is needed for the API response. You call ReefAPI with your x-api-key header, and the playground can run live examples before you create a production key.
How fresh is the Streaming Availability data?
The page example is captured from a live search call, and production requests fetch live data through ReefAPI rather than a static sample.
How many credits does the Streaming Availability API use?
Streaming Availability actions currently cost 1-2 credits per successful call. Failed or blocked calls are free, and all APIs draw from one credit pool.
Can I call Streaming Availability from an AI assistant or MCP client?
Yes. Connect ReefAPI once through MCP and your assistant can call streaming actions with the same key, credit pool and JSON envelope used by normal REST requests.