{"openapi": "3.1.0", "info": {"title": "Smart Store Suite API", "version": "1.0.0", "description": "Smart Store Suite joins three checks for Naver Smart Store sellers into one flow. Step 1, store check, collects products from a store URL (Smart Store, Brand Store, Shopping Window, Naver+) or from product, sales and margin CSVs and combines search demand with margin or reviews and sales to show which products to grow and which to drop. Step 2 rewrites a product title in the words searchers actually use, and step 3 scores how well a detail page covers the buying criteria searchers look for and suggests fixes. Smart Store sellers, brand managers and commerce MDs use it. Data comes from the ListeningMind Data API (keyword_info, intent_finder, cluster_finder, path_finder), maistro-lmpipe and LLMs (MiniMax, Claude); the market is Korea (Naver Shopping). Workflow: collect_store_products → preview_dormant_products → start_store_check → get_store_check → get_store_check_product → download_store_check_csv → start_title_analysis → get_title_analysis → select_title_identity → start_detail_page_analysis → get_detail_page_analysis → rescore_detail_page → add_watch → list_store_checks", "contact": {"email": "m-support@listeningmind.com"}}, "servers": [{"url": "https://daas-store.listeningmind.ai"}], "paths": {"/portfolio/api/uploads/store-url": {"post": {"operationId": "collect_store_products", "summary": "Collect products from a store URL", "description": "Collects the products of a Naver store (smartstore.naver.com/{id}, brand.naver.com/{id}, shopping.naver.com/window/{vertical}/store/{channelId} or a Naver+ store shopping.naver.com/{slug}) by popularity order, with price, category, review count, rating, sales count (Shopping Window) and rank, and stores a review snapshot for momentum. By default it first REMOVES the current product set (past results stay). Returns {ok, store{name, storeId, host}, imported, totalAvailable, via (http or browser), note, watching}. Uses a headless browser when Naver blocks plain requests; can take tens of seconds to a few minutes. Then call start_store_check. Spends ListeningMind Data API credits or paid model calls. Over MCP a person approves it first (you get a confirm link); in the browser the page asks the person. Cost: free: no Data API credits or LLM calls (Naver pages only); it replaces the product set unless append is true. Time: tens of seconds to a few minutes (server limit 300 seconds). Usually followed by: preview_dormant_products, start_store_check.", "tags": ["run"], "x-lm-kind": "run", "x-lm-cost": "free: no Data API credits or LLM calls (Naver pages only); it replaces the product set unless append is true", "responses": {"200": {"description": "Success"}, "default": {"description": "Error (application/problem+json or JSON with detail)"}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"url": {"type": "string", "description": "Store URL. Sub paths (a product page of the store too) are allowed; only the store id is used."}, "limit": {"type": "integer", "minimum": 1, "maximum": 1000, "default": 100, "description": "How many top products (popularity order) to collect, capped at 1000. The UI offers 50, 100, 200 and 500. More products mean more keywords for start_store_check and therefore more credits."}, "watch": {"type": "boolean", "default": false, "description": "Also register the store for periodic re-collection and re-analysis (see add_watch); later runs spend credits automatically."}, "intervalDays": {"type": "integer", "enum": [7, 14, 30], "default": 7, "description": "Re-collection interval in days when watch is true (other values become 7)."}, "append": {"type": "boolean", "default": false, "description": "Keep the current products and add these (mixes stores). The UI never sends it; false replaces the product set."}}, "required": ["url"]}}}}}}, "/portfolio/api/products/dormant": {"post": {"operationId": "restore_dormant_products", "summary": "Restore dormant products", "description": "Clears the dormant exclusion on every current product. Returns {ok, restored}. Changes saved data in the app; no credits.", "tags": ["action"], "x-lm-kind": "action", "x-lm-cost": "free", "responses": {"200": {"description": "Success"}, "default": {"description": "Error (application/problem+json or JSON with detail)"}}}}, "/portfolio/api/uploads/products": {"delete": {"operationId": "clear_store_products", "summary": "Clear product data", "description": "Deletes the current product set (with its sales and margin data) so a new store can be loaded. Past store check results and review snapshots are kept. Returns {ok, deleted, note}. Deletes data. A person approves it first.", "tags": ["delete"], "x-lm-kind": "delete", "x-lm-cost": "free", "responses": {"200": {"description": "Success"}, "default": {"description": "Error (application/problem+json or JSON with detail)"}}}}, "/portfolio/api/samples/{kind}": {"get": {"operationId": "download_sample_csv", "summary": "Download sample CSV", "description": "Downloads a sample CSV that shows the columns of the product, sales or margin upload used on /portfolio/upload. Uploading CSV files is done in the web page (multipart upload), not through this tool set. Read only, free.", "tags": ["read"], "x-lm-kind": "read", "x-lm-cost": "free", "responses": {"200": {"description": "Success"}, "default": {"description": "Error (application/problem+json or JSON with detail)"}}, "parameters": [{"name": "kind", "in": "path", "required": true, "description": "Which sample: products (product_id, product_name, sale_price required), sales (product_id, revenue, orders or units_sold) or margins (product_id plus cost columns).", "schema": {"type": "string", "enum": ["products", "sales", "margins"]}}]}}, "/portfolio/api/analysis/portfolio/start": {"post": {"operationId": "start_store_check", "summary": "Start store check", "description": "Starts a store check on the current product set (from collect_store_products or CSV uploads), skipping dormant-excluded products. In the background it picks a representative search keyword per product (rules, plus an LLM when the server has a MiniMax key), reads keyword_info and intent_finder for each new keyword, scores search demand, margin (with margin CSV) or sales power (reviews, sales count), momentum (review growth since the last collection) and risk, classifies every product and recommends actions. Returns {ok, runId} (or {ok, runId, resumed: true} when a run is already in progress); 400 when there are no products or all are excluded. Poll get_store_check. Spends ListeningMind Data API credits or paid model calls. Over MCP a person approves it first (you get a confirm link); in the browser the page asks the person. Cost: per 100 products with new keywords about 1,000 Data API credits for keyword_info plus 100 intent_finder calls (limit 100 each; the app does not report their credit price); keywords fetched in the last 7 days are free; plus 1 MiniMax LLM call per 30 products; no credits when the server runs in mock mode. Time: usually a few minutes for 100 products; depends on product count and cache. Usually followed by: get_store_check.", "tags": ["run"], "x-lm-kind": "run", "x-lm-cost": "per 100 products with new keywords about 1,000 Data API credits for keyword_info plus 100 intent_finder calls (limit 100 each; the app does not report their credit price); keywords fetched in the last 7 days are free; plus 1 MiniMax LLM call per 30 products; no credits when the server runs in mock mode", "responses": {"200": {"description": "Success"}, "default": {"description": "Error (application/problem+json or JSON with detail)"}}}}, "/portfolio/api/analysis/{run_id}/portfolio": {"get": {"operationId": "get_store_check", "summary": "Store check status and result", "description": "Returns one store check: run {id, label (store name), status (pending, running, completed, failed), totalCount, doneCount, excludedCount, errorMessage, startedAt, completedAt}, summary (dominantMode margin/proxy/demand, counts per classification and per recommended action, withMargin, withReview, withMomentum, pending) and items[] per product ordered by priority (scoreId, productName, category, salePrice, revenue, reviewCount, representativeKeyword, demandQualityScore, marginScore, popularityScore, momentumScore, portfolioScore, riskScore, classification, analysisMode, recommendedAction[], reason, dataBasis[], priority). Repeat until run.status is completed or failed; progress is doneCount/totalCount. Read only, free. Waits up to about 45 s for 'run.status' to reach completed, failed; call again if not done. Usually followed by: get_store_check_product, download_store_check_csv, start_title_analysis, start_detail_page_analysis.", "tags": ["read"], "x-lm-kind": "read", "x-lm-cost": "free", "responses": {"200": {"description": "Success"}, "default": {"description": "Error (application/problem+json or JSON with detail)"}}, "parameters": [{"name": "run_id", "in": "path", "required": true, "description": "Store check run id returned by start_store_check or list_store_checks (shown in the page URL /portfolio/analysis/{run_id}/portfolio).", "schema": {"type": "string"}}]}}, "/portfolio/api/analysis/{run_id}/portfolio/{score_id}": {"get": {"operationId": "get_store_check_product", "summary": "Product detail of a store check", "description": "Returns one product of a store check: product (name, category, brand, productUrl, salePrice, cost fields, reviewCount, reviewScore, collectionRank, dataSource), sales totals, score (keywords, all scores and statuses with breakdowns, classification, recommendedAction, reason, priority, dataBasis) and signal for the representative keyword (volume, Naver volume, trend, competition, CPC, intents, AI Overview, 12 monthly volumes, SERP features). preserved is true when the product was removed since and only the snapshot remains. Read only, free. Usually followed by: rescore_store_check_product, start_title_analysis, start_detail_page_analysis.", "tags": ["read"], "x-lm-kind": "read", "x-lm-cost": "free", "responses": {"200": {"description": "Success"}, "default": {"description": "Error (application/problem+json or JSON with detail)"}}, "parameters": [{"name": "run_id", "in": "path", "required": true, "description": "Store check run id returned by start_store_check or list_store_checks (shown in the page URL /portfolio/analysis/{run_id}/portfolio).", "schema": {"type": "string"}}, {"name": "score_id", "in": "path", "required": true, "description": "Product result id: items[].scoreId from get_store_check (the last segment of /portfolio/analysis/{run_id}/portfolio/{score_id}). items[].productDbId is also accepted for older links.", "schema": {"type": "string"}}]}, "patch": {"operationId": "rescore_store_check_product", "summary": "Rescore product with a keyword", "description": "Replaces the representative keyword of one product in a store check (use when the automatic keyword is wrong or had no search data), fetches its search data and rescores the product, then recomputes priorities in the run. Overwrites the stored product result. Returns {ok}; read get_store_check_product after. Fails with 409 for products removed since the run. Spends ListeningMind Data API credits or paid model calls. Over MCP a person approves it first (you get a confirm link); in the browser the page asks the person. Cost: about 10 Data API credits for keyword_info plus one intent_finder call (limit 100) when the keyword was not fetched in the last 7 days; free when cached. Time: a few seconds. Usually followed by: get_store_check_product.", "tags": ["run"], "x-lm-kind": "run", "x-lm-cost": "about 10 Data API credits for keyword_info plus one intent_finder call (limit 100) when the keyword was not fetched in the last 7 days; free when cached", "responses": {"200": {"description": "Success"}, "default": {"description": "Error (application/problem+json or JSON with detail)"}}, "parameters": [{"name": "run_id", "in": "path", "required": true, "description": "Store check run id returned by start_store_check or list_store_checks (shown in the page URL /portfolio/analysis/{run_id}/portfolio).", "schema": {"type": "string"}}, {"name": "score_id", "in": "path", "required": true, "description": "Product result id: items[].scoreId from get_store_check (the last segment of /portfolio/analysis/{run_id}/portfolio/{score_id}). items[].productDbId is also accepted for older links.", "schema": {"type": "string"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"keyword": {"type": "string", "description": "Search keyword that best names the product, e.g. '이유식 큐브틀'."}}, "required": ["keyword"]}}}}}}, "/portfolio/api/analysis/{run_id}/portfolio/export": {"get": {"operationId": "download_store_check_csv", "summary": "Download store check CSV", "description": "Downloads the store check as CSV (UTF-8 with BOM): priority, product_id, product_name, representative_keyword, analysis_mode, scores and statuses, review and momentum figures, classification and label, recommended_actions, data_basis, reason, revenue. Read only, free.", "tags": ["read"], "x-lm-kind": "read", "x-lm-cost": "free", "responses": {"200": {"description": "Success"}, "default": {"description": "Error (application/problem+json or JSON with detail)"}}, "parameters": [{"name": "run_id", "in": "path", "required": true, "description": "Store check run id returned by start_store_check or list_store_checks (shown in the page URL /portfolio/analysis/{run_id}/portfolio).", "schema": {"type": "string"}}]}}, "/portfolio/api/analysis/runs": {"get": {"operationId": "list_store_checks", "summary": "List store checks", "description": "Lists up to 100 store check runs, newest first: {runs[{id, label, status, totalCount, analyzed, startedAt, completedAt, dominantMode, topClass, withMomentum, classCount}]}. Read only, free. Usually followed by: get_store_check.", "tags": ["read"], "x-lm-kind": "read", "x-lm-cost": "free", "responses": {"200": {"description": "Success"}, "default": {"description": "Error (application/problem+json or JSON with detail)"}}}}, "/portfolio/api/watch": {"get": {"operationId": "list_watches", "summary": "List store watches", "description": "Lists stores registered for periodic re-collection: {watches[{id, url, label, intervalDays, productLimit, active, nextRunAt, lastRunAt, lastRunId, lastStatus, lastError, runCount}]}. lastRunId opens the latest store check. Read only, free. Usually followed by: get_store_check.", "tags": ["read"], "x-lm-kind": "read", "x-lm-cost": "free", "responses": {"200": {"description": "Success"}, "default": {"description": "Error (application/problem+json or JSON with detail)"}}}, "post": {"operationId": "add_watch", "summary": "Add store watch", "description": "Registers (or updates and re-activates) a store for periodic tracking. A server timer runs daily at 09:05 and, for every due store, replaces the product set with a fresh collection and runs a full store check, so momentum (review growth) appears from the second run. A new watch is due immediately. Returns {ok, watch}. Spends ListeningMind Data API credits or paid model calls. Over MCP a person approves it first (you get a confirm link); in the browser the page asks the person. Cost: free at call time; every scheduled run then costs the same as start_store_check. Usually followed by: list_watches.", "tags": ["run"], "x-lm-kind": "run", "x-lm-cost": "free at call time; every scheduled run then costs the same as start_store_check", "responses": {"200": {"description": "Success"}, "default": {"description": "Error (application/problem+json or JSON with detail)"}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"url": {"type": "string", "description": "Store URL in one of the formats collect_store_products accepts."}, "intervalDays": {"type": "integer", "enum": [7, 14, 30], "default": 7, "description": "Days between runs (other values become 7)."}, "limit": {"type": "integer", "minimum": 1, "maximum": 500, "default": 50, "description": "Products to collect per run (capped at 500)."}, "label": {"type": "string", "description": "Optional display name; replaced by the store name after the first run."}}, "required": ["url"]}}}}}}, "/portfolio/api/watch/{watch_id}": {"patch": {"operationId": "set_watch_active", "summary": "Pause or resume a watch", "description": "Pauses (active false) or resumes (active true) a store watch. Resuming lets the daily timer spend credits again. Returns {ok, watch}. Changes saved data in the app; no credits.", "tags": ["action"], "x-lm-kind": "action", "x-lm-cost": "free", "responses": {"200": {"description": "Success"}, "default": {"description": "Error (application/problem+json or JSON with detail)"}}, "parameters": [{"name": "watch_id", "in": "path", "required": true, "description": "Watch id from list_watches (watches[].id).", "schema": {"type": "string"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"active": {"type": "boolean", "description": "true to resume, false to pause."}}, "required": ["active"]}}}}}, "delete": {"operationId": "delete_watch", "summary": "Delete store watch", "description": "Removes a store watch. Past store checks stay. Returns {ok}. Deletes data. A person approves it first.", "tags": ["delete"], "x-lm-kind": "delete", "x-lm-cost": "free", "responses": {"200": {"description": "Success"}, "default": {"description": "Error (application/problem+json or JSON with detail)"}}, "parameters": [{"name": "watch_id", "in": "path", "required": true, "description": "Watch id from list_watches (watches[].id).", "schema": {"type": "string"}}]}}, "/portfolio/api/listeningmind/keyword-info": {"post": {"operationId": "lookup_keyword_info", "summary": "Look up keyword metrics", "description": "Calls ListeningMind keyword_info (Korea) through the store check module for up to 50 keywords: volume, Naver volume, competition, CPC (KRW), intents, 12 monthly volumes, SERP features and AI Overview presence. Returns {ok, mode (real or mock), data[]}. mode mock means synthetic numbers. Spends ListeningMind Data API credits or paid model calls. Over MCP a person approves it first (you get a confirm link); in the browser the page asks the person. Cost: up to 500 Data API credits (about 10 per keyword, at most 50 keywords); free in mock mode. Time: a few seconds.", "tags": ["run"], "x-lm-kind": "run", "x-lm-cost": "up to 500 Data API credits (about 10 per keyword, at most 50 keywords); free in mock mode", "responses": {"200": {"description": "Success"}, "default": {"description": "Error (application/problem+json or JSON with detail)"}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"keywords": {"type": "array", "items": {"type": "string"}, "maxItems": 50, "description": "Keywords to look up; only the first 50 are used."}}, "required": ["keywords"]}}}}}}, "/portfolio/api/listeningmind/intent-finder": {"post": {"operationId": "lookup_intent_keywords", "summary": "Look up related searches", "description": "Calls ListeningMind intent_finder keyword_list (Korea, volume 100 or more, sorted by volume) through the store check module: search queries that contain the keyword. Returns {ok, mode (real or mock), data[] of keyword strings}. Spends ListeningMind Data API credits or paid model calls. Over MCP a person approves it first (you get a confirm link); in the browser the page asks the person. Cost: one intent_finder call (the app does not report its credit price); free in mock mode. Time: a few seconds.", "tags": ["run"], "x-lm-kind": "run", "x-lm-cost": "one intent_finder call (the app does not report its credit price); free in mock mode", "responses": {"200": {"description": "Success"}, "default": {"description": "Error (application/problem+json or JSON with detail)"}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"keyword": {"type": "string", "description": "Seed keyword."}, "limit": {"type": "integer", "minimum": 1, "maximum": 300, "default": 100, "description": "Maximum keywords returned (capped at 300)."}}, "required": ["keyword"]}}}}}}, "/api/v1/titles/analyses": {"post": {"operationId": "start_title_analysis", "summary": "Start title rewrite", "description": "Starts a background title analysis for one Smart Store product name: splits it into brand, category, attribute, spec and noise words with keyword_info (an LLM only for unclear words), builds or reuses the category's identity candidates (search modifiers that really have volume, from intent_finder, cluster_finder, path_finder, keyword_info and maistro-lmpipe), ranks them, scores the current title (TIS 0-100) and composes A/B titles, front 3 word sets, category fit, noise words and tag / option plans. Returns {analysis_id, status: queued}. Poll get_title_analysis. 429 when 12 jobs are already queued or running. Spends ListeningMind Data API credits or paid model calls. Over MCP a person approves it first (you get a confirm link); in the browser the page asks the person. Cost: about 11,000 Data API credits or more when the category is new (identity set not built in the last 30 days): path_finder limit 300 (about 8,450 at the Funnel Leak Finder rate), keyword_info for up to about 190 keywords (about 10 each), intent_finder limit 300 and cluster_finder hop 2 (prices not reported by the app), plus a maistro-lmpipe analysis; a cached category needs only keyword_info for the title words, word combinations and tags (a few hundred credits); 1-4 LLM calls (MiniMax for unclear words, Claude to screen brand words in a new category and to compose the A and B titles). Time: usually under 3 minutes; a new category adds about 30-90 seconds. Usually followed by: get_title_analysis.", "tags": ["run"], "x-lm-kind": "run", "x-lm-cost": "about 11,000 Data API credits or more when the category is new (identity set not built in the last 30 days): path_finder limit 300 (about 8,450 at the Funnel Leak Finder rate), keyword_info for up to about 190 keywords (about 10 each), intent_finder limit 300 and cluster_finder hop 2 (prices not reported by the app), plus a maistro-lmpipe analysis; a cached category needs only keyword_info for the title words, word combinations and tags (a few hundred credits); 1-4 LLM calls (MiniMax for unclear words, Claude to screen brand words in a new category and to compose the A and B titles)", "responses": {"200": {"description": "Success"}, "default": {"description": "Error (application/problem+json or JSON with detail)"}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"title": {"type": "string", "maxLength": 200, "description": "Current product name (1-200 characters). Required."}, "category_path": {"type": "array", "items": {"type": "string"}, "maxItems": 8, "description": "Registered category path, e.g. ['패션잡화', '운동화', '러닝화'] (up to 8). Used to pick the main category word, to detect ambiguous seeds and for the category fit diagnosis."}, "product_hint": {"type": "string", "description": "Short note on what the product really is (material, target, use). Without it every identity gets match 0.5; with it the B title is the identity that matches the product best."}, "tags": {"type": "array", "items": {"type": "string"}, "maxItems": 30, "description": "Current seller tags (up to 30). Each is checked for search volume and promo words; tags that contain the seed are also tried as seed candidates."}, "seed_override": {"type": "string", "description": "Category word to analyze, forced (skips automatic seed choice and seed refinement). The UI sends it when a person typed the seed."}, "seed_hint": {"type": "string", "description": "Suggested category word (the UI fills it from the category path); used only as a fallback and as a refinement candidate, not forced."}, "gl": {"type": "string", "default": "kr", "description": "Search market sent to the Data API. The UI never sends it (server default kr); the app's word rules are Korean and built for Naver, so keep kr."}}, "required": ["title"]}}}}}, "get": {"operationId": "list_title_analyses", "summary": "List title analyses", "description": "Lists the 30 newest title analyses: {analyses[{analysis_id, raw_title, seed_keyword, status, error_code, tis, grade, created_at, finished_at}]}. Read only, free. Usually followed by: get_title_analysis.", "tags": ["read"], "x-lm-kind": "read", "x-lm-cost": "free", "responses": {"200": {"description": "Success"}, "default": {"description": "Error (application/problem+json or JSON with detail)"}}}}, "/api/v1/titles/analyses/{analysis_id}": {"get": {"operationId": "get_title_analysis", "summary": "Title analysis status and result", "description": "Returns one title analysis: analysis_id, raw_title, seed_keyword, gl, status (queued, running, done, error), error_code (SEED_AMBIGUOUS, NO_VALID_IDENTITY, INTERNAL), error_detail, tis, grade (S/A/B/C/D), selected_identity_id, created_at, finished_at, tokens[] and, when done, report {title_score, identity_diagnosis{candidates[], selected_identity_id, seed_refined, seed_warning}, front3_recommendations, category_diagnosis, noise_keywords, title_variants[] (A/B with predicted_tis and policy findings), tag_option_plan, policy_report, data_meta}. Repeat until status is done or error. Read only, free. Waits up to about 45 s for 'status' to reach done, error; call again if not done. Usually followed by: select_title_identity, start_detail_page_analysis.", "tags": ["read"], "x-lm-kind": "read", "x-lm-cost": "free", "responses": {"200": {"description": "Success"}, "default": {"description": "Error (application/problem+json or JSON with detail)"}}, "parameters": [{"name": "analysis_id", "in": "path", "required": true, "description": "Title analysis id (12 hex characters) returned by start_title_analysis, select_title_identity or list_title_analyses.", "schema": {"type": "string"}}]}, "delete": {"operationId": "delete_title_analysis", "summary": "Delete title analysis", "description": "Deletes one stored title analysis. Cannot be undone. Returns {ok, deleted}. Deletes data. A person approves it first.", "tags": ["delete"], "x-lm-kind": "delete", "x-lm-cost": "free", "responses": {"200": {"description": "Success"}, "default": {"description": "Error (application/problem+json or JSON with detail)"}}, "parameters": [{"name": "analysis_id", "in": "path", "required": true, "description": "Title analysis id (12 hex characters) returned by start_title_analysis, select_title_identity or list_title_analyses.", "schema": {"type": "string"}}]}}, "/api/v1/titles/analyses/{analysis_id}/select-identity": {"post": {"operationId": "select_title_identity", "summary": "Recompose with another identity", "description": "Re-runs the title analysis of the same product name and seed with a chosen identity candidate (report.identity_diagnosis.candidates[].identity_id), so the A title is built around it. Creates a NEW analysis and returns {analysis_id, status: queued, parent_analysis_id, identity_id}. Poll get_title_analysis with the new id. Spends ListeningMind Data API credits or paid model calls. Over MCP a person approves it first (you get a confirm link); in the browser the page asks the person. Cost: about 200 Data API credits or less (keyword_info for the title words; the category identity set is cached) plus 1-3 LLM calls. Time: usually under a minute. Usually followed by: get_title_analysis.", "tags": ["run"], "x-lm-kind": "run", "x-lm-cost": "about 200 Data API credits or less (keyword_info for the title words; the category identity set is cached) plus 1-3 LLM calls", "responses": {"200": {"description": "Success"}, "default": {"description": "Error (application/problem+json or JSON with detail)"}}, "parameters": [{"name": "analysis_id", "in": "path", "required": true, "description": "Title analysis id (12 hex characters) returned by start_title_analysis, select_title_identity or list_title_analyses.", "schema": {"type": "string"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"identity_id": {"type": "string", "description": "identity_id of one candidate in the earlier report. Unknown ids are rejected with the list of valid ones."}, "product_hint": {"type": "string", "description": "Optional product note, as in start_title_analysis."}}, "required": ["identity_id"]}}}}}}, "/api/v1/analyses": {"post": {"operationId": "start_detail_page_analysis", "summary": "Start detail page intent check", "description": "Starts a background check of how well one product page covers the buying criteria searchers use. It reads the page (Smart Store URL, then a reader fallback; usually blocked, so pass tier3 data), OCRs detail images, picks a seed keyword (LLM candidates checked with keyword_info, raised to a broader category under 1,000 monthly searches), builds or reuses the category's intent items on 6 axes (price, performance, use, comparison, risk, trust), judges each item covered / partial / missing with evidence (two LLM passes plus a tie-break), scores ICS and CPS and writes recommendations. Returns {analysis_id, status: queued}. Poll get_detail_page_analysis. 429 when 12 jobs are queued or running. Spends ListeningMind Data API credits or paid model calls. Over MCP a person approves it first (you get a confirm link); in the browser the page asks the person. Cost: about 10,000 Data API credits or more when the category is new (intent items not built in the last 30 days): path_finder limit 300 (about 8,450 at the Funnel Leak Finder rate), keyword_info for up to 150 keywords (about 10 each), intent_finder limit 300 and cluster_finder (prices not reported by the app), plus a maistro-lmpipe analysis; a cached category needs only keyword_info for up to 8 seed candidates; LLM calls: 1 per detail image (OCR), 1 to 2 for the seed, 1 to classify a new category, 2 per 10 intent items plus tie-breaks (20 to 40 items) and 1 for recommendations. Time: a few minutes; a new category adds about 60-120 seconds. Usually followed by: get_detail_page_analysis.", "tags": ["run"], "x-lm-kind": "run", "x-lm-cost": "about 10,000 Data API credits or more when the category is new (intent items not built in the last 30 days): path_finder limit 300 (about 8,450 at the Funnel Leak Finder rate), keyword_info for up to 150 keywords (about 10 each), intent_finder limit 300 and cluster_finder (prices not reported by the app), plus a maistro-lmpipe analysis; a cached category needs only keyword_info for up to 8 seed candidates; LLM calls: 1 per detail image (OCR), 1 to 2 for the seed, 1 to classify a new category, 2 per 10 intent items plus tie-breaks (20 to 40 items) and 1 for recommendations", "responses": {"200": {"description": "Success"}, "default": {"description": "Error (application/problem+json or JSON with detail)"}}, "requestBody": {"required": false, "content": {"application/json": {"schema": {"type": "object", "properties": {"product_url": {"type": "string", "description": "Product page URL on smartstore.naver.com, brand.naver.com or shopping.naver.com (m. hosts allowed). Other hosts are rejected. Either this or tier3 data is required."}, "tier3": {"type": "object", "description": "Product data typed or captured by the seller, used when the server cannot read the page (Smart Store usually blocks server fetches). Any of these fields; all optional.", "properties": {"title": {"type": "string", "description": "Product name (cut to 200 characters)."}, "price": {"type": "string", "description": "Sale price; digits are extracted, e.g. '39,000'."}, "category_path": {"type": "string", "description": "Category path 'a > b > c' (a list of strings is also accepted, up to 6 used)."}, "options": {"type": "string", "description": "Option names, one per line (a list is also accepted, up to 40 used)."}, "detail_text": {"type": "string", "description": "Detail page text (cut to 20,000 characters)."}, "reviews_text": {"type": "string", "description": "Review texts, one per line."}, "qna_text": {"type": "string", "description": "Q&A questions, one per line."}, "review_count": {"type": "integer", "description": "Total review count shown on the page (trust signal)."}, "review_rating": {"type": "number", "description": "Average review rating shown on the page."}, "images": {"type": "array", "items": {"type": "string"}, "description": "Detail images as data:image/* URIs, up to 15, each at most 4.5 MB of base64. Each image is read with one vision LLM call (OCR)."}, "image_urls": {"type": "array", "items": {"type": "string"}, "description": "Detail image URLs on Naver image hosts (pstatic.net, phinf.naver.net, naver.net, naver.com); the server downloads up to 15 and reads them with OCR."}, "capture": {"type": "string", "description": "JSON string copied by the page's bookmarklet on the product page (title, price, category_path, tags, attributes, options, detail_text, image_urls, reviews, review_count, review_rating), or page HTML. Up to 6 MB. Fills the fields above that are empty."}}}, "seed_override": {"type": "string", "description": "Category keyword to analyze, forced (skips the LLM seed choice). Changes which intent items the page is judged against."}, "gl": {"type": "string", "default": "kr", "description": "Search market sent to the Data API. The UI always sends kr; the app is built for Naver Smart Store, so keep kr."}}, "required": []}}}}}, "get": {"operationId": "list_detail_page_analyses", "summary": "List detail page checks", "description": "Lists the 30 newest detail page analyses: {analyses[{analysis_id, product_url, product_title, seed_keyword, status, error_code, ics, cps, grade, created_at, finished_at, parent_analysis_id}]}. Read only, free. Usually followed by: get_detail_page_analysis.", "tags": ["read"], "x-lm-kind": "read", "x-lm-cost": "free", "responses": {"200": {"description": "Success"}, "default": {"description": "Error (application/problem+json or JSON with detail)"}}}}, "/api/v1/analyses/{analysis_id}/seed": {"post": {"operationId": "set_detail_page_seed", "summary": "Change the proposed seed", "description": "Replaces the seed keyword the running analysis just proposed. Only works during the 5-second window after the seed is proposed (the web page shows it as a live prompt); later calls have no effect on the result. For agents, seed_override in start_detail_page_analysis is the reliable way. Returns {ok, seed}; 404 when the analysis is no longer running. Changes saved data in the app; no credits.", "tags": ["action"], "x-lm-kind": "action", "x-lm-cost": "free", "responses": {"200": {"description": "Success"}, "default": {"description": "Error (application/problem+json or JSON with detail)"}}, "parameters": [{"name": "analysis_id", "in": "path", "required": true, "description": "Detail page analysis id (12 hex characters) returned by start_detail_page_analysis, rescore_detail_page or list_detail_page_analyses.", "schema": {"type": "string"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"seed": {"type": "string", "description": "Seed keyword to use instead."}}, "required": ["seed"]}}}}}}, "/api/v1/analyses/{analysis_id}": {"get": {"operationId": "get_detail_page_analysis", "summary": "Detail page check status and result", "description": "Returns one detail page analysis: analysis_id, product_url, product_title, seed_keyword, status (queued, running, done, error), error_code (EXTRACT_BLOCKED, LOW_DATA, SEED_AMBIGUOUS, INTERNAL), error_detail, ics, cps, grade (S/A/B/C/D), parent_analysis_id, created_at, finished_at and, when done, report {scores{ics, cps, grade, axis_scores, cps_parts}, axes[], items[] (intent item, keywords, volume, verdict, evidence), cards{covered, missed}, recommendations{restructure, title_suggestions, faq, review_prompts, comparison_frame}, seed, data_quality, report_meta, diff (after a re-check)}. Repeat until status is done or error. Read only, free. Waits up to about 45 s for 'status' to reach done, error; call again if not done. Usually followed by: rescore_detail_page, get_category_universe.", "tags": ["read"], "x-lm-kind": "read", "x-lm-cost": "free", "responses": {"200": {"description": "Success"}, "default": {"description": "Error (application/problem+json or JSON with detail)"}}, "parameters": [{"name": "analysis_id", "in": "path", "required": true, "description": "Detail page analysis id (12 hex characters) returned by start_detail_page_analysis, rescore_detail_page or list_detail_page_analyses.", "schema": {"type": "string"}}]}, "delete": {"operationId": "delete_detail_page_analysis", "summary": "Delete detail page check", "description": "Deletes one stored detail page analysis. Cannot be undone. Returns {ok, deleted}. Deletes data. A person approves it first.", "tags": ["delete"], "x-lm-kind": "delete", "x-lm-cost": "free", "responses": {"200": {"description": "Success"}, "default": {"description": "Error (application/problem+json or JSON with detail)"}}, "parameters": [{"name": "analysis_id", "in": "path", "required": true, "description": "Detail page analysis id (12 hex characters) returned by start_detail_page_analysis, rescore_detail_page or list_detail_page_analyses.", "schema": {"type": "string"}}]}}, "/api/v1/analyses/{analysis_id}/rescore": {"post": {"operationId": "rescore_detail_page", "summary": "Re-check an edited detail page", "description": "Re-checks a product after its detail page was edited: reuses the earlier page data and seed, replaces it with any new tier3 data (for example the new detail text), and adds diff (score change and verdict changes) to the report. Creates a NEW analysis and returns {analysis_id, status: queued, parent_analysis_id}. Poll get_detail_page_analysis. Spends ListeningMind Data API credits or paid model calls. Over MCP a person approves it first (you get a confirm link); in the browser the page asks the person. Cost: about 10 Data API credits (keyword_info for the seed) when the category is still cached, else same as start_detail_page_analysis; LLM calls as in start_detail_page_analysis without the seed step. Time: a few minutes. Usually followed by: get_detail_page_analysis.", "tags": ["run"], "x-lm-kind": "run", "x-lm-cost": "about 10 Data API credits (keyword_info for the seed) when the category is still cached, else same as start_detail_page_analysis; LLM calls as in start_detail_page_analysis without the seed step", "responses": {"200": {"description": "Success"}, "default": {"description": "Error (application/problem+json or JSON with detail)"}}, "parameters": [{"name": "analysis_id", "in": "path", "required": true, "description": "Detail page analysis id (12 hex characters) returned by start_detail_page_analysis, rescore_detail_page or list_detail_page_analyses.", "schema": {"type": "string"}}], "requestBody": {"required": false, "content": {"application/json": {"schema": {"type": "object", "properties": {"tier3": {"type": "object", "description": "New page data. Without detail_text or images, the earlier detail text is reused; title, category, options, price, reviews and Q&A carry over unless given.", "properties": {"title": {"type": "string", "description": "Product name (cut to 200 characters)."}, "price": {"type": "string", "description": "Sale price; digits are extracted, e.g. '39,000'."}, "category_path": {"type": "string", "description": "Category path 'a > b > c' (a list of strings is also accepted, up to 6 used)."}, "options": {"type": "string", "description": "Option names, one per line (a list is also accepted, up to 40 used)."}, "detail_text": {"type": "string", "description": "Detail page text (cut to 20,000 characters)."}, "reviews_text": {"type": "string", "description": "Review texts, one per line."}, "qna_text": {"type": "string", "description": "Q&A questions, one per line."}, "review_count": {"type": "integer", "description": "Total review count shown on the page (trust signal)."}, "review_rating": {"type": "number", "description": "Average review rating shown on the page."}, "images": {"type": "array", "items": {"type": "string"}, "description": "Detail images as data:image/* URIs, up to 15, each at most 4.5 MB of base64. Each image is read with one vision LLM call (OCR)."}, "image_urls": {"type": "array", "items": {"type": "string"}, "description": "Detail image URLs on Naver image hosts (pstatic.net, phinf.naver.net, naver.net, naver.com); the server downloads up to 15 and reads them with OCR."}, "capture": {"type": "string", "description": "JSON string copied by the page's bookmarklet on the product page (title, price, category_path, tags, attributes, options, detail_text, image_urls, reviews, review_count, review_rating), or page HTML. Up to 6 MB. Fills the fields above that are empty."}}}}, "required": []}}}}}}, "/api/v1/categories/{seed}/universe": {"get": {"operationId": "get_category_universe", "summary": "Category intent library", "description": "Returns the cached intent items of a category seed (built by an earlier detail page check, kept 30 days): items on the 6 axes with keywords and volumes, data quality and cache info. 404 when no cached library exists for that seed. Read only, free.", "tags": ["read"], "x-lm-kind": "read", "x-lm-cost": "free", "responses": {"200": {"description": "Success"}, "default": {"description": "Error (application/problem+json or JSON with detail)"}}, "parameters": [{"name": "seed", "in": "path", "required": true, "description": "Seed keyword exactly as used by an analysis (seed_keyword).", "schema": {"type": "string"}}, {"name": "gl", "in": "query", "required": false, "description": "Market of the cached library (kr).", "schema": {"type": "string", "default": "kr"}}]}}, "/api/v1/i18n": {"post": {"operationId": "get_i18n_strings", "summary": "UI strings (language)", "description": "Returns UI strings for a language (called on language switch; no cost, no ledger entry). Read only, free.", "tags": ["read"], "x-lm-kind": "read", "x-lm-cost": "free", "responses": {"200": {"description": "Success"}, "default": {"description": "Error (application/problem+json or JSON with detail)"}}, "requestBody": {"required": false, "content": {"application/json": {"schema": {"type": "object", "properties": {"lang": {"type": "string"}, "keys": {"type": "array", "items": {"type": "string"}}}, "required": []}}}}}}, "/api/v1/discover/recent": {"get": {"operationId": "list_recent_discoveries", "summary": "Recent keyword discoveries", "description": "Seeds recently explored in keyword discovery, with counts. Signed-in members only. Read only, free.", "tags": ["read"], "x-lm-kind": "read", "x-lm-cost": "free", "responses": {"200": {"description": "Success"}, "default": {"description": "Error (application/problem+json or JSON with detail)"}}}}}, "externalDocs": {"url": "https://daas-store.listeningmind.ai/agents.md", "description": "Agent guide"}}