{"openapi": "3.1.0", "info": {"title": "ICSS API", "version": "1.0.0", "description": "ICSS (Intent-Conditioned Silicon Sampling) samples synthetic respondents from intent states observed in search behavior (CEP, nano intent, KBF, constraint, avoidance, consideration, journey stage) instead of demographics, and runs surveys, FGDs and 1:1 chats with them. Marketers and researchers use it to test hypotheses before real fieldwork. Data comes from ListeningMind search data (DaaS, SERP) plus stored CEP Finder and Intent KG runs, for Korea, Japan and the US. It also includes a distinctive brand asset (DBA) recognition test. Workflow: get_config → analyze_topic → find_cep_run → get_cep_states → start_cep_build → get_cep_job → get_grounding_pack → build_grounding_pack → get_grounding_job → get_evidence → probe_ai_overview → get_cluster_serp → get_keyword_info → ask_llm → save_run → list_runs", "contact": {"email": "m-support@listeningmind.com"}}, "servers": [{"url": "https://daas-icss.listeningmind.ai"}], "paths": {"/api/config": {"get": {"operationId": "get_config", "summary": "Check server setup", "description": "Returns which back-ends are switched on: llm (bool), provider, chain, model, daas (bool), maistro (bool). Call first; if llm is false the survey, FGD and question generation cannot run. Read only, free. Usually followed by: analyze_topic.", "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/analyze": {"post": {"operationId": "analyze_topic", "summary": "Analyze a topic's search data", "description": "Pulls the full search-behavior analysis for one keyword (demand, gender/age audience, search journeys, behavior clusters, SERP) from the maistro-lmpipe analyze service. This is the first data step of the app; the UI calls it once per keyword and merges the results in the browser. Cached on the server for 12 hours. Returns the raw analysis JSON. 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: ListeningMind Data API usage through maistro-lmpipe (amount not reported by the app); free when cached. Time: about 10-60 seconds. Usually followed by: get_evidence, find_cep_run, get_grounding_pack.", "tags": ["run"], "x-lm-kind": "run", "x-lm-cost": "ListeningMind Data API usage through maistro-lmpipe (amount not reported by the app); free when cached", "responses": {"200": {"description": "Success"}, "default": {"description": "Error (application/problem+json or JSON with detail)"}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"q": {"type": "string", "description": "Keyword or brand/category to analyze."}, "locale": {"type": "string", "description": "Market code.", "enum": ["kr", "jp", "us"], "default": "kr"}, "language": {"type": "string", "description": "Optional output language passed through to the analyzer (e.g. ko, ja, en)."}}, "required": ["q"]}}}}}}, "/api/daas/keyword_info": {"post": {"operationId": "get_keyword_info", "summary": "Get keyword metrics", "description": "Calls the ListeningMind keyword_info endpoint through the app proxy: monthly volume, trend, competition, CPC, gender/age demography and intents for a list of keywords. The UI uses it to add demography and volume to the chosen cluster keywords. Cached 12 hours. 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: ListeningMind Data API credits (keyword_info, per keyword).", "tags": ["run"], "x-lm-kind": "run", "x-lm-cost": "ListeningMind Data API credits (keyword_info, per keyword)", "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", "description": "Keywords to look up.", "items": {"type": "string"}}, "gl": {"type": "string", "description": "Market code.", "enum": ["kr", "jp", "us"], "default": "kr"}, "data_type": {"type": "string", "description": "keyword_info data type; the server uses 'all' when omitted.", "default": "all"}}, "required": ["keywords", "gl"]}}}}}}, "/api/evidence": {"post": {"operationId": "get_evidence", "summary": "Get evidence summary", "description": "Looks up existing CEP Finder runs and Intent KG runs that match the topic and returns a short evidence summary (top CEPs with keywords, KBF, constraints, brands; KG nodes such as KBF, CEP, heuristics, pitfalls). Reads stored runs only, never builds. Returns {topic, locale, cep, kg, cep_error, kg_error}. 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": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"q": {"type": "string", "description": "Topic label or keyword."}, "locale": {"type": "string", "description": "Market code.", "enum": ["kr", "jp", "us"], "default": "kr"}, "alt": {"type": "array", "description": "Alternative topic names to try when matching stored runs.", "items": {"type": "string"}}}, "required": ["q"]}}}}}}, "/api/compare": {"post": {"operationId": "compare_brands", "summary": "Compare brands head to head", "description": "Runs the maistro-lmpipe compare analysis for 2 to 5 brands or items in one market (search demand, audience and intent side by side). The UI starts it when the user enters comparison items. Cached 12 hours. 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: ListeningMind Data API usage through maistro-lmpipe (amount not reported).", "tags": ["run"], "x-lm-kind": "run", "x-lm-cost": "ListeningMind Data API usage through maistro-lmpipe (amount not reported)", "responses": {"200": {"description": "Success"}, "default": {"description": "Error (application/problem+json or JSON with detail)"}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"items": {"type": "array", "description": "2 to 5 brand or item names.", "items": {"type": "string"}, "minItems": 2, "maxItems": 5}, "locale": {"type": "string", "description": "Market code.", "enum": ["kr", "jp", "us"], "default": "kr"}, "language": {"type": "string", "description": "Optional output language (ko, ja, en)."}}, "required": ["items"]}}}}}}, "/api/cdj": {"post": {"operationId": "get_category_journey", "summary": "Get category journey scope", "description": "Calls the maistro-lmpipe category scope analysis that the UI uses as the substrate for the 5-stage consumer decision journey (CDJ) view. Returns the top_n category keywords with stage signals. Cached 12 hours. 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: ListeningMind Data API usage through maistro-lmpipe (amount not reported).", "tags": ["run"], "x-lm-kind": "run", "x-lm-cost": "ListeningMind Data API usage through maistro-lmpipe (amount not reported)", "responses": {"200": {"description": "Success"}, "default": {"description": "Error (application/problem+json or JSON with detail)"}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"q": {"type": "string", "description": "Topic label or keyword."}, "locale": {"type": "string", "description": "Market code.", "enum": ["kr", "jp", "us"], "default": "kr"}, "top_n": {"type": "integer", "description": "How many category keywords to return (UI sends 40).", "default": 40}}, "required": ["q"]}}}}}}, "/api/prompts/{prompt_id}": {"get": {"operationId": "get_analysis_prompt", "summary": "Get purpose analysis prompt", "description": "Fetches a purpose-specific analysis prompt template from maistro-lmpipe (first 4,000 chars of analysis_prompt). The UI uses it to build insight prompts. Returns {id, analysis_prompt, version}. 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": "prompt_id", "in": "path", "required": true, "description": "Prompt id (lowercase letters and underscores only).", "schema": {"type": "string"}}, {"name": "language", "in": "query", "required": false, "description": "Prompt language.", "schema": {"type": "string", "enum": ["ko", "ja", "en"], "default": "ko"}}, {"name": "audience", "in": "query", "required": false, "description": "Audience of the prompt (UI sends marketer).", "schema": {"type": "string", "default": "marketer"}}]}}, "/api/aio-probe": {"post": {"operationId": "probe_ai_overview", "summary": "Probe Google AI Overviews", "description": "Collects Google AI Overview and People Also Ask text for the keyword plus probe queries such as 'keyword + downsides / side effects / caveats' in the market language. The UI uses it to fill category-specific avoidance and decision criteria in the intent state vector. Returns {keyword, gl, queries, aio:[{text, from}], paa:[{q, from}]}. 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: ListeningMind SERP Data API credits, 4 queries by default (keyword + 3 probes). Time: about 10-40 seconds.", "tags": ["run"], "x-lm-kind": "run", "x-lm-cost": "ListeningMind SERP Data API credits, 4 queries by default (keyword + 3 probes)", "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": "Topic keyword."}, "gl": {"type": "string", "description": "Market code.", "enum": ["kr", "jp", "us"], "default": "kr"}, "probes": {"type": "array", "description": "Optional probe words (max 5). Default: the first 3 market-language probes.", "items": {"type": "string"}}}, "required": ["keyword"]}}}}}}, "/api/cluster-serp": {"post": {"operationId": "get_cluster_serp", "summary": "Get SERP evidence for a cluster", "description": "For up to 6 keywords of the chosen search cluster, collects AI Overview text, People Also Ask, people-also-search-for and top organic titles, merged and de-duplicated. The UI uses it when a custom panel is built from one cluster. Returns {aio, paa, pasf, organic, per_keyword, n_keywords}. 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: ListeningMind SERP Data API credits, one SERP per keyword.", "tags": ["run"], "x-lm-kind": "run", "x-lm-cost": "ListeningMind SERP Data API credits, one SERP per keyword", "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", "description": "1 to 6 cluster keywords.", "items": {"type": "string"}, "maxItems": 6}, "gl": {"type": "string", "description": "Market code.", "enum": ["kr", "jp", "us"], "default": "kr"}}, "required": ["keywords"]}}}}}}, "/api/cep/find": {"post": {"operationId": "find_cep_run", "summary": "Find an existing CEP run", "description": "Searches the CEP Finder run history for a run that matches the topic in the same market (prefers deep over standard over quick, and the market language). Free. Returns {found, run, candidates:[{run_id, topic, keyword, gl, depth, score}]}. Read only, free. Usually followed by: get_cep_states, start_cep_build.", "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": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"q": {"type": "string", "description": "Topic or keyword."}, "gl": {"type": "string", "description": "Market code.", "enum": ["kr", "jp", "us"], "default": "kr"}}, "required": ["q"]}}}}}}, "/api/cep/states": {"post": {"operationId": "get_cep_states", "summary": "Load CEP intent states", "description": "Converts a CEP Finder run (cep_map) into the ICSS intent-state distribution: per CEP weight, volume, nano intents, KBF, constraints, avoidances, alternatives, thresholds, brands, journey, demography with evidence labels. This is P(IntentState) used to sample the synthetic panel. Free. 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": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"run_id": {"type": "string", "description": "CEP Finder run id from find_cep_run or get_cep_job."}}, "required": ["run_id"]}}}}}}, "/api/cep/build": {"post": {"operationId": "start_cep_build", "summary": "Start a new CEP analysis", "description": "Starts a new CEP Finder analysis for the keyword when no stored run exists. Returns {job_id}; poll get_cep_job, then call get_cep_states with the finished run_id. Spends 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: Data API credits: standard about 30,000-40,000; deep measured 66,000-133,000. Time: several minutes. Usually followed by: get_cep_job.", "tags": ["run"], "x-lm-kind": "run", "x-lm-cost": "Data API credits: standard about 30,000-40,000; deep measured 66,000-133,000", "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."}, "topic": {"type": "string", "description": "Optional topic label."}, "gl": {"type": "string", "description": "Market code.", "enum": ["kr", "jp", "us"], "default": "kr"}, "depth": {"type": "string", "description": "Analysis depth: quick = about 6 CEPs, standard = about 10 CEPs, deep = about 25 CEPs with more nano intents and KBF per CEP. Deeper runs give richer intent states and cost more.", "enum": ["quick", "standard", "deep"], "default": "standard"}, "focal_brand": {"type": "string", "description": "Optional brand to focus on."}, "lang": {"type": "string", "description": "Output language.", "enum": ["ko", "ja", "en"], "default": "ko"}, "ui_lang": {"type": "string", "description": "UI language of the CEP report.", "enum": ["ko", "ja", "en"], "default": "ko"}}, "required": ["keyword"]}}}}}}, "/api/cep/job/{job_id}": {"get": {"operationId": "get_cep_job", "summary": "Check CEP analysis progress", "description": "Returns the CEP Finder job state: status, progress [{pct, msg, stage}] and run_id when finished. Repeat until status is done, completed or error. Read only, free. Waits up to about 45 s for 'status' to reach done, completed, error, failed; call again if not done. Usually followed by: get_cep_states.", "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": "job_id", "in": "path", "required": true, "description": "Job id from start_cep_build.", "schema": {"type": "string"}}]}}, "/api/icss/grounding": {"get": {"operationId": "get_grounding_pack", "summary": "Get a stored grounding pack", "description": "Reads the stored deep-grounding pack for a topic and market (CEP map states, related CEP runs, KG nodes and sentences with evidence grades, sufficiency verdict, credits). Returns {found:false} when none exists. Use full=1 for the whole pack as the UI does. 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": "q", "in": "query", "required": true, "description": "Topic label.", "schema": {"type": "string"}}, {"name": "gl", "in": "query", "required": false, "description": "Market code.", "schema": {"type": "string", "enum": ["kr", "jp", "us"], "default": "kr"}}, {"name": "full", "in": "query", "required": false, "description": "'1' returns the full pack including sentences; otherwise a summary.", "schema": {"type": "string", "enum": ["1", "0"], "default": "1"}}]}}, "/api/icss/grounding/list": {"get": {"operationId": "list_grounding_packs", "summary": "List grounding packs", "description": "Lists all stored grounding packs: {items:[{topic, gl, built_at, sufficiency, stats, 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)"}}}}, "/api/icss/ground": {"post": {"operationId": "build_grounding_pack_new", "summary": "Build grounding pack with new builds", "description": "Same as build_grounding_pack but also starts a new CEP Finder build (cep_build) and/or a new Intent KG build (kg_build) when stored runs are missing. Requires confirm_credits=true, which this tool sends. Returns {job_id}; poll get_grounding_job. 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: Data API credits: CEP deep 66,000-133,000, standard about 30,000-40,000; KG 38,000-46,000. Time: several minutes to tens of minutes. Usually followed by: get_grounding_job.", "tags": ["run"], "x-lm-kind": "run", "x-lm-cost": "Data API credits: CEP deep 66,000-133,000, standard about 30,000-40,000; KG 38,000-46,000", "responses": {"200": {"description": "Success"}, "default": {"description": "Error (application/problem+json or JSON with detail)"}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"q": {"type": "string", "description": "Topic label."}, "gl": {"type": "string", "description": "Market code.", "enum": ["kr", "jp", "us"], "default": "kr"}, "alt": {"type": "array", "description": "Up to 5 alternative names of the topic.", "items": {"type": "string"}}, "related": {"type": "array", "description": "Up to 12 related topics.", "items": {"type": "string"}}, "cep_build": {"type": "string", "description": "Depth of a new CEP build when no stored run exists; omit to reuse only. The UI offers standard and deep.", "enum": ["quick", "standard", "deep"]}, "kg_build": {"type": "boolean", "description": "Start a new Intent KG build when no matching KG exists.", "default": false}, "related_max": {"type": "integer", "description": "Max related topics to pull in (1-20). Server default 8 when omitted; the UI sends its field value (default 10). 0 is treated as 8.", "default": 8, "minimum": 1, "maximum": 20}}, "required": ["q"]}}}}}}, "/api/icss/ground/job/{job_id}": {"get": {"operationId": "get_grounding_job", "summary": "Check grounding job", "description": "Returns the grounding job: status (running, done, error), stage (start, cep, kg, related, assemble), steps log, and a pack summary when done. Repeat until done or error, then call get_grounding_pack with full=1. Read only, free. Waits up to about 45 s for 'status' to reach done, error; call again if not done. Usually followed by: get_grounding_pack.", "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": "job_id", "in": "path", "required": true, "description": "Job id from build_grounding_pack.", "schema": {"type": "string"}}]}}, "/api/llm": {"post": {"operationId": "ask_llm", "summary": "Call the LLM (survey, FGD, questions)", "description": "Sends one prompt to the server LLM chain (Gemini first, then OpenAI on failure; 75 s limit per provider) and returns {text, provider}. The UI builds every synthetic-respondent prompt in the browser (state-first persona: CEP, nano intent, KBF, constraint, avoidance, consideration, journey, then demography as reference) and calls this for question suggestions, survey batches, open-answer theming, FGD turns and summaries. An agent must build those prompts itself. 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 paid LLM call (Gemini 2.5 Flash by default). Time: 5-75 seconds.", "tags": ["run"], "x-lm-kind": "run", "x-lm-cost": "one paid LLM call (Gemini 2.5 Flash by default)", "responses": {"200": {"description": "Success"}, "default": {"description": "Error (application/problem+json or JSON with detail)"}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"prompt": {"type": "string", "description": "Full prompt text."}, "nothink": {"type": "boolean", "description": "Disable Gemini thinking tokens (UI sets true for jp and us markets so long batches are not cut off).", "default": false}}, "required": ["prompt"]}}}}}}, "/api/runs/{run_id}": {"put": {"operationId": "save_run", "summary": "Save a story (run snapshot)", "description": "Saves a full session snapshot (data, panel, questions, results, FGD log, chats) on the server so it opens at /#run=<id> on any PC. The UI does this automatically after a survey finishes. The id must match run_<letters/digits/_ 6-64>. Body limit 25 MB. Returns {ok, id, bytes}. 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": "run_id", "in": "path", "required": true, "description": "New id like run_<timestamp>_<random6>.", "schema": {"type": "string"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"cur": {"type": "object", "description": "Current dataset object; must contain q (topic) and locale."}, "q": {"type": "string", "description": "Topic shown in the archive."}, "locale": {"type": "string", "description": "Market code.", "enum": ["kr", "jp", "us"]}, "label": {"type": "string", "description": "Panel label shown in the archive."}, "n": {"type": "integer", "description": "Number of respondents."}, "mode": {"type": "string", "description": "Result mode, 'llm' or 'sim'."}, "at": {"type": "string", "description": "ISO time of the results."}, "savedAt": {"type": "string", "description": "ISO time saved."}, "panel": {"type": "array", "description": "Synthetic respondents with state vectors.", "items": {"type": "object"}}, "panelMeta": {"type": "object", "description": "Panel conditions: {source (market|icss|group...), label, groupName, groupCtx, cond:{target: market|group, method: random|enumerate, n (random mode), tau (enumerate threshold as a fraction, 0.01 = 1%), depth (extra respondents per state), seed, groupId, groupLabel}}. These are the browser-side run settings; record them so stories can be compared."}, "questions": {"type": "array", "description": "Survey questions.", "items": {"type": "object"}}, "results": {"type": "object", "description": "Survey results."}, "fgd": {"type": "object", "description": "FGD state {participants, log, round}."}, "chatLogs": {"type": "object", "description": "1:1 chat logs by respondent id."}, "gateLog": {"type": "array", "description": "Hallucination gate log.", "items": {"type": "object"}}, "dba": {"type": "array", "description": "Ids of brand-asset tests linked to this story.", "items": {"type": "string"}}}, "required": ["cur"]}}}}}, "get": {"operationId": "get_run", "summary": "Open a saved story", "description": "Returns the full saved snapshot of a story (cur, panel, questions, results, fgd, chatLogs, gateLog, dba). 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": "Story id (run_...).", "schema": {"type": "string"}}]}, "delete": {"operationId": "delete_run", "summary": "Delete a story", "description": "Moves a saved story to the server trash; it disappears from every PC's archive. Returns {ok, id}. 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": "run_id", "in": "path", "required": true, "description": "Story id (run_...).", "schema": {"type": "string"}}]}}, "/api/runs": {"get": {"operationId": "list_runs", "summary": "List saved stories", "description": "Lists stories saved on the server, newest first: {runs:[{id, q, locale, label, n, mode, at, panelMeta, hasResults, fgdN, chatN, bytes}], total}. Read only, free. Usually followed by: get_run.", "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/dba/mask-check": {"post": {"operationId": "check_asset_masking", "summary": "Check brand-asset masking", "description": "Brand asset test (DBA) step 1: checks that each asset description contains no target or competitor brand name and, for images, transcribes visible text with a vision model to detect brand names. Returns {assets:[{id, img}], checks:[{id, ok, textLeaks, imageText, imageLeaks, note}]}. Uploaded data-URL images are stored and replaced by /api/dba/img paths. 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 vision LLM call per image asset; text-only assets are free. Usually followed by: start_dba_ai_test.", "tags": ["run"], "x-lm-kind": "run", "x-lm-cost": "one vision LLM call per image asset; text-only assets are 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": {"category": {"type": "string", "description": "Product category shown as context, e.g. 'coffee chain' (max 60 chars)."}, "locale": {"type": "string", "description": "Market of the test.", "enum": ["kr", "jp", "us"], "default": "kr"}, "brand": {"type": "object", "description": "Target brand: {name (required), aliases: [string] up to 10, parents: [string] up to 5 (parent company names, coded separately, not counted as fame)}.", "properties": {"name": {"type": "string", "description": "Brand name."}, "aliases": {"type": "array", "description": "Other spellings of the brand.", "items": {"type": "string"}}, "parents": {"type": "array", "description": "Parent company names.", "items": {"type": "string"}}}, "required": ["name"]}, "competitors": {"type": "array", "description": "Competitor brands, up to 30: [{name, aliases: [string]}]. Needed when prompted=true.", "items": {"type": "object", "properties": {"name": {"type": "string"}, "aliases": {"type": "array", "items": {"type": "string"}}}}}, "catHint": {"type": "boolean", "description": "Tell the respondent the category (default true).", "default": true}, "prompted": {"type": "boolean", "description": "Show the brand list as answer options (prompted recall). Default false (unprompted).", "default": false}, "assets": {"type": "array", "description": "Masked brand assets, 1 to 20: [{id, type (colour|shape|logo|character|celebrity|tagline|sound|font|pack|other), label, desc (text description without brand names, max 600 chars), img (data URL png/jpeg/webp/gif up to 5 MB, or a stored /api/dba/img/<name> path), control (true for the placebo baseline asset)}]. Each asset needs desc or img.", "items": {"type": "object", "properties": {"id": {"type": "string"}, "type": {"type": "string", "enum": ["colour", "shape", "logo", "character", "celebrity", "tagline", "sound", "font", "pack", "other"]}, "label": {"type": "string"}, "desc": {"type": "string"}, "img": {"type": "string"}, "control": {"type": "boolean"}}}}}, "required": ["brand", "assets"]}}}}}}, "/api/dba/ai-test": {"post": {"operationId": "start_dba_ai_test", "summary": "Start AI-response asset test", "description": "Brand asset test, AI-response mode: asks Gemini and OpenAI directly (no persona) 'which brand is this?' for every masked asset, reps times per model, then scores fame and uniqueness on first-mentioned brand and saves the test. This is a GEO metric, not consumer response. Returns {job}; poll get_dba_job. 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: paid LLM calls = assets x models x reps (e.g. 6 x 2 x 5 = 60); no Data API credits. Time: 1-5 minutes. Usually followed by: get_dba_job.", "tags": ["run"], "x-lm-kind": "run", "x-lm-cost": "paid LLM calls = assets x models x reps (e.g. 6 x 2 x 5 = 60); no Data API credits", "responses": {"200": {"description": "Success"}, "default": {"description": "Error (application/problem+json or JSON with detail)"}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"category": {"type": "string", "description": "Product category shown as context, e.g. 'coffee chain' (max 60 chars)."}, "locale": {"type": "string", "description": "Market of the test.", "enum": ["kr", "jp", "us"], "default": "kr"}, "brand": {"type": "object", "description": "Target brand: {name (required), aliases: [string] up to 10, parents: [string] up to 5 (parent company names, coded separately, not counted as fame)}.", "properties": {"name": {"type": "string", "description": "Brand name."}, "aliases": {"type": "array", "description": "Other spellings of the brand.", "items": {"type": "string"}}, "parents": {"type": "array", "description": "Parent company names.", "items": {"type": "string"}}}, "required": ["name"]}, "competitors": {"type": "array", "description": "Competitor brands, up to 30: [{name, aliases: [string]}]. Needed when prompted=true.", "items": {"type": "object", "properties": {"name": {"type": "string"}, "aliases": {"type": "array", "items": {"type": "string"}}}}}, "catHint": {"type": "boolean", "description": "Tell the respondent the category (default true).", "default": true}, "prompted": {"type": "boolean", "description": "Show the brand list as answer options (prompted recall). Default false (unprompted).", "default": false}, "assets": {"type": "array", "description": "Masked brand assets, 1 to 20: [{id, type (colour|shape|logo|character|celebrity|tagline|sound|font|pack|other), label, desc (text description without brand names, max 600 chars), img (data URL png/jpeg/webp/gif up to 5 MB, or a stored /api/dba/img/<name> path), control (true for the placebo baseline asset)}]. Each asset needs desc or img.", "items": {"type": "object", "properties": {"id": {"type": "string"}, "type": {"type": "string", "enum": ["colour", "shape", "logo", "character", "celebrity", "tagline", "sound", "font", "pack", "other"]}, "label": {"type": "string"}, "desc": {"type": "string"}, "img": {"type": "string"}, "control": {"type": "boolean"}}}}, "providers": {"type": "array", "description": "Models to ask.", "items": {"type": "string", "enum": ["gemini", "openai"]}, "default": ["gemini", "openai"]}, "reps": {"type": "integer", "description": "Repeats per model per asset (1-20). More repeats give more stable fame and uniqueness.", "default": 5, "minimum": 1, "maximum": 20}, "force": {"type": "boolean", "description": "Run assets that failed masking too (marked maskOverride).", "default": false}}, "required": ["brand", "assets"]}}}}}}, "/api/dba/job/{job_id}": {"get": {"operationId": "get_dba_job", "summary": "Check asset test job", "description": "Returns {id, status (running, done, error), done, total, error, testId} and, when done, the full scored test. Repeat until done or error. Read only, free. Waits up to about 45 s for 'status' to reach done, error; call again if not done.", "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": "job_id", "in": "path", "required": true, "description": "Job id from start_dba_ai_test.", "schema": {"type": "string"}}]}}, "/api/dba/ask": {"post": {"operationId": "ask_dba_llm", "summary": "Call vision LLM for synthetic asset test", "description": "One vision-capable LLM call used by the synthetic-panel asset test: the UI sends a batch prompt built from ICSS personas plus up to 4 images and parses brand answers. Returns {text, provider, model}. 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 paid LLM call. Usually followed by: score_dba_synthetic.", "tags": ["run"], "x-lm-kind": "run", "x-lm-cost": "one paid LLM call", "responses": {"200": {"description": "Success"}, "default": {"description": "Error (application/problem+json or JSON with detail)"}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"prompt": {"type": "string", "description": "Prompt text."}, "images": {"type": "array", "description": "Up to 4 images as data URLs or /api/dba/img/<name> paths.", "items": {"type": "string"}}, "temperature": {"type": "number", "description": "Sampling temperature.", "default": 1}, "provider": {"type": "string", "description": "Force one provider; default tries gemini then openai.", "enum": ["gemini", "openai"]}, "json": {"type": "boolean", "description": "Ask the model for JSON output.", "default": false}}, "required": ["prompt"]}}}}}}, "/api/dba/score": {"post": {"operationId": "score_dba_synthetic", "summary": "Score and save synthetic asset test", "description": "Scores synthetic-panel answers (fame, uniqueness, quadrant, baseline) and saves the test. Send the same test fields plus responses collected with ask_dba_llm. Returns {test}. 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": {"category": {"type": "string", "description": "Product category shown as context, e.g. 'coffee chain' (max 60 chars)."}, "locale": {"type": "string", "description": "Market of the test.", "enum": ["kr", "jp", "us"], "default": "kr"}, "brand": {"type": "object", "description": "Target brand: {name (required), aliases: [string] up to 10, parents: [string] up to 5 (parent company names, coded separately, not counted as fame)}.", "properties": {"name": {"type": "string", "description": "Brand name."}, "aliases": {"type": "array", "description": "Other spellings of the brand.", "items": {"type": "string"}}, "parents": {"type": "array", "description": "Parent company names.", "items": {"type": "string"}}}, "required": ["name"]}, "competitors": {"type": "array", "description": "Competitor brands, up to 30: [{name, aliases: [string]}]. Needed when prompted=true.", "items": {"type": "object", "properties": {"name": {"type": "string"}, "aliases": {"type": "array", "items": {"type": "string"}}}}}, "catHint": {"type": "boolean", "description": "Tell the respondent the category (default true).", "default": true}, "prompted": {"type": "boolean", "description": "Show the brand list as answer options (prompted recall). Default false (unprompted).", "default": false}, "assets": {"type": "array", "description": "Masked brand assets, 1 to 20: [{id, type (colour|shape|logo|character|celebrity|tagline|sound|font|pack|other), label, desc (text description without brand names, max 600 chars), img (data URL png/jpeg/webp/gif up to 5 MB, or a stored /api/dba/img/<name> path), control (true for the placebo baseline asset)}]. Each asset needs desc or img.", "items": {"type": "object", "properties": {"id": {"type": "string"}, "type": {"type": "string", "enum": ["colour", "shape", "logo", "character", "celebrity", "tagline", "sound", "font", "pack", "other"]}, "label": {"type": "string"}, "desc": {"type": "string"}, "img": {"type": "string"}, "control": {"type": "boolean"}}}}, "responses": {"type": "array", "description": "Answers: [{asset (asset id), rid (respondent id), brands: [up to 3 brand names, first = first mentioned], provider, model}].", "items": {"type": "object"}}, "meta": {"type": "object", "description": "Panel info: {runId, topic, panelLabel, panelSource, panelN, respondents, failedBatches, models}."}}, "required": ["brand", "assets", "responses"]}}}}}}, "/api/dba/tests": {"get": {"operationId": "list_dba_tests", "summary": "List brand-asset tests", "description": "Lists saved brand-asset tests with per-asset fame, uniqueness and quadrant. Filter by brand (exact name or alias), locale and kind. Returns {tests, total, providers}. 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": "brand", "in": "query", "required": false, "description": "Brand name or alias.", "schema": {"type": "string"}}, {"name": "locale", "in": "query", "required": false, "description": "Market code.", "schema": {"type": "string", "enum": ["kr", "jp", "us"]}}, {"name": "kind", "in": "query", "required": false, "description": "Respondent type.", "schema": {"type": "string", "enum": ["ai", "synthetic"]}}]}}, "/api/dba/tests/{test_id}": {"get": {"operationId": "get_dba_test", "summary": "Open a brand-asset test", "description": "Returns one saved test in full: brand, assets, responses, per-asset results, baseline, disclaimer. 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": "test_id", "in": "path", "required": true, "description": "Test id like dba_ai_<ts>_<hex6> or dba_syn_<ts>_<hex6>.", "schema": {"type": "string"}}]}}, "/api/dba/img/{name}": {"get": {"operationId": "get_dba_image", "summary": "Download stimulus image", "description": "Downloads a stored stimulus image referenced by a test asset (img field /api/dba/img/<name>). 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": "name", "in": "path", "required": true, "description": "File name: 24 hex chars plus .png, .jpg, .webp or .gif.", "schema": {"type": "string"}}]}}}, "externalDocs": {"url": "https://daas-icss.listeningmind.ai/agents.md", "description": "Agent guide"}}