{
  "openapi": "3.0.1",
  "info": {
    "title": "Japan Used Model Train Market — KATO, TOMIX Search & Alerts",
    "description": "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.",
    "version": "0.1",
    "x-build-id": "CVfOH8jLtg1jTI8eu"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/keiya_dev~japan-used-model-train-market/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-keiya_dev-japan-used-model-train-market",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/acts/keiya_dev~japan-used-model-train-market/runs": {
      "post": {
        "operationId": "runs-sync-keiya_dev-japan-used-model-train-market",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor and returns information about the initiated run in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/runsResponseSchema"
                }
              }
            }
          }
        }
      }
    },
    "/acts/keiya_dev~japan-used-model-train-market/run-sync": {
      "post": {
        "operationId": "run-sync-keiya_dev-japan-used-model-train-market",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "inputSchema": {
        "type": "object",
        "required": [
          "mode",
          "sources"
        ],
        "properties": {
          "mode": {
            "title": "Mode",
            "enum": [
              "search",
              "stats",
              "deals",
              "monitor",
              "history"
            ],
            "type": "string",
            "description": "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.",
            "default": "search"
          },
          "sources": {
            "title": "Shops",
            "type": "array",
            "description": "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.",
            "items": {
              "type": "string",
              "enum": [
                "pochi",
                "offmall"
              ],
              "enumTitles": [
                "Hobbyland Pochi (ホビーランドぽち) — used model trains",
                "Hard Off Off Mall (ハードオフ オフモール) — model trains"
              ]
            },
            "default": [
              "pochi",
              "offmall"
            ]
          },
          "keywords": {
            "title": "Keywords (OR)",
            "type": "array",
            "description": "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).",
            "items": {
              "type": "string"
            }
          },
          "brands": {
            "title": "Brands",
            "type": "array",
            "description": "Optional exact maker filter (canonical English names): KATO, TOMIX, MicroAce, GreenMax, Tenshodo, Endo, TOMYTEC, Popondetta, MODEMO, Zoukeimura, Katsumi. Example: [\"KATO\", \"TOMIX\"].",
            "items": {
              "type": "string"
            }
          },
          "models": {
            "title": "Model keys (history mode)",
            "type": "array",
            "description": "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\").",
            "items": {
              "type": "string"
            }
          },
          "days": {
            "title": "Days of history (history mode)",
            "minimum": 1,
            "maximum": 3650,
            "type": "integer",
            "description": "History mode: how many days back to return, counting today (JST). Example: 30 for the last month.",
            "default": 90
          },
          "minPriceJpy": {
            "title": "Min price (JPY)",
            "minimum": 0,
            "type": "integer",
            "description": "Drop listings cheaper than this. Example: 5000 to skip single spare parts."
          },
          "maxPriceJpy": {
            "title": "Max price (JPY)",
            "minimum": 0,
            "type": "integer",
            "description": "Drop listings more expensive than this. Example: 30000 (about $200)."
          },
          "grades": {
            "title": "Condition grades",
            "type": "array",
            "description": "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\"].",
            "items": {
              "type": "string",
              "enum": [
                "NEW",
                "MINT",
                "EXCELLENT",
                "VERY_GOOD",
                "GOOD",
                "FAIR",
                "JUNK",
                "CUSTOM"
              ]
            }
          },
          "includeSoldOut": {
            "title": "Include sold-out listings",
            "type": "boolean",
            "description": "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.",
            "default": false
          },
          "fullScan": {
            "title": "Full scan (monitor mode)",
            "type": "boolean",
            "description": "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.",
            "default": false
          },
          "monitorId": {
            "title": "Monitor ID (monitor mode)",
            "type": "string",
            "description": "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": {
            "title": "Max listings",
            "minimum": 0,
            "type": "integer",
            "description": "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.",
            "default": 200
          },
          "jpyPerUsd": {
            "title": "JPY per USD",
            "minimum": 1,
            "type": "number",
            "description": "Exchange rate used for priceUsd. Leave empty to fetch the current rate automatically. Example: 150."
          },
          "alertWebhookUrl": {
            "title": "Alert webhook URL (monitor / deals mode)",
            "type": "string",
            "description": "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": {
            "title": "Deals sent to the webhook (deals mode)",
            "minimum": 1,
            "maximum": 40,
            "type": "integer",
            "description": "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.",
            "default": 10
          },
          "alertEvents": {
            "title": "Monitor events to output",
            "type": "array",
            "description": "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.",
            "items": {
              "type": "string",
              "enum": [
                "NEW",
                "PRICE_DROP",
                "PRICE_UP",
                "SOLD_OUT"
              ]
            },
            "default": [
              "NEW",
              "PRICE_DROP"
            ]
          },
          "dealsOnly": {
            "title": "Deals only (monitor mode)",
            "type": "boolean",
            "description": "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.",
            "default": false
          },
          "dealThresholdPct": {
            "title": "Deal threshold % (deals / dealsOnly)",
            "minimum": 0,
            "maximum": 95,
            "type": "integer",
            "description": "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.",
            "default": 15
          },
          "summarize": {
            "title": "English one-line summaries (LLM, your key)",
            "type": "boolean",
            "description": "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.",
            "default": false
          },
          "llmApiKey": {
            "title": "LLM API key (summarize)",
            "type": "string",
            "description": "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": {
            "title": "LLM provider (summarize)",
            "enum": [
              "anthropic",
              "openai"
            ],
            "type": "string",
            "description": "anthropic (default, model claude-haiku-5-5) or openai (model gpt-5-mini). Example: \"openai\" if you only have an OpenAI key.",
            "default": "anthropic"
          },
          "llmModel": {
            "title": "LLM model (summarize, optional)",
            "type": "string",
            "description": "Optional model id override, e.g. claude-sonnet-5-5. Leave empty for the provider default."
          },
          "proxyConfiguration": {
            "title": "Proxy",
            "type": "object",
            "description": "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.",
            "default": {
              "useApifyProxy": false
            }
          }
        }
      },
      "runsResponseSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "actId": {
                "type": "string"
              },
              "userId": {
                "type": "string"
              },
              "startedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "finishedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "status": {
                "type": "string",
                "example": "READY"
              },
              "meta": {
                "type": "object",
                "properties": {
                  "origin": {
                    "type": "string",
                    "example": "API"
                  },
                  "userAgent": {
                    "type": "string"
                  }
                }
              },
              "stats": {
                "type": "object",
                "properties": {
                  "inputBodyLen": {
                    "type": "integer",
                    "example": 2000
                  },
                  "rebootCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "restartCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "resurrectCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "computeUnits": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "options": {
                "type": "object",
                "properties": {
                  "build": {
                    "type": "string",
                    "example": "latest"
                  },
                  "timeoutSecs": {
                    "type": "integer",
                    "example": 300
                  },
                  "memoryMbytes": {
                    "type": "integer",
                    "example": 1024
                  },
                  "diskMbytes": {
                    "type": "integer",
                    "example": 2048
                  }
                }
              },
              "buildId": {
                "type": "string"
              },
              "defaultKeyValueStoreId": {
                "type": "string"
              },
              "defaultDatasetId": {
                "type": "string"
              },
              "defaultRequestQueueId": {
                "type": "string"
              },
              "buildNumber": {
                "type": "string",
                "example": "1.0.0"
              },
              "containerUrl": {
                "type": "string"
              },
              "usage": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "integer",
                    "example": 1
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "usageTotalUsd": {
                "type": "number",
                "example": 0.00005
              },
              "usageUsd": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "number",
                    "example": 0.00005
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}