javinfo

Filtering

Filter, sort and paginate /query results, plus what each provider supports.

Filtering applies to /query only (multi-result search). The single-hit /movie and /random endpoints do not take filters.


1. Quick start

Every /query request accepts four optional inputs on top of the search term q: filter, sort, page, and num (page size). Works on both GET (query string) and POST (JSON body).

KEY="jvi_..."   # your API key, sent as the x-javinfo-key header

# POST — genre + runtime filter, newest first
curl -s -X POST https://api.javinfo.dev/query \
  -H "x-javinfo-key: $KEY" -H 'content-type: application/json' \
  -d '{
        "q": "ema kisaki",
        "filter": { "genre": "Big Tits", "runtimeMin": 120 },
        "sort": "release",
        "page": 1
      }'

# GET — same thing, flattened into query params
curl -s "https://api.javinfo.dev/query?q=ema%20kisaki&filter[genre]=Big%20Tits&filter[runtimeMin]=120&sort=release" \
  -H "x-javinfo-key: $KEY"

q is optional when a filter is present. You can browse a whole category with no keyword:

# All "creampie" titles, no search term
curl -s -X POST https://api.javinfo.dev/query \
  -H "x-javinfo-key: $KEY" -H 'content-type: application/json' \
  -d '{ "filter": { "genre": "creampie" } }'

A request with neither q nor a filter is rejected with 400 ("provide a search query or at least one filter").

Cost is a flat 200 units per successful /query call regardless of filters. A request that returns no result (404) or errors is free.


2. The inputs

filter

An object. All fields are optional. Set only the ones you need.

FieldTypeMeaning
genrestringCategory / genre
actressstringActress (performer)
makerstringMaker / studio
seriesstringSeries
directorstringDirector
labelstringLabel
actorstringMale actor
censored"censored" | "uncensored"Mosaic status
runtimeMinnumber (minutes)Minimum runtime
runtimeMaxnumber (minutes)Maximum runtime
releaseAfterstring YYYY-MM-DDReleased on/after
releaseBeforestring YYYY-MM-DDReleased on/before
availability"playable" | "magnets" | "subtitle" | "single"Has stream / magnets / subtitles / is a single title

sort

One of: relevance (default), release, update, rating, views.

  • relevance: text-match relevance (default when omitted).
  • release: newest release date first.
  • update: recently added/updated first.
  • rating: highest rated first.
  • views: reserved; no provider supports it yet (always rejected).

page

1-based integer. Omitted = page 1. Page size is set by num.

num

Results per page. Integer, default 10, max 50 (higher values are clamped, not rejected; num < 1400). Best-effort per provider: javdatabase honors it only up to the site's fixed archive page size (caps the returned rows); missav caps at its search count. page offset is computed from num (page 2 with num=10 skips the first 10).

GET numeric coercion. num is coerced from the query string, but page and nested filter[...] numbers are not yet. On GET they reject with 400 "expected number, received string". Send page and numeric filters via POST JSON until that's fixed.


3. Provider capability matrix

/query searches multiple providers. Not every provider supports every filter. This is the crux of the system. Read it before building queries.

Providers (and their ids): query:fanza, query:dmm (the two DMM + FANZA storefronts), query:missav, query:javdb, query:javdatabase.

Capabilityfanza / dmmmissavjavdbjavdatabase
genre
actress
maker
series
director
label
actor
censored: censored
censored: uncensored
runtimeMin / runtimeMax
releaseAfter / releaseBefore
availability
Combine multiple filtersany comboany combo❌ noneonly genre+maker
sort: relevance
sort: release≈ (always newest)
sort: update
sort: rating
sort: views
page❌ (always page 1)

Legend: ✅ supported · ❌ not supported · ≈ accepted but behaves as the default.

Notes:

  • fanza/dmm are censored-only. An uncensored filter excludes them.
  • javdb has no per-field filters (genre/actress/etc). It only offers the coarse censored tab, availability, and rich sort. Asking javdb for any named dimension excludes it.
  • javdatabase combines only genre + maker (a genre ∩ studio archive); any other pair excludes it.
  • missav ignores page. It always returns the first page of matches.
  • missav ignores sort. Results are relevance-ranked only.

4. How provider selection works (the waterfall)

/query tries providers in order, first valid result wins:

FANZA → DMM → missav → javdb → javdatabase

What happens to a filter a provider can't satisfy depends on whether you pinned providers.

Unpinned (default): skip and advance

If you don't send providers, every registered provider is a candidate. Any provider that can't fully satisfy your filter is silently skipped, and the waterfall advances to the next one. You get a result from the first provider that can honor the whole request.

# sort=rating is javdb-only → fanza/dmm/missav/javdatabase are skipped,
# javdb answers.
curl -s -X POST https://api.javinfo.dev/query \
  -H "x-javinfo-key: $KEY" -H 'content-type: application/json' \
  -d '{ "q": "ABP", "sort": "rating" }'
# → { "source": "javdb", ... }

If no provider can satisfy the request, you get 422 with a message explaining why.

Pinned: hard error

Send providers to force a specific provider (or set). If a pinned provider can't satisfy the filter, the request fails with 422 and a message naming the reason. It is never silently dropped.

# Pin javdb, ask for a genre it can't filter → 422
curl -s -X POST https://api.javinfo.dev/query \
  -H "x-javinfo-key: $KEY" -H 'content-type: application/json' \
  -d '{ "q": "x", "providers": ["query:javdb"], "filter": { "genre": "creampie" } }'
# → 422 { "message": "does not support filter \"genre\"" }

# Pin fanza, ask for uncensored → 422
#   → { "message": "does not support uncensored content" }

providers accepts a comma list or array, with or without the query: prefix: "providers": ["fanza","missav"] or "providers": "javdb".


5. Values are passed through verbatim (important)

This is a v1 pass-through design: whatever you put in a filter value is sent to that provider's own backend as-is. There is no shared taxonomy and no fuzzy matching across providers. A value that works on one provider will often not match on another, because each source stores its metadata differently.

Consequences you must plan for:

  • Genres differ per provider.

    • fanza/dmm and javdatabase use English genre names ("Big Tits", "creampie").
    • missav genres are Japanese ("巨乳", "フィスト"). An English genre will return nothing on missav.
  • Names must match exactly. Filters are exact-match, not substring. On the DMM + FANZA index an actress is stored with her aliases baked into the name, e.g. "Ema Kisaki (HARUKI, Haruki Kato)". Filtering actress: "Ema Kisaki" returns zero rows there. You need the full stored string. (This is a known v1 rough edge.)

  • censored means different things per source. On missav there is no literal "censored/uncensored" flag; the API maps censored → mainstream mosaic titles and uncensored → everything else (Caribbeancom, 10musume, Tokyo-Hot, 1pondo, FC2, uncensored leaks, …).

  • javdatabase paths are slugified. maker: "S1 NO.1 STYLE" becomes the s1-no-1-style studio archive automatically. Pass the human-readable name; the slug is derived for you.

If a value doesn't match, you simply get fewer/no rows from that provider (and, if unpinned, the waterfall moves on). Nothing errors. An empty match is not an error.


6. Response shape

The body is the result set from the winning provider:

{
  "q": "ema kisaki",        // your query, echoed
  "source": "fanza",        // which provider answered
  "count": 10,              // page size (default 10, set by num)
  "results": [
    {
      "id": "118abp00999",          // stable id (content id or dvd id)
      "dvdId": "ABP-999",
      "title": "…",
      "cover": "https://…/…ps.jpg",
      "releaseDate": "2019-01-04",
      "extra": {                    // provider-specific, keys vary by source
        "runtimeMins": 130,
        "maker": "…",
        "categories": ["Big Tits", "…"],
        "actresses": [{ "name": "…", "image": "https://…|null" }],
        "duration": 7800,           // missav (seconds)
        "genres": ["巨乳"],          // missav
        "studio": "…", "url": "…"   // javdatabase
        // …
      }
    }
  ]
}

extra is a superset: only the keys the answering provider produces are present. Core fields (id, dvdId, title, cover, releaseDate) are consistent across all providers.

Response headers carry metadata: X-Response-Time-Ms, X-Balance-Remaining.


7. Per-provider cheat sheet

fanza / dmm (the DMM + FANZA storefronts): richest structured filtering.

  • All named dims, freely combined. English genre/name values.
  • runtimeMin/runtimeMax in minutes. sort: release. Paginated.
  • Censored catalog only. No uncensored, no availability, no release range.
# Big-tits titles over 120 min, newest first
-d '{ "filter": { "genre": "Big Tits", "runtimeMin": 120 }, "sort": "release" }'

missav: broadest filter surface, relevance-ranked only.

  • All named dims (genres are Japanese), runtime and release ranges, censored both ways.
  • No sort (relevance only), no real pagination (page 1 only), no availability.
# Uncensored titles matching "caribbean"
-d '{ "q": "caribbean", "filter": { "censored": "uncensored" } }'
# Japanese genre browse
-d '{ "q": "SSIS", "filter": { "genre": "巨乳" } }'

javdb: no field filters, but best sort + availability.

  • Only censored (both), availability, and sort (relevance/release/update/rating).
  • Paginated. No genre/actress/maker/etc.
# Playable, highest rated
-d '{ "q": "ABP", "filter": { "availability": "playable" }, "sort": "rating" }'

javdatabase: archive browsing by one dimension (or genre ∩ maker).

  • genre, actress, maker, series, director; only genre+maker combine. Censored + uncensored. English values, auto-slugified. Paginated.
  • No runtime/release range, no label/actor, no real sort (newest-first).
# Creampie titles from S1
-d '{ "filter": { "genre": "creampie", "maker": "S1 NO.1 STYLE" } }'

8. What is NOT possible (v1)

  • Cross-provider value normalization. No unified genre/actress vocabulary; you must speak each provider's dialect (English vs Japanese, exact strings).
  • sort: views is reserved; no provider implements it.
  • Multi-value per dimension. One value per field (no genre: ["a","b"]).
  • Ranges outside their provider. Runtime range is fanza/dmm/missav only; release range is missav only.
  • availability anywhere but javdb.
  • Combining arbitrary filters on javdb (none) or javdatabase (genre+maker only).
  • Pagination / sort on missav.
  • Filtering /movie or /random.

When a combination isn't possible: pinned → 422 with a reason; unpinned → that provider is skipped and the next one is tried.

Next

  • Browse the full API reference. The /query operation lists every filter param with a live playground.
  • See Errors for the 400 and 422 cases.

On this page