I work on OnePassApps, so this is a measurement of our own product rather than a review of somebody else's. MovieMatcherAI has a browse tab that lists films, and behind it sits a JSON endpoint that had not been written down anywhere I could find. So I read it, and this is what it actually answers.
The endpoint is GET https://api.onepassapps.com/api/movie-tracker/catalog. It is a plain public read: no key, no session, no cookie, no account. Every fact below came from ordinary HTTPS requests made from outside a browser on 5 November 2026, and the field census covers all 650 records rather than a sample.
Open MovieMatcherAI to see the browse tab, or read the app guides for the rest of the product.
The envelope
The response has three top-level keys and no others: ok, data and meta.
{
"ok": true,
"data": {
"query": "",
"normalizedQuery": "",
"mediaType": "movie",
"region": "US",
"page": 1,
"provider": "wikidata",
"cacheStatus": "miss",
"providerStatus": "unavailable",
"totalPages": 33,
"totalResults": 650,
"results": []
},
"meta": {
"requestId": "req_...",
"pagination": { "page": 1, "pageSize": 20, "total": 650 }
}
}
Two of those fields are worth pausing on. provider reads wikidata, and providerStatus reads unavailable — on every read I made, including repeats seconds apart. The upstream the catalogue is built from was not being reached during this test, and the endpoint still answered with the full 650-title catalogue. The freshness markers on the records themselves say the same story from the other side: every item carried a metadataFetchedAt on 2026-09-29 and a metadataStaleAt exactly thirty days later on 2026-10-29. Across all 650 records there are only four distinct metadataFetchedAt values, all on that one evening and all inside a thirty-one-second window — 21:33:32, 21:33:41, 21:33:50 and 21:34:03 — which is what a single gathering run looks like. So the catalogue was assembled in one pass, and the envelope is reporting, accurately, that it is not currently going back to the source.
The parameter contract, enforced rather than documented
The endpoint does not ignore bad parameters. It rejects them with a VALIDATION_ERROR envelope, and the error carries the list of options it would have accepted:
{
"ok": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid MovieMatcherAI request.",
"details": { "issues": [ {
"code": "invalid_value",
"values": ["movie", "tv", "all"],
"path": ["mediaType"],
"message": "Invalid option: expected one of \"movie\"|\"tv\"|\"all\""
} ] }
}
}
Reading those errors is the fastest way to learn the API. mediaType accepts movie, tv or all. discovery accepts all, this-week, new-releases or top-rated. sort accepts popular, top-rated, newest or oldest. Anything else comes back with Invalid MovieMatcherAI request. and no data.
Counts differ sharply between those modes, measured on the same day:
| Request | totalResults |
|---|---|
discovery=all |
650 |
discovery=top-rated |
511 |
discovery=new-releases |
88 |
discovery=this-week |
88 |
mediaType=tv |
2 |
mediaType=all |
652 |
The browse tab on the live site is showing you one of these without naming it. The page loaded with discovery=new-releases and rendered the counter 20 of 88 — 20 rows out of the 88 the endpoint reports for that mode, which is exactly pageSize from meta.pagination. The first three rows on the page and the first three results the API returned for the same query were the same films, in the same order: Masterplan, Whalefall, Animals.
Two parameters that are accepted but do nothing
region is echoed back and changes nothing else. I fetched the same page as US, GB, DE and even XX; with the requestId stripped, the payloads were identical except for the echoed region string, and the results arrays compared equal element by element every time. There is no regional filtering behind that parameter today — it is a label, not a filter.
query is worse. Send query=matrix and the request succeeds, totalResults stays at 650, and the results array is the same list you get with no query at all. The endpoint even tells you it ignored you: the query field comes back as an empty string and normalizedQuery comes back as an empty string. Search on that tab is done somewhere else.
What each record actually carries
Every item in results has the same 45 keys. I fetched all 650 across all 33 pages and counted how often each key is populated. The shape is consistent, and so are the gaps:
-
On all 650:
id,title,mediaType,overview,tmdbId,imdbId,contentPolicy,sourceUrl,popularity,ratingEnrichment,metadataFetchedAt,metadataStaleAt, andwatchAvailability. -
On none of the 650:
reportedRatings,castSource,originalTitle,firstAirDate,seriesStatus,seasonCount,contentRating,awards,imdbVotes,boxOffice,watchProviders,watchLink,posterPathandbackdropPath. -
Mostly filled:
descriptionSourceon 644,releaseYearon 648,countrieson 648,peopleon 648,directoron 647,genreson 641,languageson 642,caston 629,writerson 617,runtimeMinuteson 614,releaseDateon 518,providerMediaon 398,posterUrlon 405. -
Exactly half:
ratingSource,voteAverage,voteCountandratingsare populated on 511 records and empty on the other 139. That 511 is the same number as thediscovery=top-ratedtotal. -
Present but always a placeholder:
watchAvailabilityis on every record and reads the stringunknownon every one of them, withwatchLinknull throughout. So the field exists and tells you nothing. -
Null by design on movies:
seriesStatus,seasonCountandfirstAirDateare null on every movie, because they belong to the television branch.
Two titles have no releaseYear at all — One Last Shot and Clean Hands — and the rest run from 1922 to 2027, with 648 of 650 carrying a year at all. The genres are Wikidata's own rather than a normalised set: there are 182 distinct genre strings across the 650 films, from arthouse science fiction and sword-and-sandal through white savior and girls with guns.
The identifiers are worth reading once, because they tell you how a record is keyed. An id looks like mt_title_movie_wikidata_q40083273: media type, then the provider, then the provider's own id, lowercased. The same item also carries tmdbId as wikidata:Q40083273 and imdbId as tt3566834, so one row carries three different namespaces for the same film.
Where the text and the pictures come from
Provenance is spelled out per record rather than implied. contentPolicy was wikidata-cc0-v1 on all 650. The description is not generated: descriptionSource names wikipedia, gives the exact article URL, the revision id, a revisionUrl pinned to that revision, a historyUrl, and the licence CC-BY-SA-4.0 with its URL. It even records what was done to the text: Selected introductory paragraphs; formatting simplified. On the first record that is revision 1378124578 of the article for A Minecraft Movie.
The artwork and trailers come from a different provider with a different permission. Where providerMedia is populated — 398 of 650 — the provider reads kinocheck and the kind reads trailer-thumbnail, with a per-film imageCaption, an attribution line, a licenseLabel of KinoCheck promotional media permission, plus reviewedAt, youtubeId and a trailerUrl. Eleven of the twenty records on page one carried one; the other nine had no providerMedia at all. The same attribution line appears in the page footer of the live browse tab.
The television branch is two rows wide
The site calls itself "Movies, TV and private watchlists", so the tv mode is worth its own look. It returns exactly two records: Breaking Bad and Game of Thrones, with totalPages of 1. Asking for tv with discovery=new-releases returns zero. Neither of the two carries a releaseYear, a firstAirDate, a seasonCount or a seriesStatus — the fields exist on the record and are null, which is a different thing from a record that has been filled in and happens to be empty.
Limits of this measurement
One build, one day, one signed-out session, no cookies, plain HTTPS from outside a browser, on 5 November 2026. I fetched all 33 pages of the movie catalogue and counted field presence across all 650 records. The providerStatus reading of unavailable means the upstream was down or blocked for this network during the test, so I could not confirm whether the stored catalogue would change on a successful refresh. sort was read from its validation error and from two orderings: popular gives A Minecraft Movie, Jurassic World Rebirth, Titanic — the same order as no sort — while newest gives Elsinore, The Rescue, Pendulum. I did not compare the full ordering of top-rated or oldest. query was tested with one term. The browse tab's own on-screen filtering — Rating, Genre, Year, Person — happens in the page, not in this endpoint, so I did not test it here.
Top comments (0)