# Japan Used Model Train Market — KATO, TOMIX Search & Alerts (`keiya_dev/japan-used-model-train-market`) Actor

Search, benchmark and monitor used Japanese model trains (KATO, TOMIX, MicroAce, GreenMax) from Hobbyland Pochi and Hard Off: maker product codes, N / HO scale, set / add-on / single, motor flag, case, normalized grade, JPY/USD. Medians, price history, NEW / PRICE_DROP alerts.

- **URL**: https://apify.com/keiya_dev/japan-used-model-train-market.md
- **Developed by:** [Keiya](https://apify.com/keiya_dev) (community)
- **Categories:** E-commerce, Other
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.40 / 1,000 listings

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Japan Used Model Train Market: KATO, TOMIX, MicroAce — Search, Stats, History & Alerts

### Quick start

1. Click **Try for free** / open the Actor in Apify Console.
2. Keep the prefilled input (`{"mode": "search", "sources": ["pochi", "offmall"], "keywords": ["KATO"], "maxItems": 10}`) or type your own: a maker ("TOMIX", "MicroAce"), a product code ("10-1332", "98313", "A-6590") or a train ("新幹線", "0系", "EF58", "Sunrise" → try "サンライズ").
3. Press **Start**. Listings appear in the Output tab in under a minute, with **the maker's product code, N / HO scale, set / add-on / single car, whether a powered car is included, case & manual, a normalized condition grade and the price in JPY and USD**.

**Example output** — 3 real rows from the prefilled run above (run on 2026-11-05; prices and stock change daily):

```json
[
  {
    "source": "offmall",
    "sourceName": "Hard Off (Off Mall)",
    "sourceItemId": "6676195",
    "url": "https://netmall.hardoff.co.jp/product/6676195/",
    "title": "10-426/10-427 (189系(あずさニューカラー)基本・増結11両セット)",
    "brand": "KATO",
    "brandJa": "カトー",
    "conditionGrade": "VERY_GOOD",
    "conditionGradeRaw": "B",
    "priceJpy": 11000,
    "inStock": true,
    "category": "used",
    "scrapedAt": "2026-11-05T12:49:29.502Z",
    "brandRaw": "KATO",
    "productCode": "10-426",
    "productCodeSource": "title",
    "ref": "10-426",
    "model": "kato 10-426",
    "scale": "N",
    "scaleRatio": null,
    "setType": "add-on",
    "motorized": null,
    "accessories": null,
    "lotYear": null,
    "shop": "ホビーオフ秦野店",
    "priceUsd": 69.51,
    "fxJpyPerUsd": 158.25
  },
  {
    "source": "pochi",
    "sourceName": "Hobbyland Pochi",
    "sourceItemId": "601688",
    "url": "https://hobbyland-pochi.net/products/detail.php?product_id=15636&product_class_id=601688",
    "title": "客車 セットバラ 10-1873 寝台特急「さくら」佐世保編成バラ マヤ20-2(1両のみ)",
    "brand": "KATO",
    "brandJa": "カトー",
    "brandRaw": "KATO(カトー)",
    "productCode": "10-1873",
    "productCodeSource": "title",
    "ref": "10-1873",
    "shopProductId": "15636",
    "model": "kato 10-1873",
    "scale": "N",
    "scaleRatio": null,
    "setType": "set",
    "motorized": null,
    "accessories": {
      "case": null,
      "manual": null,
      "sleeve": null
    },
    "lotYear": null,
    "conditionGrade": "MINT",
    "conditionGradeRaw": "A",
    "priceJpy": 4400,
    "inStock": true,
    "category": "used",
    "scrapedAt": "2026-11-05T12:49:30.037Z",
    "priceUsd": 27.8,
    "fxJpyPerUsd": 158.25
  },
  {
    "source": "pochi",
    "sourceName": "Hobbyland Pochi",
    "sourceItemId": "601697",
    "url": "https://hobbyland-pochi.net/products/detail.php?product_id=15637&product_class_id=601697",
    "title": "電車 セットバラ 10-1182 飯田線荷物電車バラ クモニ83-100(1両のみ)動力なし",
    "brand": "KATO",
    "brandJa": "カトー",
    "brandRaw": "KATO(カトー)",
    "productCode": "10-1182",
    "productCodeSource": "title",
    "ref": "10-1182",
    "shopProductId": "15637",
    "model": "kato 10-1182",
    "scale": "N",
    "scaleRatio": null,
    "setType": "set",
    "motorized": false,
    "accessories": {
      "case": null,
      "manual": null,
      "sleeve": null
    },
    "lotYear": null,
    "conditionGrade": "VERY_GOOD",
    "conditionGradeRaw": "B",
    "priceJpy": 4400,
    "inStock": true,
    "category": "used",
    "scrapedAt": "2026-11-05T12:49:30.041Z",
    "priceUsd": 27.8,
    "fxJpyPerUsd": 158.25
  }
]
```

Japan is where Japanese model trains are cheapest and most plentiful: KATO and TOMIX sets that sold out years ago, MicroAce private-railway EMUs, GreenMax kits, Tenshodo brass, Japan-only limited editions. But the listings are in Japanese, the product code is hidden in an image file name or on the product page, and "does it have the motor car?" is a word in brackets. This Actor turns Japan's large used-train shops into one clean, English dataset you can pipe into Google Sheets, n8n, Slack, Discord or your own pricing model.

### Who uses it

| You are… | You use… |
|---|---|
| **An eBay seller** sourcing Japanese N gauge | `search` with a grade floor and a max price; `stats` for the Japanese median per product code before you list |
| **A JNR / Shinkansen collector** | `monitor` on "国鉄", "新幹線", "0系", "EF58", "キハ" with alerts to Discord; filter on `motorized: true` and `setType: "set"` |
| **A private-railway (私鉄) collector** | `monitor` on a railway ("小田急", "近鉄", "阪急", "京急") or a maker that covers them (MicroAce, GreenMax) |
| **Hunting Japan-only limited editions** | `monitor` on the product code or name; `history` to see how often it turns up and at what price |

### Shops

| Shop | Id | Listings | What you get |
|---|---|---|---|
| **Hobbyland Pochi** (ホビーランドぽち, Osaka-based chain specialised in used model trains) | `pochi` | ~12,000 used N and HO trains, Tetsudou Collection, B-Train Shorty (about 1,100 of them shown as sold) | maker, scale, title, grade A / A´ / B / C / D / ジャンク / 加工品, price, **product code from the photo's file name** when the shop names it after the code (most KATO / TOMIX / GreenMax items). From the product page: the **maker code (メーカー品番), JAN**, and case / sleeve / lot facts from the condition note |
| **Hard Off Off Mall** (ハードオフ オフモール, Hard Off / Hobby Off stores nationwide) | `offmall` | ~9,600 model trains on sale | maker, code field (usually the maker's product code), name, grade N / S / A / B / C / D / ジャンク, price. From the product page: **motor (モーター ○ / -)**, accessories, case and box condition, store |

**Shops not included**

| Shop | Why |
|---|---|
| Popondetta (ポポンデッタ) | **blocked**: Cloudflare answers HTTP 403 to every request from Apify's servers (its "中古品速報" list also needs a session token). About 2,100 used trains were counted on its store lists on 2026-11-05 |
| Surugaya (駿河屋) | **blocked**: its list pages (`/search/`) are disallowed by robots.txt |
| Mandarake, Joshin | **blocked**: plain requests are redirected / refused (403) |

Want a shop added? Open an issue on the Actor page.

### What you can do

| Mode | What it does |
|---|---|
| **search** | Listings matching keywords / makers / grades / price. Keywords match maker + title in English or Japanese, **and product codes**. For each listing in the result, the product page is read once to add the **maker code, motor and case** when the listing itself doesn't say. |
| **stats** | Per-model summary of in-stock listings: count, **min / median / max** in JPY and USD, broken down by shop and grade, plus the cheapest listing. Models are grouped by **maker + product code**, so the same set groups across shops. |
| **monitor** | Run on a schedule. It keeps a snapshot and emits **only what changed**: `NEW`, `PRICE_DROP`, `PRICE_UP`, `SOLD_OUT`. An optional webhook goes to Slack / Discord / n8n / Make / Zapier. |
| **history** | Daily min / median / count per model, by shop and grade, from stored daily snapshots. There is no crawling, so it returns in seconds. Needs `keywords`, `brands` or `models`. |
| **deals** | In-stock listings at least `dealThresholdPct` % (default 15) **under the median of the same model in the same grade or better**, best `dealScore` first. Statistics only. See [Deals](#deals). |

### Train fields

| Field | Values | Where it comes from |
|---|---|---|
| `brand` | KATO, TOMIX, MicroAce, GreenMax, Tenshodo, Endo, TOMYTEC (Tetsudou Collection), Popondetta, MODEMO, Zoukeimura, Katsumi… (`brandJa`: カトー, トミックス…) | the shop's maker label, Japanese → English |
| `productCode` | KATO `10-1332`, `1-701`, `5183`, `3067-3` · TOMIX `98313`, `9472`, `HO-9105` · MicroAce `A-6590` · GreenMax `31978` · bundles `10-2047+10-2048` | Off Mall's code field or the title (`productCodeSource: "title"`); Pochi's photo file name (`"image"`, 14 of 14 sampled matched the product page); Pochi's メーカー品番 (`"product-page"`, search / monitor) |
| `scale` | `N`, `HO`, `Z`, `other`, plus `scaleRatio` ("1/150", "1/80") | printed scale, or implied by the code (KATO 1-xxx / 3-xxx = HO, 10-xxxx = N; TOMIX HO-xxxx = HO) |
| `setType` | `set` (基本セット, N両セット, 基本+増結), `add-on` (増結セット), `single` (one car or locomotive), `null` (track, parts, unknown) | title words |
| `motorized` | `true` = includes a powered car, `false` = trailer cars only, `null` = not stated | "(M)" / "動力付き" / a locomotive → true; "(T)" / "動力無し" / display models (Tetsudou Collection) → false; Off Mall product page モーター ○ / - |
| `accessories` | `{ case, manual, sleeve }`, each `true` / `false` / `null` | only what the shop states: "インサート紙なし" → sleeve false, "クリアケース傷み" → case true (worn but present) |
| `lotYear` | 2012 | "2012年ロット": KATO and TOMIX re-run the same code; lots are priced apart |

### Condition grades

`NEW` > `MINT` > `EXCELLENT` > `VERY_GOOD` > `GOOD` > `FAIR` > `JUNK`, plus `CUSTOM` (modified, repainted, kit-built). The shop's own label is always kept in `conditionGradeRaw`. Both maps follow the shops' published legends:

| Shop | Raw → normalized |
|---|---|
| Hobbyland Pochi | A (car and case mint, test-run only, extra parts unused) → MINT · A´ (mint car, minor factory dust or an unfixed maker error) → EXCELLENT · B (some extra parts fitted, all originals kept) → VERY_GOOD · C (parts fitted / missing, wheel wear) → GOOD · D (faults, visible marks) → FAIR · ジャンク (as is) → JUNK · 加工品 (custom) → CUSTOM |
| Off Mall | N 新品・未開封 → NEW · S 新品同様・廃盤 → MINT · A 使用回数の少ない美品 → EXCELLENT · B 日常使用・傷汚少 → VERY_GOOD · C 使用感・傷汚れ多 → GOOD · D ダメージ多 → FAIR · ジャンク → JUNK |

### Deals

`deals` mode reads the same listings as `stats`, then compares each in-stock listing with the **other listings of the same model** (same `model` key) **in the same grade or better**, and returns only those at least `dealThresholdPct` % under that median:

```json
{ "mode": "deals", "keywords": ["KATO"], "dealThresholdPct": 15, "maxItems": 0 }
```

Each deal is a normal listing plus:

| Field | Meaning |
|---|---|
| `medianJpy` (`medianUsd`) | median price of the listings it was compared with |
| `comparisonCount` | how many listings that median is based on |
| `discountPct` | how far under the median, in % |
| `dealScore` | 0–100: the discount (40 % off = full marks) weighted by `comparisonCount` (1 → 60 %, 5 or more → 100 %). **Capped at 50 when `comparisonCount` is 2 or less** (low confidence) |

- Models with nothing to compare against are not returned. Grades sold as is (`JUNK` and `CUSTOM`) are neither returned nor used as comparisons.
- The market is the listings this run read: use `maxItems: 0` (whole shops) or a keyword that covers the whole model, so every listing of "kato 10-1332" is compared.
- No LLM is involved; it is the same arithmetic as `stats`.

**Deal alerts.** In `monitor` mode, `"dealsOnly": true` outputs and sends only the `NEW` / `PRICE_DROP` events that are deals against the listings that monitor tracks, with the same four fields. They are charged as normal monitor events.

**Daily deal digest.** In `deals` mode, set `alertWebhookUrl` (Slack, Discord or any URL) and the best `dealsWebhookTop` deals (default 10, highest `dealScore` first, ties broken by the deeper discount) are POSTed once per run, one line each: score, discount, grade, title, price vs median, link. Schedule it every morning (e.g. `0 7 * * *`, `maxItems: 0`) for a short list of the day's best-priced listings; the dataset still holds every deal.

**English summaries (optional, your own LLM key).** `"summarize": true` with `llmApiKey` (stored encrypted) adds `summaryEn` to every listing in `search` and `deals` mode, e.g. "KATO 10-1332 Sunrise Express 7-car set, Excellent, 24% under Japan median". `llmProvider` is `anthropic` (default, Claude Haiku `claude-haiku-5-5`) or `openai` (`gpt-5-mini`); `llmModel` overrides the model. Listings are sent 25 per request, so the cost grows with the number of listings: with Claude Haiku, **100 listings ≈ $0.003, well under $0.01**. Your provider bills your key; the Actor charges nothing extra. Without a key the option is skipped with a warning, and an LLM error never fails the run (the listings are returned without `summaryEn`).

### Input

```json
{
  "mode": "search",
  "sources": ["pochi", "offmall"],
  "keywords": ["新幹線", "0系"],
  "brands": ["KATO", "TOMIX"],
  "grades": ["MINT", "EXCELLENT", "VERY_GOOD"],
  "maxPriceJpy": 30000,
  "maxItems": 30
}
```

Monitor example (schedule it hourly):

```json
{
  "mode": "monitor",
  "sources": ["pochi", "offmall"],
  "keywords": ["KATO", "TOMIX"],
  "alertWebhookUrl": "https://discord.com/api/webhooks/XXX/YYY",
  "alertEvents": ["NEW", "PRICE_DROP"]
}
```

The first monitor run only builds the snapshot and emits nothing. Each monitor keeps one snapshot per shop, keyed by its filters. Give each schedule a distinct `monitorId` if several use the same filters.

**Request budget:**

- Every request is one listing page (Pochi 50 trains, Off Mall 30), read newest-first. Requests to Pochi are spaced at least 1.5 s apart.
- An hourly light monitor is normally **2 requests**, plus one product page per new listing.
- `"fullScan": true` reads everything: **Pochi ≈ 250 pages (~7 min), Off Mall ≈ 320 pages (~6 min)**.

### Price history since 2026-11-05

The Actor's own scheduled full scans store the complete inventory of each shop: **Pochi every day**, **Off Mall once a week, on Sundays**. `history` mode reads those snapshots:

```json
{ "mode": "history", "models": ["kato 10-1332", "tomix 98313"], "days": 90 }
```

Each row is one model × day: `count`, `minJpy`, `medianJpy`, `maxJpy`, plus `byShop`, `byGrade` and `byShopGrade`.

- **History is still being collected.** Treat the first 30 days as indicative only.
- Off Mall numbers appear on Sunday rows only, so compare them week to week.
- History uses the codes found on listing pages (title, Off Mall code field, Pochi photo names). Pochi items whose photo isn't named after the code group by maker + cleaned title.

### Output

```json
{
  "source": "pochi",
  "sourceName": "Hobbyland Pochi",
  "sourceItemId": "601669",
  "url": "https://hobbyland-pochi.net/products/detail.php?product_id=3570&product_class_id=601669",
  "title": "オロネ25 2012年ロット",
  "brand": "KATO",
  "brandJa": "カトー",
  "productCode": "5183",
  "productCodeSource": "product-page",
  "model": "kato 5183",
  "jan": "4949727053882",
  "scale": "N",
  "scaleRatio": "1/150",
  "setType": "single",
  "motorized": null,
  "accessories": { "case": true, "manual": null, "sleeve": null },
  "lotYear": 2012,
  "conditionGrade": "EXCELLENT",
  "conditionGradeRaw": "A´",
  "priceJpy": 3300,
  "priceUsd": 20.85,
  "fxJpyPerUsd": 158.25,
  "inStock": true,
  "category": "used",
  "scrapedAt": "2026-11-05T06:10:12.000Z"
}
```

`stats` rows and monitor events have the same shape as in the [camera Actor](https://apify.com/keiya_dev/japan-used-camera-market): stats adds `count`, `minJpy`, `medianJpy`, `maxJpy`, `byShop`, `byGrade`; events add `eventType` and the price change.

### Pricing

Pay per event, no subscription:

| Event | Price |
|---|---|
| `listing` (search mode, per listing) | $0.003 |
| `model-stats` (stats mode, per model row) | $0.005 |
| `alert-event` (monitor mode, per NEW / PRICE_DROP / PRICE_UP / SOLD_OUT) | $0.01 |
| `history-row` (history mode, per model × day row) | $0.002 |
| `deal-row` (deals mode, per deal returned) | $0.005 |

Higher Apify plans get progressively lower prices (Bronze / Silver / Gold discounts).

### Integrations

- **Google Sheets**: Apify → Integrations → Google Sheets.
- **Slack / Discord**: paste an incoming-webhook URL into `alertWebhookUrl`.
- **n8n / Make / Zapier**: the Apify node, or point `alertWebhookUrl` at a webhook trigger.
- **AI agents**: see the next section.

### AI agents (MCP)

A dedicated MCP server, [`@keiya-dev/japan-used-market-mcp`](https://github.com/Enu27/japan-used-market-mcp) (open source, MIT), gives Claude, Cursor and other MCP clients tools backed by this Actor. Pass `"market": "model-train"` (the server also covers used cameras, its default, watches and instruments):

| Tool | Mode |
|---|---|
| `search_listings` | search, with product code, scale, set type, motor and accessories |
| `price_stats` | stats |
| `price_history` | history |
| `start_monitor` | creates a scheduled monitor (Task + Schedule) in your Apify account |
| `list_markets` | shops and grades per market (no run) |

**Claude Desktop**: add this to `claude_desktop_config.json`. On macOS it is `~/Library/Application Support/Claude/claude_desktop_config.json`; on Windows, `%APPDATA%\Claude\claude_desktop_config.json`. Then restart the app:

```json
{
  "mcpServers": {
    "japan-used-market": {
      "command": "npx",
      "args": ["-y", "@keiya-dev/japan-used-market-mcp"],
      "env": { "APIFY_TOKEN": "apify_api_..." }
    }
  }
}
```

Get the token at Apify Console → Settings → API & Integrations. Runs are billed to your Apify account, as with any other run.

Then just ask: *"Find a KATO 0-series Shinkansen set with the motor car under $150"*, *"What's the median price of TOMIX 98313 in Japan?"*, *"Alert me on Discord when a MicroAce Odakyu set appears."*

**Claude Code**: `claude mcp add japan-used-market -e APIFY_TOKEN=apify_api_... -- npx -y @keiya-dev/japan-used-market-mcp`

**Remote / HTTP clients**: run `npx -y @keiya-dev/japan-used-market-mcp --http --port 3000`. The endpoint is `/mcp` (Streamable HTTP); send your token as `Authorization: Bearer <APIFY_TOKEN>`.

The generic [Apify MCP server](https://mcp.apify.com) also works: add the Actor `keiya_dev/japan-used-model-train-market` as a tool.

### Limitations & fair use

- We read only public listing pages at low request rates and return factual listing data: brand, model / code, price, condition grade, stock, shop and URL. Product photos and the shops' own description text are not copied into the output.
- Prices are the shops' tax-included asking prices (税込), not sold prices. USD is a mid-market conversion for convenience. Shipping is not included.
- **Pochi ships within Japan only**, may cancel orders sent to forwarding services, and asks buyers not to purchase for resale (転売目的でのご購入はご遠慮ください). Check each shop's terms before you buy.
- `motorized`, `accessories` and `setType` come from the shops' own words. When a shop doesn't say, the field is `null`: nothing is guessed.
- Only public listing pages and the product pages of returned or alerted listings are read. There is no login, no search endpoint and no sort parameter that robots.txt forbids.
- If a shop's bot protection challenges a run, a page can't be loaded or a shop changes its layout, the run fails with a message saying what to do. It writes no partial data, charges nothing and leaves the monitor snapshot unchanged.
- Not affiliated with any of the shops or makers.

### Changelog

- **2026-11-05 — keywords: words are AND'ed.** A keyword with several words now matches listings that contain *all* of its words, in any order and position ("KATO 新幹線" no longer needs the words side by side). Keywords are still OR'ed with each other. **Compatibility:** single-word keywords and phrases that appeared side by side still match, but a multi-word keyword can now match more listings than before (e.g. Leica M → "leica" + "m", and "m" is in "mm"). To keep the old exact-phrase behaviour, wrap the keyword in double quotes: `"\"Leica M\""` in JSON, `"Leica M"` in the Console. Monitors whose keywords change get a fresh baseline unless they set a `monitorId`.
- **0.1** (2026-11-05): Hobbyland Pochi (all used model trains) and Hard Off Off Mall (model trains). Search / stats / deals / monitor / history, `dealsOnly` alerts, optional English summaries (your LLM key), maker product codes, scale, set type, motorized, accessories, lot year, normalized grades. Output is factual listing data only: `imageUrl` and the shops' free-text notes are no longer returned.

### Related

- [Japan Used Camera Market](https://apify.com/keiya_dev/japan-used-camera-market): the same five modes for used cameras and lenses (Fujiya Camera, Sanpou Camera, Naniwa, Hard Off).
- [Japan Used Watch Market](https://apify.com/keiya_dev/japan-used-watch-market): Grand Seiko, Rolex and more from WATCHNIAN and Hard Off.
- [Japan Used Guitar & Instrument Market](https://apify.com/keiya_dev/japan-used-instrument-market): Fender Japan, Made in Japan guitars and wind instruments from Shimokura Gakki and Hard Off.

***

If this saved you a trip to Akihabara, a review on the Store helps others find it.

### 日本の方へ

ホビーランドぽち・ハードオフの中古鉄道模型（KATO・TOMIX など）の在庫を、英語の統一形式（状態ランク・円とドル価格つき）で取り出す Actor です。

- **海外転売の仕入れ監視**：`monitor` モードを Schedule で定期実行し、新着（NEW）や値下げ（PRICE_DROP）を Slack / Discord に通知
- **相場確認**：`stats` / `history` モードで、モデルごとの最安・中央値・最高値と日々の推移を確認
- **割安出品の発見**：`deals` モードで、同じモデル・同ランク以上の中央値より安い出品だけを抽出

**使い方（Quick start）**：Apify Console でこの Actor を開き、Input の **Mode**（`search` / `stats` / `deals` / `monitor` / `history`）を選んで **Keywords** に "KATO", "10-1332", "新幹線" などを入れ、**Start** を押すだけです。結果は Output タブに表示され、CSV や Excel でダウンロードできます。

**料金の円換算目安**（1ドル＝150円で概算。実際の請求はドル建てで、為替により変わります）：

| 内容 | ドル | 円の目安 |
|---|---|---|
| 出品データ 1,000件（search） | $3 | 約450円 |
| モデル集計 1行（stats） | $0.005 | 約0.75円 |
| 割安出品 1件（deals） | $0.005 | 約0.75円 |
| アラート 1件（monitor） | $0.01 | 約1.5円 |
| 価格履歴 1行（history） | $0.002 | 約0.3円 |

Apify の上位プランでは割引（Bronze / Silver / Gold）が自動で適用されます。英語の要約（summarize）を使う場合は、ご自身の Anthropic / OpenAI の API キーに対して各社から別途請求されます（Actor 側の課金はありません）。

日本語でのお問い合わせ・不具合の報告は、Actor ページの **Issues** タブへどうぞ。

# Actor input Schema

## `mode` (type: `string`):

search = return listings. stats = model stats of in-stock listings (count, min / median / max by shop & condition grade). deals = in-stock listings at least dealThresholdPct % under the median of the same model in the same grade or better, with medianJpy, comparisonCount, discountPct and dealScore (statistics only). monitor = compare against the last run and emit only NEW / PRICE_DROP / PRICE_UP / SOLD_OUT events (use with a Schedule). history = daily min / median / count per model, by shop and condition grade, from stored daily snapshots (no crawling; needs keywords, brands or models). History is collected since 2026-11-05 (Hobbyland Pochi daily, Off Mall weekly) — treat the first 30 days as indicative. Example: "deals" to list only underpriced listings.

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

Which shops to search. Hobbyland Pochi (ホビーランドぽち, Osaka, ~12,000 used N / HO model trains, all graded A–D) and Hard Off Off Mall (~9,600 model trains on sale from Hard Off / Hobby Off stores nationwide). Maker codes (Pochi), motor and case (Off Mall) are completed from product pages for the listings a run returns. Example: \["pochi"] for graded listings only.

## `keywords` (type: `array`):

Only keep listings whose maker + title contains any of these (case-insensitive, English or Japanese; product codes work too). Leave empty to get everything. Examples: "KATO", "TOMIX", "10-1332", "98313", "新幹線", "0系", "EF58", "国鉄", "サンライズ", "小田急". Words inside one keyword must all appear, in any order: "KATO 新幹線" matches listings that contain every word. Put a keyword in double quotes for an exact phrase, e.g. '"0系"' (until 2026-11-05 every keyword was an exact phrase).

## `brands` (type: `array`):

Optional exact maker filter (canonical English names): KATO, TOMIX, MicroAce, GreenMax, Tenshodo, Endo, TOMYTEC, Popondetta, MODEMO, Zoukeimura, Katsumi. Example: \["KATO", "TOMIX"].

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

History mode: only these exact model keys, as shown in the "model" field of stats mode ("maker code", e.g. "kato 10-1332", "tomix 98313", "microace a-6590").

## `days` (type: `integer`):

History mode: how many days back to return, counting today (JST). Example: 30 for the last month.

## `minPriceJpy` (type: `integer`):

Drop listings cheaper than this. Example: 5000 to skip single spare parts.

## `maxPriceJpy` (type: `integer`):

Drop listings more expensive than this. Example: 30000 (about $200).

## `grades` (type: `array`):

Keep only these normalized grades. NEW > MINT > EXCELLENT > VERY_GOOD > GOOD > FAIR > JUNK (sold as is), plus CUSTOM (modified / painted / kit-built). Pochi A = MINT, A´ = EXCELLENT, B = VERY_GOOD, C = GOOD, D = FAIR. Example: \["MINT", "EXCELLENT"].

## `includeSoldOut` (type: `boolean`):

Search mode: also return listings marked sold out (Pochi keeps ~1,100 sold cards listed with a 売り切れ badge). Example: on, to see what sold recently and at what price.

## `fullScan` (type: `boolean`):

Monitor mode only. Off (default): lists are read newest-first and stop after 20 already-known listings in a row (normally 1 request per list per run). On: read every page (Pochi ≈ 250 pages, ~7 min; Off Mall ≈ 320 pages, ~6 min) to catch every PRICE_DROP / PRICE_UP / SOLD_OUT. Example: on in a once-a-day schedule, off in an hourly one.

## `monitorId` (type: `string`):

Optional. Each monitor keeps its own snapshot, keyed by its filters (keywords, brands, grades, price range, includeSoldOut). Set a monitorId to separate several schedules that use the same filters, or to keep the snapshot when you edit the filters. Letters, digits and - \_ . only. Example: "daily-full-scan".

## `maxItems` (type: `integer`):

Stop after this many matching listings across all selected shops (0 = no limit), split evenly between shops. Pochi has ~12,000 used model trains, Off Mall ~9,600. In search mode each returned listing also costs one product-page request (maker code, motor, case). Ignored in monitor mode. Example: 0 with keywords "10-1332" to get every listing of that set.

## `jpyPerUsd` (type: `number`):

Exchange rate used for priceUsd. Leave empty to fetch the current rate automatically. Example: 150.

## `alertWebhookUrl` (type: `string`):

Optional. In monitor mode every batch of monitor events is POSTed as JSON to this URL. In deals mode the best dealsWebhookTop deals (highest dealScore first) are POSTed once per run — schedule it daily for a morning digest. Works with Slack/Discord incoming webhooks, n8n, Make, Zapier. Example: https://hooks.slack.com/services/T000/B000/XXXX.

## `dealsWebhookTop` (type: `integer`):

Deals mode with alertWebhookUrl: how many deals to POST, best dealScore first (ties: deeper discount first). The dataset still gets every deal. Example: 5 for a short Discord message.

## `alertEvents` (type: `array`):

Monitor mode: only these event types are written to the dataset, charged, and sent to the webhook. Example: \["NEW", "PRICE_DROP"] to hear about new listings and price cuts only.

## `dealsOnly` (type: `boolean`):

Monitor mode: output and send only the NEW / PRICE_DROP events whose listing is a deal (at least dealThresholdPct % under the median of the same model, same grade or better, among the listings this monitor tracks). Each event then carries medianJpy, comparisonCount, discountPct and dealScore. Charged as monitor events. Example: on, to get a Slack ping only when a new listing is a bargain.

## `dealThresholdPct` (type: `integer`):

Deals mode and monitor dealsOnly: a listing is a deal when it is at least this many % under the median of the same model in the same grade or better. Example: 20 = only listings at least 20 % under the median.

## `summarize` (type: `boolean`):

Search and deals mode: add summaryEn, a one-line English summary per listing (e.g. "Grand Seiko SBGX063, A-grade, full set, 18% under Japan median"), written by an LLM with YOUR API key below. The Actor charges nothing for it; your LLM provider bills you (Claude Haiku: roughly $0.01 per 100 listings or less). Without a key it is skipped with a warning.

## `llmApiKey` (type: `string`):

Your Anthropic or OpenAI API key, used only for summarize. Stored encrypted as a secret input. Example: sk-ant-api03-… (Anthropic) or sk-… (OpenAI).

## `llmProvider` (type: `string`):

anthropic (default, model claude-haiku-5-5) or openai (model gpt-5-mini). Example: "openai" if you only have an OpenAI key.

## `llmModel` (type: `string`):

Optional model id override, e.g. claude-sonnet-5-5. Leave empty for the provider default.

## `proxyConfiguration` (type: `object`):

Off by default (direct connection). Switch to an Apify proxy only if runs get blocked. Example: Apify Proxy → RESIDENTIAL group, if a shop returns 403.

## Actor input object example

```json
{
  "mode": "search",
  "sources": [
    "pochi",
    "offmall"
  ],
  "keywords": [
    "KATO"
  ],
  "days": 90,
  "includeSoldOut": false,
  "fullScan": false,
  "maxItems": 10,
  "dealsWebhookTop": 10,
  "alertEvents": [
    "NEW",
    "PRICE_DROP"
  ],
  "dealsOnly": false,
  "dealThresholdPct": 15,
  "summarize": false,
  "llmProvider": "anthropic",
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `results` (type: `string`):

Dataset items. Shape depends on mode — see the dataset schema (listing / model stats row / monitor event / history row).

## `overview` (type: `string`):

No description

## `stats` (type: `string`):

No description

## `history` (type: `string`):

No description

## `deals` (type: `string`):

No description

# 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 = {
    "sources": [
        "pochi",
        "offmall"
    ],
    "keywords": [
        "KATO"
    ],
    "maxItems": 10,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("keiya_dev/japan-used-model-train-market").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 = {
    "sources": [
        "pochi",
        "offmall",
    ],
    "keywords": ["KATO"],
    "maxItems": 10,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("keiya_dev/japan-used-model-train-market").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 '{
  "sources": [
    "pochi",
    "offmall"
  ],
  "keywords": [
    "KATO"
  ],
  "maxItems": 10,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call keiya_dev/japan-used-model-train-market --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,keiya_dev/japan-used-model-train-market"
        }
    }
}
```

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/69xDCPgTkvuxpjb8p/builds/CVfOH8jLtg1jTI8eu/openapi.json
