# Japan Used Camera Sold Price vs Dealer Ask — Lens Resale Value (`jpmarketdata/japan-camera-gear-sold-comps`) Actor

Sold comps for any camera or lens model in Japan: what it actually sold for at auction next to the Japanese dealer ask per condition rank (未使用/A/AB+/AB/B), and the spread between them — the used-gear export and proxy-buying decision in one call. From $0.02. 中古カメラの業者ask×落札実売の差を1コールで。

- **URL**: https://apify.com/jpmarketdata/japan-camera-gear-sold-comps.md
- **Developed by:** [h ichi](https://apify.com/jpmarketdata) (community)
- **Categories:** E-commerce, Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $20.00 / 1,000 model sold comps

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Japan Used Camera Sold Price vs Dealer Ask — Lens Resale Value

**What did this camera actually sell for in Japan, what is a Japanese dealer asking for it, and how big is the gap?** One call per model returns all three.

| Side | Source | What you get | Basis |
|---|---|---|---|
| **Dealer ask** | [Fujiya Camera](https://www.fujiya-camera.co.jp/) (フジヤカメラ, Nakano) | Shelf price **per condition rank** (未使用 / A / AB+ / AB / AB- / B / 現状品 / コレクション), with the exact population count and median behind each | `ask` · seller `dealer` |
| **Sold** | [Yahoo! Auctions Japan](https://auctions.yahoo.co.jp/) (ヤフオク) | Closed auctions with at least one bid = **realized sale prices** | `sold` · seller `mixed` |
| **Sold** | [Mercari Japan](https://jp.mercari.com/) (メルカリ) | Sold-out listings, as a second realized reference | `sold` · seller `consumer` |
| Consumer ask | [PayPay Flea Market](https://paypayfleamarket.yahoo.co.jp/) (PayPayフリマ) | Live listings (optional) | `ask` · seller `consumer` |

The headline field is **`spread`**: the dealer's median ask minus the realized sold median, overall **and rank by rank**. That is the used-camera export trade's buy decision expressed as one number.

No model-name matching is involved — a model number is already the search key on all four sites, so nothing is being guessed on your behalf.

### Pricing — from $0.02 per model, no subscription

| Event | Price | When |
|---|---|---|
| `model-analyzed` | **$0.02** | Per model, whatever the number of sources |
| `listing-scraped` | **$0.002** | Only if you enable **Include individual listings** |

A default run (1 model, 3 sources, summary only) costs **$0.02** and took **29 seconds** measured 2026-08-07. Apify's free plan includes **$5/month of credit ≈ 250 default runs**. No subscription, no minimum.

**A model is only charged when the spread could actually be computed** — i.e. when a dealer ask median *and* a realized sold median both came back. Measured 2026-08-07: Fujiya had **zero** used `Nikon D850` bodies in stock, so that record shipped with three sold/ask medians in it and cost **$0.00**, because the thing you are buying is the gap, not the lookup. (If you deliberately select one side only — e.g. Fujiya alone for the rank ladder — the record is billed as soon as that side delivers.)

### Why `priceBasis` and `sellerType` are on every block

A closed Yahoo! auction is a **realized transaction**. A dealer's shelf price is an **aspiration nobody has agreed to yet**. And a graded, inspected, shop-warrantied dealer ask is not the same quantity as a stranger's Mercari asking price either. Subtract the wrong pair and your "margin" is fiction. So:

- every source block carries **`priceBasis`** (`ask` / `sold`) and a plain-English **`priceBasisLabel`**;
- every source block carries **`sellerType`** (`dealer` / `consumer` / `mixed`) — this is what stops `spread` from quietly becoming "Fujiya vs some guy";
- **`spread` only ever pairs a dealer ask with a realized sale.** A consumer ask is never promoted into it; those comparisons still ship, in `comparison.pairs`, tagged `ask_vs_sold` / `sold_vs_sold` / `ask_vs_ask`;
- **`statsBasis`** says how each distribution was *measured* — `exact` (the whole filtered result set fit on one page), `population_quantiles` (read off the site's own price-sorted paging), `sample` (the first pages only). It is deliberately a different word from `priceBasis`, which is an *economic* label.

### The rank ladder is the point

Japanese used-camera dealers grade every body and lens on a published ladder, and `secondhand_state` is a **filter** on the shop's search — so for every rank the Actor gets the **exact population count** and, by jumping to the page holding the median of a price-ascending sort, the **exact population median**. Not a first-page average.

`spread.byRank` then quotes each rank against the same realized sold median, which is what the trade actually acts on: an AB body at ¥236,500 against a ¥192,181 auction median is a different business from an AB+ at ¥370,150.

### Input

| Field | Example | Notes |
|---|---|---|
| `models` | `["Canon EOS R6"]` | Model name or number. Latin script works everywhere; Japanese also works. Each model costs $0.02 |
| `sources` | `["fujiya","yahoo_auction","mercari"]` | The spread needs Fujiya plus one sold source. Price per model does not change |
| `conditionRanks` | `[]` | Empty = the whole ladder. Codes: `1000`=未使用, `1001`=A, `1002`=AB+, `1003`=AB, `1004`=AB-, `1005`=B, `1006`=現状品, `1007`=コレクション. Narrow it to speed up multi-model runs |
| `mercariStatus` | `"sold_out"` | `sold_out` (a second sold comp) / `on_sale` (consumer ask) / `both` (two separate blocks) |
| `priceMinJpy` / `priceMaxJpy` | `80000` | Optional window on the **auction / flea-market** side. The de-junking tool — see below |
| `includeNewReference` | `false` | Also price the dealer's new/outlet stock, for `usedVsNewDiscountPct` |
| `maxListingsPerSource` | `60` | 30–300 listings sampled per source. Does **not** affect the dealer rank counts or rank medians |
| `includeIndividualListings` | `false` | Enable to also get every sampled listing, +$0.002 each |
| `convertToUsd` | `true` | Adds USD next to JPY (one FX lookup per run) |

### Output example (`type: "model_sold_comps"`, abridged — measured 2026-08-07)

```json
{
  "type": "model_sold_comps",
  "model": "Canon EOS R6",
  "spread": {
    "comparable": true,
    "basis": "dealer_ask_vs_sold",
    "askSource": "fujiya_dealer_ask",  "askSellerType": "dealer",
    "askMedianJpy": 238150, "askListingsFound": 28,
    "soldSource": "yahoo_auction_sold",
    "soldMedianJpy": 192181, "soldListingsFound": 619, "soldPricedListings": 34,
    "spreadJpy": 45969, "spreadPct": 23.9,
    "soldP25ToAskMedianRatio": 0.606, "mixWarning": false,
    "byRank": [
      {"rank": "A",   "dealerListings":  2, "askMedianJpy": 372900, "soldMedianJpy": 192181, "spreadJpy": 180719, "spreadPct": 94.0},
      {"rank": "AB+", "dealerListings": 11, "askMedianJpy": 370150, "soldMedianJpy": 192181, "spreadJpy": 177969, "spreadPct": 92.6},
      {"rank": "AB",  "dealerListings": 12, "askMedianJpy": 236500, "soldMedianJpy": 192181, "spreadJpy":  44319, "spreadPct": 23.1},
      {"rank": "AB-", "dealerListings":  3, "askMedianJpy": 231550, "soldMedianJpy": 192181, "spreadJpy":  39369, "spreadPct": 20.5}
    ],
    "askMedianUsd": 1505.35, "soldMedianUsd": 1214.78, "spreadUsd": 290.57,
    "note": "spreadJpy = dealer ask median - realized sold median. … It is not profit."
  },
  "sources": {
    "fujiya_dealer_ask": {
      "priceBasis": "ask", "sellerType": "dealer", "statsBasis": "exact",
      "totalListingsFound": 28, "sampledListings": 28, "pricedListings": 28,
      "priceJpy": {"min": 168850, "p25": 236500, "median": 238150, "p75": 370150, "max": 372900, "average": 286354},
      "signals": {
        "rankStats": [{"rank": "AB", "rankLabel": "AB", "count": 12, "medianJpy": 236500, "medianBasis": "exact"}, "…"],
        "rankPremium": {"baseRank": "AB-", "baseMedianJpy": 231550, "premiumPct": {"A": 61.0, "AB+": 59.9, "AB": 2.1}},
        "modelMixSampled": [["EOS R6 Mark II ボディー", 16], ["EOS R6 Mark III ボディー", 11], ["EOS R6 ボディー", 1]],
        "distinctModelsSampled": 3,
        "brandTop": [["Canon", 28]]
      }
    },
    "yahoo_auction_sold": {
      "priceBasis": "sold", "sellerType": "mixed", "statsBasis": "sample",
      "totalListingsFound": 619, "pricedListings": 34, "priceFilterApplied": true,
      "priceJpy": {"min": 128000, "p25": 144325, "median": 192181, "p75": 227328, "max": 425000, "average": 201663},
      "signals": {"soldListings": 34, "unsoldListings": 0, "sellThroughRatioSampled": 1.0,
                  "bidCount": {"min": 1, "median": 3, "max": 104}}
    },
    "mercari_sold": {
      "priceBasis": "sold", "sellerType": "consumer", "totalListingsFound": 1650,
      "priceJpy": {"median": 206000}, "signals": {"medianDaysToSell": 6}
    }
  },
  "comparison": {
    "medianJpy": {"fujiya_dealer_ask": 238150, "yahoo_auction_sold": 192181, "mercari_sold": 206000},
    "comparable": true, "mixedBasis": true,
    "pairs": [
      {"from": "yahoo_auction_sold", "to": "fujiya_dealer_ask", "basis": "ask_vs_sold", "sameBasis": false,
       "sellerTypes": {"yahoo_auction_sold": "mixed", "fujiya_dealer_ask": "dealer"}, "diffJpy": 45969, "diffPct": 23.9},
      {"from": "yahoo_auction_sold", "to": "mercari_sold", "basis": "sold_vs_sold", "sameBasis": true,
       "diffJpy": 13819, "diffPct": 7.2}
    ]
  },
  "priceFilterJpy": {"min": 80000, "max": null,
                     "appliedTo": ["yahoo_auction_sold", "mercari_sold"],
                     "notAppliedTo": ["fujiya_dealer_ask"]},
  "sourcesWithData": ["fujiya", "mercari", "yahoo_auction"],
  "exchangeRateJpyUsd": 0.006321,
  "checkedAt": "2026-08-07T07:03:45+00:00"
}
```

With `includeIndividualListings: true` you additionally get one record per listing, each tagged with `source`, `priceBasis`, `sellerType` and — on the dealer side — `conditionRank`.

### Use cases

- **Sourcing for export** — buy at auction, sell at the dealer band. `spread.byRank` tells you which grade the gap actually lives in
- **Pricing your own used stock** — quote against the same rank ladder Japanese dealers publish
- **Insurance / estate valuation** — a realized sold median plus a dealer ask, with the sample sizes attached
- **Deciding whether to sell or trade in** — `sellThroughRatioSampled` (Yahoo) and `medianDaysToSell` (Mercari) are the liquidity, `spread` is the money you leave on the table by trading in
- **Watching a model over time** — schedule it and track `spreadPct` per rank

### Notes & limits — read these before trusting a number

- **A model name also matches its accessories.** Measured 2026-08-07: `Canon EOS R6` with no price floor returned a Yahoo sold p25 of ¥2,300 (straps, caps, batteries) against a ¥238,150 dealer ask, and a "71.9%" spread that was pure product mix. The Actor computes **`spread.soldP25ToAskMedianRatio`** and raises **`spread.mixWarning: true`** when it drops below 0.25. Fix it with `priceMinJpy` — the same model with a ¥80,000 floor gives the honest 23.9% above
- **The dealer's search is looser than a model number.** Measured 2026-08-07: `keyword=Nikon Z6II` returns 18 used hits of which **14 are Z6III bodies and 4 are Z6II**, and `keyword=Z6II` returns exactly the same set. No price statistic can reveal that, so **`signals.modelMixSampled`** ships the title histogram behind the ask median (in the example above: 16 Mark II, 11 Mark III, 1 original R6 — which is why the A / AB+ ranks sit near ¥370,000 and AB / AB- near ¥235,000). **Always read it before quoting `spread`**
- **`priceMinJpy` / `priceMaxJpy` are not applied to the dealer block**, and the record says so in `priceFilterJpy.notAppliedTo`. Those counts and rank medians are read off the shop's own filters and were never enumerated here — a client-side window cannot honestly claim to have touched them
- **The dealer may simply not stock the model.** Then `spread.comparable` is `false` with a `note`, the sold medians are still returned, and the model is **free**
- **`totalListingsFound` is what each site reports** and is never rewritten by the price window. Each site counts differently (Mercari caps its hit count)
- Check **`pricedListings`** before trusting a median: a tight window can leave a source with very few listings
- Yahoo's sold filter is `bidCount >= 1`; ended auctions with no bid are sampled but excluded from the price statistics (`signals.unsoldListings`)
- Mercari's `medianDaysToSell` uses `updated - created`, which also moves on price edits, so it skews low — a liquidity signal, not an exact time-to-sale
- **PayPay Flea Market can never return sold prices** — they are not server-rendered. Nothing here pretends otherwise
- **A source that fails does not fail the run**: it comes back as `available: false` with an `error` and the rest are still compared. Only a model where *every* source failed fails the run
- Large multi-model runs may hit the internal time budget; affected blocks carry `truncatedForTimeLimit`. Run fewer models per call, or narrow `conditionRanks`
- Read-only, no login, no browser, HTTP+JSON only, 256 MB. Requests are throttled to one per 1.5 s, and Yahoo! Auctions and PayPay Flea Market are queried **sequentially** because they share one backend
- No personal data is collected — sellers are excluded from every record

***

### 日本語ガイド

**カメラ・レンズの型番1件につき、「日本の業者が今いくらで売っているか(状態ランク別)」と「実際にいくらで落札されたか」、そしてその**差(スプレッド)**を1レコードで返す Actor です。**

- **中核は `spread`**: フジヤカメラの中古 ask 中央値 − ヤフオク落札(入札1件以上)の sold 中央値。**状態ランク別(`byRank`)にも出します**。実測(2026-08-07)では Canon EOS R6 が ask ¥238,150 / sold ¥192,181 = **+23.9%**、ランク別では AB +23.1% / AB+ +92.6% でした
- **基準タグは2種類**: `priceBasis`(`ask` / `sold`)に加えて **`sellerType`(`dealer` / `consumer` / `mixed`)**。保証・検品付きの業者 ask と、メルカリの個人出品 ask は別物なので、**`spread` は「業者 ask × 実売 sold」の組み合わせしか作りません**(個人 ask は `comparison.pairs` に basis タグ付きで残します)
- **ランク別の件数と中央値は正確値です**: フジヤの `secondhand_state` は絞り込みフィルタなので、各ランクの母集団件数と(価格昇順ページの中央位置を直接取ることで)母集団中央値が取れます。1ページ目の平均ではありません
- **料金**: 型番1件 **$0.02**(`model-analyzed`)、個別明細は **$0.002/件**(`listing-scraped`、既定 OFF)。**スプレッドが計算できなかった型番は課金されません** — 実測で `Nikon D850` はフジヤに中古在庫ゼロだったため $0.00 でした。無料プランの月$5クレジットで既定実行 約250回。サブスク不要
- **必ず読んでほしい注意2点**: ①**型番はアクセサリにも一致します**(EOS R6 は無フィルタだとヤフオク側 p25 が ¥2,300 = ストラップ等になり、スプレッドが 71.9% と嘘になります)。`spread.mixWarning` が立つので `priceMinJpy` で下限を切ってください。②**業者側の検索は型番より緩い**(実測: `Nikon Z6II` の18件中14件が Z6III)。`signals.modelMixSampled` に商品名の内訳を必ず出しているので、ask 中央値を引用する前に見てください
- **その他**: `priceMinJpy` / `priceMaxJpy` は業者ブロックには適用しません(母集団の正確値を客観的に壊さないため。適用範囲は `priceFilterJpy` に明記)。1ソースが落ちても `available: false` として残り、他ソースの比較は続行します。ブラウザ不使用・ログイン不要・1.5秒に1リクエスト、ヤフオクと PayPayフリマは同一基盤のため逐次取得。個人情報は取得しません

# Actor input Schema

## `models` (type: `array`):

One or more model names — the model number is the search key on every site, so no name matching is involved (Nikon Z6, Canon RF 24-70mm F2.8, SIGMA 35mm F1.4 DG DN, Leica M6). Latin script works everywhere; Japanese also works. Each model costs $0.02.

## `sources` (type: `array`):

Which side of the market to measure. Fujiya Camera is the DEALER ASK (graded by condition rank), Yahoo! Auctions is the realized SOLD price, Mercari can be either, PayPay Flea Market is a consumer ASK only. The spread needs at least Fujiya plus one sold source. The price per model does not change with the number of sources.

## `conditionRanks` (type: `array`):

Which of the dealer's condition ranks to price. Each rank costs 1-2 extra requests, so narrowing this speeds up multi-model runs. Codes: 1000=未使用/未開封品 (unused), 1001=A, 1002=AB+, 1003=AB, 1004=AB-, 1005=B, 1006=現状品 (as-is), 1007=コレクション (collection). Leave empty for the whole ladder.

## `mercariStatus` (type: `string`):

What Mercari should contribute. 'Sold out' (default) is a second realized sold reference next to Yahoo! Auctions. 'On sale' is a consumer asking price. 'Both' returns them as two separate blocks so each keeps a single, honest price basis.

## `includeNewReference` (type: `boolean`):

Also measure the dealer's new/outlet price for the same model, so the used discount against new (usedVsNewDiscountPct) can be reported. Costs 1-2 extra requests per model.

## `priceMinJpy` (type: `integer`):

Drop auction/flea-market listings priced below this before computing the sold and consumer-ask statistics. This is the de-junking tool: a model name like 'Canon EOS R6' also matches straps, caps and batteries, which drags the sold median far below the body itself — watch spread.mixWarning. Not applied to the dealer block: those counts and rank medians come from the shop's own filters and were never enumerated here.

## `priceMaxJpy` (type: `integer`):

Drop auction/flea-market listings priced above this before computing the sold and consumer-ask statistics. Useful to cut bundles, full kits and lot sales out of a model.

## `maxListingsPerSource` (type: `integer`):

How many listings to sample per source before computing the statistics. The dealer rank counts and rank medians are read from the site's own filtered result sets and are NOT affected by this. Yahoo returns 50 per request, Mercari 120, PayPay 100, Fujiya 50, and requests are throttled to one per 1.5 s.

## `includeIndividualListings` (type: `boolean`):

Off by default: a run costs a flat $0.02 per model, whatever the number of sources. Enable to also get every sampled listing from every source (title, price, condition rank, URL, price basis) at +$0.002 per listing.

## `convertToUsd` (type: `boolean`):

Adds USD statistics next to JPY using the current exchange rate (open.er-api.com, looked up once per run).

## Actor input object example

```json
{
  "models": [
    "Canon EOS R6"
  ],
  "sources": [
    "fujiya",
    "yahoo_auction",
    "mercari"
  ],
  "conditionRanks": [],
  "mercariStatus": "sold_out",
  "includeNewReference": false,
  "priceMinJpy": 80000,
  "maxListingsPerSource": 60,
  "includeIndividualListings": false,
  "convertToUsd": true
}
```

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "models": [
        "Canon EOS R6"
    ],
    "sources": [
        "fujiya",
        "yahoo_auction",
        "mercari"
    ],
    "priceMinJpy": 80000
};

// Run the Actor and wait for it to finish
const run = await client.actor("jpmarketdata/japan-camera-gear-sold-comps").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "models": ["Canon EOS R6"],
    "sources": [
        "fujiya",
        "yahoo_auction",
        "mercari",
    ],
    "priceMinJpy": 80000,
}

# Run the Actor and wait for it to finish
run = client.actor("jpmarketdata/japan-camera-gear-sold-comps").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "models": [
    "Canon EOS R6"
  ],
  "sources": [
    "fujiya",
    "yahoo_auction",
    "mercari"
  ],
  "priceMinJpy": 80000
}' |
apify call jpmarketdata/japan-camera-gear-sold-comps --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,jpmarketdata/japan-camera-gear-sold-comps"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/8xWbMzJuUG87cC1pE/builds/O7UYYbjnMMSqKRJQr/openapi.json
