{"openapi": "3.1.0", "info": {"title": "Taste Finder API", "version": "1.0.0", "description": "Give a keyword (category, product or brand) and it extracts sensory and emotional words from related searches, SERPs, AI Overviews and People Also Ask, groups them into taste tribes and saves a report. Product planners and marketers use it to choose product language and messages. Data comes from ListeningMind DaaS and Maistro lmpipe for Korea, the US and Japan. Reports can be compared. Workflow: list_reports → get_input_hint → get_meaning_hint → explore_seeds → analyze_taste → get_report → compare_reports → download_report → archive_reports → delete_reports", "contact": {"email": "m-support@listeningmind.com"}}, "servers": [{"url": "https://daas-taste.listeningmind.ai"}], "paths": {"/hint": {"get": {"operationId": "get_meaning_hint", "summary": "Meaning hint", "description": "Second-stage hint: explains what the keyword means, which domain cards it is read with, which directions to analyze (this product only, brand line, whole category) and which other meanings to filter out. Uses the CEP Finder meaning resolver (one LLM call, cached one day per keyword and market; the same call the analysis makes later). 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 grounded model call (about USD 0.04, about 0.5 Lima) when the keyword's meaning is not cached; 0 when cached. The analysis reuses it.. Time: usually 15-40 seconds when not cached.", "tags": ["run"], "x-lm-kind": "run", "x-lm-cost": "one grounded model call (about USD 0.04, about 0.5 Lima) when the keyword's meaning is not cached; 0 when cached. The analysis reuses it.", "responses": {"200": {"description": "Success"}, "default": {"description": "Error (application/problem+json or JSON with detail)"}}, "parameters": [{"name": "q", "in": "query", "required": true, "description": "Keyword (or the base keyword returned by get_input_hint).", "schema": {"type": "string", "maxLength": 60}}, {"name": "locale", "in": "query", "required": false, "description": "Market whose search data is used: kr, us or jp. Default follows lang (ko->kr, en->us, ja->jp).", "schema": {"type": "string", "enum": ["kr", "us", "jp"]}}, {"name": "lang", "in": "query", "required": false, "description": "Page and report language.", "schema": {"type": "string", "enum": ["ko", "en", "ja"], "default": "ko"}}, {"name": "stage", "in": "query", "required": true, "description": "Must be '2'.", "schema": {"type": "string", "enum": ["2"], "default": "2"}}]}}, "/explore": {"get": {"operationId": "explore_seeds", "summary": "Explore seed candidates (step 1)", "description": "Step 1 of the UI: collects up to 26 strongly related search topics for the keyword with volume, class and flags (meme, AI Overview, no demographic data), pre-checks the recommended ones, and returns an HTML page with that seed set. Read the checked candidates (inputs named s) to pass as s to analyze_taste. Spends a small number of Data API credits. 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 170 Data API credits (about 2 Lima): related-keyword lookup, 1 credit per candidate for volumes, 10 credits per top candidate, sometimes one SERP (about 30). Time: 20-60 seconds. Usually followed by: analyze_taste.", "tags": ["run"], "x-lm-kind": "run", "x-lm-cost": "about 170 Data API credits (about 2 Lima): related-keyword lookup, 1 credit per candidate for volumes, 10 credits per top candidate, sometimes one SERP (about 30)", "responses": {"200": {"description": "Success"}, "default": {"description": "Error (application/problem+json or JSON with detail)"}}, "parameters": [{"name": "q", "in": "query", "required": true, "description": "Keyword to analyze: a category, product or brand, e.g. '향수', 'whisky', 'Lexus RX350'.", "schema": {"type": "string"}}, {"name": "locale", "in": "query", "required": false, "description": "Market whose search data is used: kr, us or jp. Default follows lang (ko->kr, en->us, ja->jp).", "schema": {"type": "string", "enum": ["kr", "us", "jp"]}}, {"name": "lang", "in": "query", "required": false, "description": "Page and report language.", "schema": {"type": "string", "enum": ["ko", "en", "ja"], "default": "ko"}}]}}, "/analyze": {"get": {"operationId": "analyze_taste", "summary": "Run taste analysis (step 2)", "description": "Step 2: collects search data, SERPs and AI Overviews for the keyword and up to 4 seeds, extracts sensory and emotional vocabulary, groups consumers into taste tribes and saves a report. Runs synchronously and answers with a redirect to the new report /r/{id}; the HTML report is returned. Spends Data API credits and one Maistro lmpipe analysis call; ask the person before calling. 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: usually 250-400 Data API credits, about 5 Lima (keyword info 10, about 30 per SERP for the keyword, seeds and 4-12 second-hop queries), plus 330 or more with journey=1 (about 4.5 Lima more), plus one grounded model call for the meaning check when it is not already cached (about USD 0.04). Time: about 1 minute, longer for keywords with much data. Usually followed by: get_report.", "tags": ["run"], "x-lm-kind": "run", "x-lm-cost": "usually 250-400 Data API credits, about 5 Lima (keyword info 10, about 30 per SERP for the keyword, seeds and 4-12 second-hop queries), plus 330 or more with journey=1 (about 4.5 Lima more), plus one grounded model call for the meaning check when it is not already cached (about USD 0.04)", "responses": {"200": {"description": "Success"}, "default": {"description": "Error (application/problem+json or JSON with detail)"}}, "parameters": [{"name": "q", "in": "query", "required": true, "description": "Keyword to analyze: a category, product or brand, e.g. '향수', 'whisky', 'Lexus RX350'.", "schema": {"type": "string"}}, {"name": "locale", "in": "query", "required": false, "description": "Market whose search data, SERPs and AI Overviews are collected. If omitted it follows lang (ko->kr, en->us, ja->jp). Japan and the US have no demographic data.", "schema": {"type": "string", "enum": ["kr", "us", "jp"]}}, {"name": "lang", "in": "query", "required": false, "description": "Report language. It is also sent as the language of the lmpipe analysis, so it can change extracted text, not only labels; a saved report can still be re-rendered in another language with get_report.", "schema": {"type": "string", "enum": ["ko", "en", "ja"], "default": "ko"}}, {"name": "s", "in": "query", "required": false, "description": "Seed topics chosen on the explore page (checkboxes named s; recommended ones are pre-checked), sent as repeated s= parameters. Seeds add related items and second-hop SERP queries, widening the tribes. The keyword itself is ignored if repeated. s plus extra are de-duplicated and cut to 4. Empty: the analysis runs on the keyword alone (the UI 'skip' link).", "schema": {"type": "array", "items": {"type": "string"}, "maxItems": 4}}, {"name": "extra", "in": "query", "required": false, "description": "Extra seeds typed by the person, separated by commas (also 、 or ，), e.g. 'pinot noir, 몬테스 알파'. Appended after s, then the list is cut to 4.", "schema": {"type": "string"}}, {"name": "journey", "in": "query", "required": false, "description": "'1' also collects the search journey (path_finder, 12 steps): alternatives weighed and entry paths appear in the report. Costs 330 or more extra credits.", "schema": {"type": "string", "enum": ["0", "1"], "default": "0"}}, {"name": "comp", "in": "query", "required": false, "description": "Competitor brands to add to the Brand x Taste table (up to 3). One extra search result page ('brand + keyword') is collected per brand, about 1.2 Lima in total.", "schema": {"type": "array", "items": {"type": "string"}, "maxItems": 3}}]}}, "/r/{run_id}": {"get": {"operationId": "get_report", "summary": "Open report", "description": "Returns a saved taste report (HTML): taste tribes, sensory vocabulary, emotions, market facts and evidence. lang re-renders it in another language at no cost. For a comparison report, base and who switch the counting view. Read only, free. Usually followed by: download_report, compare_reports.", "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": "Report id (6-20 hex chars), as in /r/{run_id}.", "schema": {"type": "string", "pattern": "^[0-9a-f]{6,20}$"}}, {"name": "lang", "in": "query", "required": false, "description": "Optional. Re-render in this language.", "schema": {"type": "string", "enum": ["ko", "en", "ja"]}}, {"name": "base", "in": "query", "required": false, "description": "Comparison reports only: count sentences mentioning the subject (subj) or all collected (all).", "schema": {"type": "string", "enum": ["subj", "all"]}}, {"name": "who", "in": "query", "required": false, "description": "Comparison reports only: all speakers or consumers only (voice).", "schema": {"type": "string", "enum": ["all", "voice"]}}]}}, "/r/{run_id}/download": {"get": {"operationId": "download_report", "summary": "Download report", "description": "Returns the report as an HTML file attachment. 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": "Report id (6-20 hex chars), as in /r/{run_id}.", "schema": {"type": "string", "pattern": "^[0-9a-f]{6,20}$"}}, {"name": "lang", "in": "query", "required": false, "description": "Optional. Render in this language.", "schema": {"type": "string", "enum": ["ko", "en", "ja"]}}]}}, "/": {"get": {"operationId": "list_reports", "summary": "Report history", "description": "Returns the home page HTML, which contains the report history (keyword, seeds, market, time, archived flag, links /r/{id}). By default it shows the market of the page language; hist=all shows all markets. There is no JSON list endpoint. The landing page no longer lists anyone's runs; use list_history for the signed-in member's own runs. 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": "lang", "in": "query", "required": false, "description": "Page and report language.", "schema": {"type": "string", "enum": ["ko", "en", "ja"], "default": "ko"}}, {"name": "hist", "in": "query", "required": false, "description": "Optional. 'all' shows reports of all markets.", "schema": {"type": "string", "enum": ["all"]}}]}}, "/history": {"get": {"operationId": "list_history", "summary": "My runs", "description": "The signed-in member's own runs (taste analyses and comparison reports) across every market, newest first, as an HTML page with links to each report. Sign-in required; other members' runs are not shown. 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": "lang", "in": "query", "required": false, "description": "Page language.", "schema": {"type": "string", "enum": ["ko", "en", "ja"], "default": "ko"}}]}}, "/compare": {"get": {"operationId": "compare_reports", "summary": "Compare reports", "description": "Creates and saves a comparison report of 2 to 4 saved full reports (each must have its model saved; very old reports cannot be compared) and returns it. No credits. Changes saved data in the app; no credits. Usually followed by: get_report.", "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": "ids", "in": "query", "required": true, "description": "2-4 report ids separated by commas, e.g. 'a1b2c3d4e5f6,0f1e2d3c4b5a'.", "schema": {"type": "string"}}, {"name": "lang", "in": "query", "required": false, "description": "Page and report language.", "schema": {"type": "string", "enum": ["ko", "en", "ja"], "default": "ko"}}]}}, "/archive": {"post": {"operationId": "archive_reports", "summary": "Archive reports", "description": "Marks or unmarks reports as archived (starred). Archived reports always stay visible in the history regardless of the list limit. Returns {ok, n}. 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)"}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"ids": {"type": "array", "items": {"type": "string"}, "description": "Report ids."}, "on": {"type": "boolean", "default": true, "description": "true archives, false removes the mark."}}, "required": ["ids"]}}}}}}, "/delete": {"post": {"operationId": "delete_reports", "summary": "Delete reports", "description": "Permanently deletes up to 50 reports and their saved models. Returns {ok, removed} where removed counts deleted files. 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)"}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"ids": {"type": "array", "items": {"type": "string"}, "maxItems": 50, "description": "Report ids (6-20 hex chars)."}}, "required": ["ids"]}}}}}}, "/lexicon": {"get": {"operationId": "get_lexicon", "summary": "Sensory lexicon", "description": "Returns the lexicon page: sensory and emotion vocabulary per domain and auto-learning status of candidate words. 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": "lang", "in": "query", "required": false, "description": "Page and report language.", "schema": {"type": "string", "enum": ["ko", "en", "ja"], "default": "ko"}}]}}, "/quality/review": {"get": {"operationId": "get_quality_review", "summary": "Word review page", "description": "Curator page listing candidate sensory words of a domain with examples and counts; each row carries tok, dom, lc and ns needed by review_word. Read only, free. Usually followed by: review_word.", "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": "dom", "in": "query", "required": false, "description": "Domain id of the sensory lexicon (as shown in the domain selector on the quality pages and on /lexicon).", "schema": {"type": "string"}}, {"name": "lang", "in": "query", "required": false, "description": "Page and report language.", "schema": {"type": "string", "enum": ["ko", "en", "ja"], "default": "ko"}}]}}, "/quality/audit": {"get": {"operationId": "get_quality_audit", "summary": "Evidence audit page", "description": "Curator page to check whether sampled evidence sentences were assigned correctly; each row carries the key needed by mark_evidence. Read only, free. Usually followed by: mark_evidence.", "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": "dom", "in": "query", "required": false, "description": "Domain id of the sensory lexicon (as shown in the domain selector on the quality pages and on /lexicon).", "schema": {"type": "string"}}, {"name": "lang", "in": "query", "required": false, "description": "Page and report language.", "schema": {"type": "string", "enum": ["ko", "en", "ja"], "default": "ko"}}]}}, "/quality/cards": {"get": {"operationId": "get_quality_cards", "summary": "Card review page", "description": "Curator page with generated taste cards of a domain and the recompute button; each row carries dom and fid needed by decide_card. Read only, free. Usually followed by: decide_card, recompute_reports.", "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": "dom", "in": "query", "required": false, "description": "Domain id of the sensory lexicon (as shown in the domain selector on the quality pages and on /lexicon).", "schema": {"type": "string"}}, {"name": "lang", "in": "query", "required": false, "description": "Page and report language.", "schema": {"type": "string", "enum": ["ko", "en", "ja"], "default": "ko"}}]}}, "/quality/word": {"post": {"operationId": "review_word", "summary": "Decide candidate word", "description": "Approves, rejects or marks as situation word (ctx, kept out of the lexicon) one candidate word. Changes the shared lexicon used by all future reports. Returns {ok}. 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)"}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"tok": {"type": "string", "description": "Candidate word."}, "dom": {"type": "string", "description": "Domain id of the sensory lexicon (as shown in the domain selector on the quality pages and on /lexicon)."}, "lc": {"type": "string", "enum": ["kr", "us", "jp"], "default": "kr", "description": "Market of the word."}, "ns": {"type": "string", "enum": ["lex", "emo"], "default": "lex", "description": "lex for sensory words, emo for emotion words."}, "action": {"type": "string", "enum": ["approve", "reject", "ctx"], "description": "Decision."}, "fam": {"type": "string", "description": "Optional taste family to file the word under when approving."}}, "required": ["tok", "dom", "action"]}}}}}}, "/quality/mark": {"post": {"operationId": "mark_evidence", "summary": "Mark evidence check", "description": "Records whether one sampled evidence assignment is correct, used for the precision figure on the quality dashboard. Returns {ok}. 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)"}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"dom": {"type": "string", "description": "Domain id of the sensory lexicon (as shown in the domain selector on the quality pages and on /lexicon)."}, "key": {"type": "string", "description": "Sample key from the audit page."}, "ok": {"type": "boolean", "description": "true if correct, false if wrong."}, "note": {"type": "string", "description": "Optional note (up to 200 characters)."}}, "required": ["dom", "key"]}}}}}}, "/quality/card": {"post": {"operationId": "decide_card", "summary": "Decide taste card", "description": "Approves, rejects or saves edits of a generated taste card (name and layer). Changes shared cards used by reports. Returns {ok}. 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)"}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"dom": {"type": "string", "description": "Domain id of the sensory lexicon (as shown in the domain selector on the quality pages and on /lexicon)."}, "fid": {"type": "string", "description": "Card (family) id from the cards page."}, "action": {"type": "string", "enum": ["approve", "reject", "save"], "description": "Decision."}, "ko": {"type": "string", "description": "Optional Korean card name."}, "layer": {"type": "string", "description": "Optional layer of the card."}}, "required": ["dom", "fid", "action"]}}}}}}, "/quality/recompute": {"post": {"operationId": "recompute_reports", "summary": "Recompute reports", "description": "Recomputes saved reports from their stored raw data with the current lexicon and cards, without new data calls: up to 50 reports of a domain, or up to 50 stale reports when dom is omitted. Overwrites those reports. Returns {ok, done, total}. Changes saved data in the app; no credits. Cost: free (no credits). Time: can take minutes for 50 reports.", "tags": ["action"], "x-lm-kind": "action", "x-lm-cost": "free (no credits)", "responses": {"200": {"description": "Success"}, "default": {"description": "Error (application/problem+json or JSON with detail)"}}, "requestBody": {"required": false, "content": {"application/json": {"schema": {"type": "object", "properties": {"dom": {"type": "string", "description": "Optional domain id. Omit to recompute stale reports."}}, "required": []}}}}}}, "/_lm/report-robots/{run_id}": {"get": {"operationId": "get_report_robots", "summary": "Report search visibility", "description": "Returns whether search engines may index this report page (index or noindex), and why: a company member's run or one set by hand is index; a customer's run, and any run that is still going, failed or came back empty, is noindex. Read only; no credits. 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": "The report's run id: the id in the report address (for ACO the project id, or project~step).", "schema": {"type": "string"}}]}}}, "externalDocs": {"url": "https://daas-taste.listeningmind.ai/agents.md", "description": "Agent guide"}}