Discover endpoints
Browse the catalogue without a seed code: trending, similar titles, releases by day, studios, series, genres and random picks.
Thirteen GET endpoints over the catalogue, not one code. All use x-javinfo-key and are metered; most return
meta with sources, documents scanned and latency.
Base price is $0.40 per 1,000 calls. Above 10, price scales with page size, so num matters: num=20 costs $0.80.
Formula in Rate limits & billing.
| Endpoint | Use it for | Per 1,000 at default |
|---|---|---|
/discover/trending | Recent releases, ranked | $0.80 (num=20) |
/discover/underrated | High-rated older titles | $0.80 (num=20) |
/discover/suggestion | Typeahead across codes, performers, tags and studios | $0.40 (num=8) |
/discover/similar | Titles like one seed code | $0.48 (num=12) |
/discover/duel | A seeded A/B pair | $0.40 |
/discover/calendar | Releases bucketed by day | $0.40 |
/discover/tags | Tag counts in a time window | $1.20 (num=30) |
/discover/studios | Studio directory, or one studio's catalogue | $1.20 / $0.80 |
/discover/series | One series, newest first | $0.80 (num=20) |
/discover/genres | Genre counts for the whole catalogue | $2.40 (num=60) |
/discover/random | Random titles matching filters | $0.40 (num=10) |
/discover/for-you | Picks from the account's own search history | $0.80 (num=20) |
/discover/stats | Catalogue totals per source | $0.40 |
Movie card
Every title in a discovery response has this shape. One card, one renderer, every endpoint below.
| Field | Type | Notes |
|---|---|---|
code | string | Normalised title code, e.g. ABP-002 |
title | string | null | English title only; null when the source has none. javbus rows often have title: null with the Japanese title in titleJa |
titleJa | string | null | Japanese title |
releaseDate | string | null | YYYY-MM-DD |
runtimeMins | number | null | Minutes |
maker | string | null | Studio / maker |
label | string | null | Label |
series | string | null | Series, as the source spells it |
categories | string[] | Genre tags |
actresses | string[] | Cast, English names where a source has them |
cover | string | null | Jacket URL |
rating | number | null | javlibrary only, 1–10; null on every other source |
source | string | Which source supplied this card: fanza, javdatabase, javlibrary, javbus or missav |
url | string | null | Page on the source site, when the source stores one |
Cards collapse by code across indexes; the first in preference order supplies metadata. rating
is the exception: only javlibrary has ratings, so other sources return null even for rated titles.
meta:
| Field | Type | Notes |
|---|---|---|
sources | string[] | Public source names that answered with hits or facet counts. An empty array usually means the catalogue could not be reached |
scanned | number | Documents read before ranking or filtering. 0 on facet-only endpoints |
latencyMs | number | Server-side time |
Examples are trimmed: first items, "…" for repeats, long titles cut. Values are real.
/discover/trending
API: /discover/trending
Recent releases ranked by quality, not just date. For a home page or a "new this week" rail.
| Parameter | Type | Default | Range |
|---|---|---|---|
range | integer | 30 | 1–365, days back to look |
num | integer | 20 | 1–50 |
genre | string | none | Exact category name |
Price: $0.80 per 1,000 at num=20; $0.40 at num ≤ 10.
The handler reads the last range days, newest first, then re-ranks on recency, rating, gallery
size, previews and cast size. No upper date bound, so future-dated announcements appear.
curl -s 'https://api.javinfo.dev/discover/trending?range=7&num=3' \
-H "x-javinfo-key: jvi_your_key_here"{
"source": "discover:trending",
"count": 3,
"results": [
{
"code": "FCDSS-120",
"title": "4 Hours of the Best Anal Licking Service: Sticking My Tongue in Your Asshole! [FALENO Maniac Special Selection]",
"titleJa": null,
"releaseDate": "2026-12-03",
"runtimeMins": 240,
"maker": "Faleno",
"label": "Faleno",
"series": "FALENO Compilation",
"categories": ["Anal Play", "Beautiful Girl", "…"],
"actresses": ["Ayaka Tomoda", "Chiharu Mitsuha", "…"],
"cover": "https://www.javdatabase.com/covers/full/1f/1fcdss00120pl.webp",
"rating": null,
"source": "javdatabase",
"url": "https://www.javdatabase.com/movies/fcdss-120/"
},
"…"
],
"meta": {
"sources": ["fanza", "javdatabase", "…"],
"scanned": 45,
"latencyMs": 23
}
}Status: 200, 400, 401, 402, 429.
/discover/underrated
API: /discover/underrated
Older titles that were missed, ranked more by rating than date. For an "overlooked" shelf.
| Parameter | Type | Default | Range |
|---|---|---|---|
minAgeDays | integer | 365 | 30–3650, minimum age in days |
num | integer | 20 | 1–50 |
Price: $0.80 per 1,000 at num=20; $0.40 at num ≤ 10.
Only javlibrary has ratings, so the pool is that index alone: eight random 30-day slices over the 12 years before the cutoff. Unrated titles drop out; the score favours older, higher-rated, more complete records.
curl -s 'https://api.javinfo.dev/discover/underrated?num=3' \
-H "x-javinfo-key: jvi_your_key_here"{
"source": "discover:underrated",
"count": 3,
"results": [
{
"code": "IRCP-016",
"title": "The Price Of Chigasaki Lion Compliant With Me Naked",
"titleJa": "裸のわたしと言いなりの値段 茅ヶ崎りおん",
"releaseDate": "2014-07-13",
"runtimeMins": 120,
"maker": "Iromegane",
"label": "Iromegane",
"series": null,
"categories": ["Solowork", "Girl", "…"],
"actresses": ["Shiina Mayu (Chigasaki Rion)"],
"cover": "https://pics.dmm.co.jp/mono/movie/adult/ircp016/ircp016pl.jpg",
"rating": 10,
"source": "javlibrary",
"url": "https://www.javlibrary.com/en/javlijya24.html"
},
"…"
],
"meta": {
"sources": ["javlibrary"],
"scanned": 640,
"latencyMs": 63
}
}Status: 200, 400, 401, 402, 429.
/discover/suggestion
API: /discover/suggestion
Typeahead for a search box: codes, performers, tags and studios, deduplicated, codes first.
| Parameter | Type | Default | Range |
|---|---|---|---|
q | string | required | at least 1 character |
num | integer | 8 | 1–20 |
Price: $0.40 per 1,000 at num=8; $0.80 at num=20.
Each entry says what it is and what to show:
kind | value | label | extra |
|---|---|---|---|
code | Title code | Same code | English title, or the Japanese one when there is no English title |
idol | Performer id | Name | Image URL |
tag | Tag slug | Same slug | Count |
studio | Studio name | Same name | Count |
extra is nullable. Search reuses the movie indexes' prefix match; no separate n-gram index.
Suggestions build by kind (codes, performers, tags, studios), then cut to num.
curl -s 'https://api.javinfo.dev/discover/suggestion?q=ABP&num=3' \
-H "x-javinfo-key: jvi_your_key_here"{
"q": "ABP",
"count": 3,
"results": [
{
"kind": "code",
"value": "ABP-001",
"label": "ABP-001",
"extra": "Lola Misaki at Your Service Newest Beauty Salon Addict"
},
{
"kind": "code",
"value": "ABP-002",
"label": "ABP-002",
"extra": "NEW TOKYO Style 01 - Aikarin"
},
"…"
]
}A missing q is rejected before the handler runs:
curl -s 'https://api.javinfo.dev/discover/suggestion' \
-H "x-javinfo-key: jvi_your_key_here"{
"defined": false,
"code": "BAD_REQUEST",
"status": 400,
"message": "Input validation failed",
"data": {
"issues": [
{
"expected": "string",
"code": "invalid_type",
"path": ["q"],
"message": "Invalid input: expected string, received undefined"
}
]
}
}Status: 200, 400, 401, 402, 429.
/discover/similar
API: /discover/similar
"More like this." One code in, ranked neighbours, the seed card and the scores out. For a detail page.
| Parameter | Type | Default | Range |
|---|---|---|---|
q | string | required | A title code |
num | integer | 12 | 1–50 |
Price: $0.48 per 1,000 at num=12; $0.40 at num ≤ 10.
The seed resolves across movie indexes. Candidates share its first performer or one of its first
three tags, then rank on cast, tags, maker, label, series, runtime and date. The seed is excluded
from results; scores aligns with results by code, 0–1, three decimals.
A code no index knows is a 404, not an empty 200. A typo is never billed.
curl -s 'https://api.javinfo.dev/discover/similar?q=ABP-002&num=3' \
-H "x-javinfo-key: jvi_your_key_here"{
"source": "discover:similar",
"count": 3,
"results": [
{
"code": "WPC-013",
"title": "WPC-013 WATER POLE Aikarin",
"titleJa": "WPC-013 WATER POLE あいかりん",
"releaseDate": "2023-03-20",
"runtimeMins": 128,
"maker": "Prestige",
"label": "WPC",
"series": "WATER POLE",
"categories": ["Hot Girl", "Sailor Suit", "…"],
"actresses": ["Aikarin"],
"cover": null,
"rating": null,
"source": "missav",
"url": null
},
"…"
],
"meta": {
"sources": ["fanza", "javdatabase", "…"],
"scanned": 180,
"latencyMs": 72
},
"seed": {
"code": "ABP-002",
"title": "NEW TOKYO Style 01 - Aikarin",
"titleJa": null,
"releaseDate": "2013-06-01",
"runtimeMins": 127,
"maker": "Prestige",
"label": "ABSOLUTELY PERFECT",
"series": "Tokyo Style",
"categories": ["Facial", "Handjob"],
"actresses": ["Aikarin"],
"cover": "https://pics.dmm.co.jp/digital/video/118abp00002/118abp00002pl.jpg",
"rating": null,
"source": "fanza",
"url": null
},
"scores": [
{ "code": "WPC-013", "score": 0.5 },
{ "code": "MAS-110", "score": 0.496 },
"…"
]
}Unknown code, same request:
curl -s 'https://api.javinfo.dev/discover/similar?q=ZZZZ-99999&num=3' \
-H "x-javinfo-key: jvi_your_key_here"{
"defined": false,
"code": "NOT_FOUND",
"status": 404,
"message": "no title found for \"ZZZZ-99999\""
}Status: 200, 400, 401, 402, 404, 429.
/discover/duel
API: /discover/duel
A/B pair for a "which one" game. One seed, the same two cards for everyone.
| Parameter | Type | Default | Range |
|---|---|---|---|
seed | string | today's UTC date | any string |
genre | string | none | Exact category name |
performer | string | none | Exact performer name |
Price: $0.40 per 1,000, flat. No page-size knob.
The pool is the newest 40 titles from DMM + FANZA, javdatabase and javlibrary, deduplicated by
code, released and with a cast. genre and performer narrow it. A seeded PRNG picks two and
orders by code, so a and b land on the same sides for everyone. The pool moves with new releases, so a seed holds
only for that window. a and b are nullable if fewer than two candidates match.
curl -s 'https://api.javinfo.dev/discover/duel?seed=42' \
-H "x-javinfo-key: jvi_your_key_here"{
"seed": "42",
"a": {
"code": "DSOD-124",
"title": "That absolute, total fatso made me come so many times it was embarrassing…",
"titleJa": "最低最悪なあのデブに恥ずかしいほど何度もイカされて…ションベン垂れ流す肉便器調教された言いなり美人清掃員 天川そら",
"releaseDate": "2026-11-06",
"runtimeMins": 141,
"maker": "Das",
"label": "Das",
"series": null,
"categories": ["Deep Throat", "Embarrassment", "…"],
"actresses": ["Sora Amakawa"],
"cover": "https://pics.dmm.co.jp/digital/video/dsod00124/dsod00124pl.jpg",
"rating": null,
"source": "fanza",
"url": null
},
"b": {
"code": "VRKM-1944",
"title": "[VR] Getting Hooked on Sora Amakawa",
"titleJa": null,
"releaseDate": "2026-11-06",
"runtimeMins": 84,
"maker": "K M Produce",
"label": "K M Produce",
"series": "pond",
"categories": ["8KVR", "Beautiful Tits", "…"],
"actresses": ["Sora Amakawa"],
"cover": "https://www.javdatabase.com/covers/full/vr/vrkm01944pl.webp",
"rating": null,
"source": "javdatabase",
"url": "https://www.javdatabase.com/movies/vrkm-1944/"
}
}Status: 200, 401, 402, 429.
/discover/calendar
API: /discover/calendar
Releases between two dates, bucketed by day. For a release calendar.
| Parameter | Type | Default | Range |
|---|---|---|---|
from | string | today | YYYY-MM-DD |
to | string | today + 30 days | YYYY-MM-DD |
Price: $0.40 per 1,000, flat. Each loop call below is a separate call.
Both dates are inclusive. Defaults are independent: from alone still ends 30 days out, so pass
both for a past window. Empty days are omitted; buckets ascend. Each release is a full card.
Long ranges stop early
At 1,000 rows per source per call, a busy range fills in about 5 days. Only complete days return; it reports where it stopped:
| Field | Meaning |
|---|---|
through | The last day fully covered, YYYY-MM-DD. Equals to unless the answer was cut. |
truncated | true when days after through were cut. |
from=2026-11-01&to=2026-11-14 is too long for one call:
curl -s 'https://api.javinfo.dev/discover/calendar?from=2026-11-01&to=2026-11-14' \
-H "x-javinfo-key: jvi_your_key_here"{
"from": "2026-11-01",
"to": "2026-11-14",
"through": "2026-11-05",
"truncated": true,
"count": 1011,
"days": [
{
"date": "2026-11-01",
"count": 109,
"releases": [
{
"code": "DANDYA-045",
"title": null,
"titleJa": "母親と行った銭湯でコッソリおちんちんをいじってくるお姉さんに逃げても追いかけられ何度も精子を飲まれてしまいました",
"releaseDate": "2026-11-01",
"runtimeMins": 175,
"maker": "DANDY",
"label": null,
"series": null,
"categories": [
"4K",
"Big Asses",
"Big Tits",
"…"
],
"actresses": [],
"cover": "https://pics.dmm.co.jp/digital/video/1dandya00045/1dandya00045pl.jpg",
"rating": null,
"source": "fanza",
"url": null
},
"…"
]
},
"…"
],
"meta": {
"sources": [
"fanza",
"javdatabase",
"javlibrary",
"javbus",
"missav"
],
"scanned": 3136,
"latencyMs": 352
}
}That answer holds 1,011 titles for November 1–5. A range that fits returns whole:
from=2026-11-01&to=2026-11-03 gives "through": "2026-11-03" and "truncated": false.
For the rest, call again with from on the day after through and repeat until truncated is false. The
second call here is from=2026-11-06&to=2026-11-14:
{
"from": "2026-11-06",
"to": "2026-11-14",
"through": "2026-11-14",
"truncated": false,
"count": 1101,
"days": [
"…"
],
"meta": {
"sources": [
"fanza",
"javdatabase",
"javbus",
"missav"
],
"scanned": 1957,
"latencyMs": 627
}
}The same loop in code:
let from = '2026-11-01';
const to = '2026-11-14';
const days = [];
while (from <= to) {
const res = await fetch(
`https://api.javinfo.dev/discover/calendar?from=${from}&to=${to}`,
{ headers: { 'x-javinfo-key': KEY } },
);
const page = await res.json();
days.push(...page.days);
if (!page.truncated) break;
const next = new Date(`${page.through}T00:00:00Z`);
next.setUTCDate(next.getUTCDate() + 1);
from = next.toISOString().slice(0, 10);
}A single day over the cap returns partly filled, with through on that day; the loop moves on.
Status: 200, 400, 401, 402, 429.
/discover/tags
API: /discover/tags
Tag counts over a recent window, highest first. For a "trending tags" block.
| Parameter | Type | Default | Range |
|---|---|---|---|
range | integer | 30 | 1–365, days back |
num | integer | 30 | 1–100 |
Price: $1.20 per 1,000 at num=30; $0.40 at num ≤ 10.
Counts come from facets on DMM + FANZA and javdatabase. Tags are canonicalised first, so variants merge. Values are slugs, not display names.
curl -s 'https://api.javinfo.dev/discover/tags?range=7&num=5' \
-H "x-javinfo-key: jvi_your_key_here"{
"source": "discover:tags",
"count": 5,
"results": [
{ "tag": "featured-actress", "count": 3476 },
{ "tag": "hi-def", "count": 2834 },
"…"
],
"meta": {
"sources": ["fanza", "javdatabase"],
"scanned": 0,
"latencyMs": 117
}
}Status: 200, 400, 401, 402, 429.
/discover/studios
API: /discover/studios
One route, two shapes. Without q, a studio directory ranked by output in range; with q, that
studio's catalogue, newest first. kind says which: directory or catalogue.
| Parameter | Type | Default | Range |
|---|---|---|---|
q | string | none | Exact studio name; switches to catalogue mode |
range | integer | 365 | 30–3650, directory mode only |
num | integer | 30 directory, 20 catalogue | 1–100 directory; catalogue is capped at 50 |
page | integer | 1 | 1 and up, catalogue mode only |
Price: directory $1.20 per 1,000 at num=30; catalogue $0.80 at num=20. Catalogue caps
num at 50, so its top price is $2.00.
range is ignored with q; page is ignored without it. Catalogue total estimates the
studio's titles, so page against it.
curl -s 'https://api.javinfo.dev/discover/studios?num=3' \
-H "x-javinfo-key: jvi_your_key_here"{
"kind": "directory",
"source": "discover:studios",
"count": 3,
"results": [
{ "studio": "MOODYZ", "count": 2688 },
{ "studio": "S1 NO.1 STYLE", "count": 2382 },
"…"
],
"meta": {
"sources": ["fanza"],
"scanned": 0,
"latencyMs": 416
}
}curl -s 'https://api.javinfo.dev/discover/studios?q=S1%20NO.1%20STYLE&num=3' \
-H "x-javinfo-key: jvi_your_key_here"{
"kind": "catalogue",
"source": "discover:studio",
"studio": "S1 NO.1 STYLE",
"total": 25713,
"count": 3,
"results": [
{
"code": "K9SNOS349",
"title": null,
"titleJa": "【数量限定】特大号新人 希望みう 104cm Iの素顔 濃厚なキスして、本能で交わって、ありのままを曝け出す。 (ブルーレイディスク) 生写真3枚セット",
"releaseDate": "2026-11-25",
"runtimeMins": 120,
"maker": "S1 NO.1 STYLE",
"label": "S1 NO.1 STYLE",
"series": null,
"categories": ["Big Tits", "Featured Actress", "…"],
"actresses": ["希望みう"],
"cover": "https://pics.dmm.co.jp/mono/movie/adult/k9snos349/k9snos349ps.jpg",
"rating": null,
"source": "fanza",
"url": null
},
"…"
],
"meta": {
"sources": ["fanza"],
"scanned": 3,
"latencyMs": 7
}
}Status: 200, 400, 401, 402, 429.
/discover/series
API: /discover/series
One series' catalogue, newest first. Use it to list the rest when a caller opens a title.
| Parameter | Type | Default | Range |
|---|---|---|---|
q | string | required | Exact series name |
num | integer | 20 | 1–50 |
page | integer | 1 | 1 and up |
Price: $0.80 per 1,000 at num=20; $0.40 at num ≤ 10.
q is an exact series-name match on the DMM + FANZA index, not a search. Pass the stored string,
readable from any title's series. A partial name or different spelling returns 200 with
count: 0, not 404. total estimates the series' titles.
curl -s 'https://api.javinfo.dev/discover/series?q=Unfaithful%20Housewife&num=2' \
-H "x-javinfo-key: jvi_your_key_here"{
"source": "discover:series",
"count": 2,
"results": [
{
"code": "JUKD-481",
"title": "Unfaithful Housewife 5",
"titleJa": "不倫妻5",
"releaseDate": "2006-12-25",
"runtimeMins": 87,
"maker": "MADONNA",
"label": "Madonna",
"series": "Unfaithful Housewife",
"categories": ["69", "Adultery", "…"],
"actresses": ["Anna Muto", "Hiromi Yuki", "…"],
"cover": "https://pics.dmm.co.jp/digital/video/jukd00481/jukd00481pl.jpg",
"rating": null,
"source": "fanza",
"url": null
},
"…"
],
"meta": {
"sources": ["fanza"],
"scanned": 2,
"latencyMs": 14
},
"series": "Unfaithful Housewife",
"total": 7
}Status: 200, 400, 401, 402, 429.
/discover/genres
API: /discover/genres
The genre taxonomy with counts across the catalogue. Use it to seed a filter menu.
| Parameter | Type | Default | Range |
|---|---|---|---|
num | integer | 60 | 1–200 |
Price: $2.40 per 1,000 at num=60; $0.40 at num ≤ 10; $8.00 at num=200.
Values are display labels (Featured Actress), unlike /discover/tags slugs. Counts come from
DMM + FANZA only; a title listed on another source adds nothing.
curl -s 'https://api.javinfo.dev/discover/genres?num=5' \
-H "x-javinfo-key: jvi_your_key_here"{
"source": "discover:genres",
"count": 5,
"results": [
{ "genre": "Featured Actress", "count": 589656 },
{ "genre": "Creampie", "count": 438721 },
"…"
],
"meta": {
"sources": ["fanza"],
"scanned": 0,
"latencyMs": 163
}
}Status: 200, 400, 401, 402, 429.
/discover/random
API: /discover/random
Random titles matching optional filters. For a "surprise me" button.
| Parameter | Type | Default | Range |
|---|---|---|---|
genre | string | none | Exact category name |
performer | string | none | Exact performer name |
studio | string | none | Exact studio name |
censored | string | none | censored or uncensored |
num | integer | 10 | 1–50 |
Price: $0.40 per 1,000 at num=10; $2.00 at num=50.
Filters combine with AND. The draw is not uniform: the handler reads five random months, takes a random offset in each, shuffles and tops up when a narrow filter leaves it short. Consecutive calls return unrelated titles, not consecutive codes.
censored only matters as uncensored, which reads javbus's uncensored section instead of
DMM + FANZA. Passing censored equals omitting it. No cache: every call samples again. The
response has no meta and no source.
curl -s 'https://api.javinfo.dev/discover/random?num=3' \
-H "x-javinfo-key: jvi_your_key_here"{
"count": 3,
"results": [
{
"code": "JUY-689",
"title": "A Former Race Queen Married Woman Ai Izumi 32 Years Old Her Adult Video Debut!!",
"titleJa": "元レースクイーンの人妻 和泉藍 32歳 AVDebut!!",
"releaseDate": "2018-11-25",
"runtimeMins": 120,
"maker": "MADONNA",
"label": "Madonna",
"series": null,
"categories": ["Debut", "Digital Mosaic", "…"],
"actresses": ["Ai Izumi"],
"cover": "https://pics.dmm.co.jp/digital/video/juy00689/juy00689pl.jpg",
"rating": null,
"source": "fanza",
"url": null
},
"…"
]
}And with the uncensored filter:
curl -s 'https://api.javinfo.dev/discover/random?censored=uncensored&num=2' \
-H "x-javinfo-key: jvi_your_key_here"{
"count": 2,
"results": [
{
"code": "KING-1009",
"title": null,
"titleJa": "Computer Fantasy",
"releaseDate": "2004-08-24",
"runtimeMins": 90,
"maker": "POPMedia",
"label": null,
"series": null,
"categories": [],
"actresses": [],
"cover": "https://www.javbus.com/imgs/cover/qq6_b.jpg",
"rating": null,
"source": "javbus",
"url": "https://www.javbus.com/en/KING1009"
},
"…"
]
}Status: 200, 400, 401, 402, 429.
/discover/for-you
API: /discover/for-you
Recommendations from the account's search history. Two keys on one account share it; history is per user, not per key.
| Parameter | Type | Default | Range |
|---|---|---|---|
num | integer | 20 | 1–50 |
lookback | integer | 20 | 1–100, how many recent searches to read |
Price: $0.80 per 1,000 at num=20; $0.40 at num ≤ 10.
Only successful /movie, /query and /idols calls count. The handler reads the last lookback
rows, keeps up to five distinct queries, takes their top hits' tags, then picks recent titles
sharing them. The /discover/trending score orders the answer.
basis explains the pick for display: queries used, tags derived, and fallback. With no
history, fallback is true and the answer is the newest titles of the last 30 days.
curl -s 'https://api.javinfo.dev/discover/for-you?num=3' \
-H "x-javinfo-key: jvi_your_key_here"{
"source": "discover:for-you",
"count": 1,
"results": [
{
"code": "FC2-PPV-4973873",
"title": "FC2-PPV-4973873 [50% OFF for one week] [First time] A 35-year-old married bank employee with a cold demeanor. She's unp…",
"titleJa": "FC2-PPV-4973873 【一週間50%OFF】【初】35歳既婚の塩対応銀行員。近寄りがたいから一転、バキュームフェラで濃厚ザーメンを搾り取る。口内射精、ごっくん合計2発。",
"releaseDate": "2026-09-09",
"runtimeMins": 35,
"maker": "Fc2",
"label": null,
"series": null,
"categories": ["Wife", "Adultery", "…"],
"actresses": [],
"cover": null,
"rating": null,
"source": "missav",
"url": null
}
],
"meta": {
"sources": ["missav"],
"scanned": 1,
"latencyMs": 115
},
"basis": {
"queries": ["JQJ-002", "JUR-851", "…"],
"tags": ["featured-actress", "big-tits", "…"],
"fallback": false
}
}Status: 200, 400, 401, 402, 429.
/discover/stats
API: /discover/stats
Catalogue totals per source, with a timestamp. No parameters.
Price: $0.40 per 1,000 calls, flat.
Counts are index documents, so a title on two sources counts twice. asOf is the read time.
Public GET /stats needs no key and caches a day, but reports provider counts:
FANZA and DMM split, no total.
curl -s 'https://api.javinfo.dev/discover/stats' \
-H "x-javinfo-key: jvi_your_key_here"{
"total": 3980531,
"sources": {
"fanza": 1759469,
"javdatabase": 505464,
"javlibrary": 430950,
"javbus": 663879,
"missav": 519017,
"idols": 101752
},
"asOf": "2026-11-06T18:30:56.778Z"
}Status: 200, 401, 402, 429.
Errors
Input is validated first. A bad parameter returns 400 with code: "BAD_REQUEST",
message: "Input validation failed" and an issues array naming it. This surface never returns
422: out-of-range is 400, and so is a wrong type. range counts days, so range=7 works and
range=week is 400 with issues[].path of ["range"]. The body from
/discover/trending?num=500, above 50:
{
"defined": false,
"code": "BAD_REQUEST",
"status": 400,
"message": "Input validation failed",
"data": {
"issues": [
{
"origin": "number",
"code": "too_big",
"maximum": 50,
"inclusive": true,
"path": ["num"],
"message": "Too big: expected number to be <=50"
}
]
}
}A missing key and a rejected key differ. No key at all:
{
"defined": false,
"code": "UNAUTHORIZED",
"status": 401,
"message": "Unauthorized"
}A key the gate does not accept:
{ "error": "invalid api key" }No credit. Nothing is charged; Retry-After is an hour:
{
"defined": false,
"code": "PAYMENT_REQUIRED",
"status": 402,
"message": "insufficient balance"
}Over the per-minute cap for the account. Retry-After is in seconds:
{ "error": "rate limit exceeded" }404 is specific to /discover/similar, shown above. No other discovery endpoint returns it.
What is free
Only a fresh 200 is charged. Free:
- A cache hit:
X-Cache: HIT, no credit./discover/randomhas no cache, so it never hits. - Any
4xx. A failed request is never billed. - A degraded answer: an upstream read fails, the API serves what it has, sets
X-Degradedto the failed reads, and neither charges nor caches. Check it when a response looks thin.
X-Balance-Remaining is the credit left after the call.