> ## Documentation Index
> Fetch the complete documentation index at: https://docs.oppin.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Tools

> Every tool the Oppin MCP server offers, with its arguments.

Your AI app picks these tools on its own when you ask a question, so you never need to name one. This page lists all 47 of them for anyone building on Oppin, or curious what a connection can reach. Each description is the one your app reads when it decides which tool to call.

28 tools only read. The other 19 change what Oppin tracks and work only on a connection approved with write access (see [Access and safety](https://docs.oppin.ai/mcp/overview.md#access-and-safety)). Most apps show each tool call as it runs: expand it to see the arguments your app chose.

For ready-made analyses that chain several tools in a fixed order, see [Commands](https://docs.oppin.ai/mcp/commands.md).

## Arguments most tools share

Names work as well as ids everywhere: a brand, a competitor, a topic, an AI engine (`ChatGPT`) or a country (`Spain` or `ES`). When `period` is left out, a tool reads the last 30 days.

| Argument | What it does |
| :- | :- |
| `brand` | Brand name or id. Optional when the organization tracks a single brand. |
| `period` | 7d, 30d, 3m, 1y, or custom:YYYY-MM-DD:YYYY-MM-DD (both days inclusive, UTC). |
| `models` | Comma-separated AI engines to limit to, e.g. 'ChatGPT,Perplexity'. Omit for all. |
| `countries` | Comma-separated countries or ISO codes, e.g. 'US,ES'. A US state narrows the US to the prompts asked from it, e.g. 'Texas' or 'US-TX' ('US-NATIONWIDE' = asked with no state). Omit for all. |
| `topics` | Comma-separated topic names or ids. Omit for all. |
| `tags` | Comma-separated tag names or ids. Omit for all. |

## Start here

Who the connection belongs to, which brands it reads, and the filters each brand offers.

### `whoami`

*Read only*

Confirm which Oppin organization this connection can read, list its brands, and show the plan's limits next to what is in use.

Call this first in a new conversation: it returns the brand names and ids every other tool takes, whether this connection may change anything or only read, and the headroom under `usage` (brands, active prompts and answers this month against the plan's limits, org-wide, plus the Claude add-on's prompts and answers). Check it before adding prompts or competitors in bulk.

Takes no arguments.

### `list_brands`

*Read only*

List the brands (trackers) in this organization, with their ids, websites and aliases.

Takes no arguments.

### `describe_brand`

*Read only*

Everything needed to filter a brand's data: its tracked AI engines, countries, topics, tags and competitors.

Use this once before a series of analysis calls so later tools can be filtered precisely.

**Also takes:** `brand`.

### `get_portfolio_summary`

*Read only*

Every brand in the organization in one call: Brand Strength, visibility, share of voice, position, top-3 rate, sentiment and mentions for the period and the previous one, each brand's rank among its own competitors, and its strongest competitor.

The agency view: use it for a portfolio report or to spot which client brands are slipping, instead of one call per brand. Engine and country filters apply to every brand; topics and tags belong to one brand, so use the per-brand tools for those. `limited_data` marks brands with fewer than six mentions, whose rank is not firm.

**Also takes:** `period`, `models`, `countries`.

| Argument | Type | What it does |
| :- | :- | :- |
| `limit` | number | Brands to return. Default 25, maximum 50; page with offset. |
| `offset` | number | Brands to skip, for paging. |

## Visibility and competitors

Where the brand stands and who it is up against.

### `get_visibility_summary`

*Read only*

Headline AI-visibility numbers for a brand: Brand Strength (the Oppin Index), visibility, share of voice, sentiment, the brand ranking, and the top cited sources.

This is the right first call for "how are we doing in AI search". Brand Strength is a 0-100 composite of visibility (40%), share of voice (30%), top-3 rate (20%) and sentiment (10%), shrunk by an evidence factor so brands with very few mentions do not score highly on noise. A sentiment of -1 means no sentiment data, not negative sentiment.

**Also takes:** `brand`, `period`, `models`, `countries`, `topics`, `tags`.

### `get_brand_trend`

*Read only*

Daily time series for the brand's own seven metrics: Brand Strength, share of voice, top-3 rate, sentiment, visibility, mentions and average position.

Own brand only. For a competitor's daily series use [`get_table`](#get_table) with table='brand\_daily'.

**Also takes:** `brand`, `period`, `models`, `countries`, `topics`, `tags`.

### `get_competitor_scoreboard`

*Read only*

Every tracked brand and competitor with its full metric row and the change versus the previous period.

The authoritative comparison table. Share of voice is answer-level (a brand counts once per AI answer), so it cannot be reproduced by counting mention rows.

**Also takes:** `brand`, `period`, `models`, `countries`, `topics`, `tags`.

### `get_model_breakdown`

*Read only*

Brand Strength, visibility, share of voice, top-3 rate, sentiment and mentions for every tracked brand on every AI engine, in every country, within every topic and in every US state the brand targets.

Use this to answer "why is our visibility different on ChatGPT than on Perplexity", to find the engines, markets or topics where a competitor beats us, and to build a topic heatmap. Each cell's Brand Strength is shrunk by that cell's own mention count, so treat cells with few mentions as indicative. Engines, countries, topics or states with no data in the period are left out; the state split exists only for a brand with state-targeted US prompts, and NATIONWIDE there is the US answers asked with no state.

**Also takes:** `brand`, `period`, `models`, `countries`, `topics`, `tags`.

| Argument | Type | What it does |
| :- | :- | :- |
| `dimension` | text | model (AI engine), country, topic or state (US state), to return only that split. Default: all of them. |

### `get_share_of_voice`

*Read only*

Share of voice for every brand, broken down by AI engine, country and topic.

Share of voice is answer-level: a brand counts once per answer it appears in, and the denominator includes every brand mentioned, tracked or not.

**Also takes:** `brand`, `period`, `models`, `countries`, `topics`, `tags`.

### `get_prompt_scoreboard`

*Read only*

Prompt by prompt, how the brand compares with its competitors: each brand's visibility, share of voice, average position, top-3 rate and sentiment within that prompt's AI answers, plus the top competitor and the visibility gap.

Use this for "which prompts are we losing", "where is our visibility lowest" and "how do we compare with X prompt by prompt". Visibility is the share of that prompt's answers mentioning the brand; `visibility_gap` is the top competitor's visibility minus the brand's, in points (positive = a competitor is ahead). The brand is always first in `brands`, at 0 when absent, and prompts whose answers named no tracked brand are included. Only tracked competitors are scored, the top three per prompt unless you name them; untracked brands still count toward share of voice. `models` on a brand lists the engines it appeared on for that prompt.

**Also takes:** `brand`, `period`, `models`, `countries`, `topics`, `tags`.

| Argument | Type | What it does |
| :- | :- | :- |
| `competitors` | text | Comma-separated competitor names or ids to compare against. Omit for every tracked competitor. |
| `sort` | text | gap (default): prompts where a competitor leads by the most first. visibility: the brand's lowest visibility first. answers: the busiest prompts first. |
| `only_gaps` | true or false | Only prompts where a competitor's visibility is above the brand's. Default false. |
| `limit` | number | Prompts to return. Default 25, maximum 50; page with offset. |
| `offset` | number | Prompts to skip, for paging. |

### `get_suggested_competitors`

*Read only*

Brands the AI answers name that this brand does not track yet, most mentioned first: the candidates for new competitors.

Only brands named at least twice in the period, and never the brand itself or a competitor already tracked or on the watchlist (in any alias form). `mentions` counts mention rows. To start tracking one, use [`add_competitor`](#add_competitor) with its real domain.

**Also takes:** `brand`, `period`, `models`, `countries`, `topics`, `tags`.

| Argument | Type | What it does |
| :- | :- | :- |
| `limit` | number | Rows to return. Default 25, maximum 200. |
| `offset` | number | Rows to skip, for paging. |

## Mentions and answers

How AI talks about the brand, down to each answer.

### `get_mentions_summary`

*Read only*

How often and how favourably AI answers mention the brand: mention count, average position, average sentiment, model reach and the sentiment distribution.

**Also takes:** `brand`, `period`, `models`, `countries`, `topics`, `tags`.

### `get_brand_associations`

*Read only*

The words and phrases AI models use when they describe this brand, ranked by how distinctive they are.

Pass `concept` to drill into one of them and see the prompts, engines and snippets it came from.

**Also takes:** `brand`, `period`, `models`, `countries`, `topics`, `tags`.

| Argument | Type | What it does |
| :- | :- | :- |
| `concept` | text | Optional: a single word or phrase to drill into, returning the answers it appears in. |

### `list_answers`

*Read only*

List the individual AI answers collected for this brand, with each one's prompt, topic, engine, the brand's position and tone, and the brands it named in order.

Use `segment`, `sentiments` and `sort` to go straight to the problem answers, e.g. the three most negative: sort='sentiment', order='asc', limit=3. Call [`get_answer`](#get_answer) for the full text of one.

**Also takes:** `brand`, `period`, `models`, `countries`, `topics`, `tags`.

| Argument | Type | What it does |
| :- | :- | :- |
| `segment` | text | all (default), mentioned, missing (brand absent), outside\_top\_3 (mentioned, never ranked 1-3), negative (a negative mention of the brand), or no\_brands (the answer named no brand at all). |
| `sentiments` | text | The brand's tone in the answer, comma-separated: positive, neutral, negative. |
| `positions` | text | The brand's exact best rank in the answer, comma-separated, e.g. '1' or '4,5,6'. |
| `mentions_brands` | text | Only answers naming any of these brands, comma-separated (e.g. a competitor). |
| `search` | text | Free-text search over the prompt, the engine and mentioned brands. |
| `sort` | text | date (default), sentiment (the brand's tone; with order='asc' the most negative first), position (the brand's rank), brands (how many brands it named), model, country or prompt. |
| `order` | text | desc (default) or asc. |
| `limit` | number | Rows to return. Default 25, maximum 200. |
| `page` | number | Page number, from 1, for paging past `limit` rows. |

### `get_answer`

*Read only*

The full text of one AI answer (markdown, with its inline citation links), with its prompt, engine, country, the brand's position and tone, every brand mention with the source cited for it, the sources, and the fan-out queries.

**Also takes:** `brand`.

| Argument | Type | What it does |
| :- | :- | :- |
| `result_id` | number | The answer's answer\_id, from [`list_answers`](#list_answers) or [`get_source_usage`](#get_source_usage). Required. |

## Sources

The sites and pages AI reads and cites.

### `get_sources_summary`

*Read only*

What AI engines read and cite when they answer this brand's prompts: source counts, own-site share, the source-type mix and how fresh the cited pages are.

Source classification runs hourly, so a share of sources may be reported as unclassified rather than miscellaneous. Treat that as pending, not as a category.

**Also takes:** `brand`, `period`, `models`, `countries`, `topics`, `tags`.

### `list_source_domains`

*Read only*

The domains AI engines use as sources for this brand's prompts, ranked, with each one's type, the brands its pages mention, and the previous period alongside.

Filter by site type (e.g. News / Media, UGC / Forum), page format (e.g. Listicle), specific prompts, or segment=mention\_gaps for the sites that talk about competitors and not the brand. `total` and `has_more` say whether to page further.

**Also takes:** `brand`, `period`, `models`, `countries`, `topics`, `tags`.

| Argument | Type | What it does |
| :- | :- | :- |
| `prompt_ids` | list of numbers | Only count the answers to these prompts (ids from [`get_prompt_scoreboard`](#get_prompt_scoreboard), [`list_answers`](#list_answers) or [`get_table('prompts')`](#get_table)). Answers "which sources does AI use for this question". |
| `search` | text | Filter to domains containing this text. |
| `segment` | text | all (default); citation\_gaps: sources that cite a competitor but not the brand; mention\_gaps: pages whose content names a competitor but not the brand. |
| `domain_types` | text | Comma-separated site types: News / Media, Corporate / Product, Retail / E-commerce, Social Media, UGC / Forum, Blogs, Reference, Educational, Government / Institutional, Others. 'News' or 'UGC' work too. |
| `page_formats` | text | Comma-separated page formats: Article, Listicle, Comparison, Review, How-to, Product, Forum, Homepage, Other. Pages not analyzed yet have no format and are left out when this is set. |
| `cited` | text | 'yes' for sources actually cited in the answer text, 'no' for read but not cited. |
| `cited_you` | text | 'yes' for sources that backed a mention of the brand, 'no' for the rest. |
| `sort` | text | used (default: how often AI read it), cited (COUNT of times its link appeared in answers: use this for 'most cited'), coverage (share of answers that used it), surfaced (PERCENT of its retrievals that were cited, so a source read once and cited once ranks first), cited\_you (cited for the brand's own mentions), source (A-Z). |
| `order` | text | desc (default) or asc. |
| `limit` | number | Rows to return. Default 25, maximum 200. |
| `page` | number | Page number, from 1, for paging past `limit` rows. |

### `list_source_pages`

*Read only*

The individual pages AI engines use as sources, with their titles, publish dates, page formats, the brands they mention, and the previous period alongside.

Pass prompt\_ids for the pages AI reads when answering specific prompts, page\_formats='Listicle' for the list articles, or domain for one site's pages (your own domain shows which of your pages AI reads). Pair with [`get_source_content`](#get_source_content) to read what a page says, and [`get_source_usage`](#get_source_usage) for the prompts a page is used for.

**Also takes:** `brand`, `period`, `models`, `countries`, `topics`, `tags`.

| Argument | Type | What it does |
| :- | :- | :- |
| `prompt_ids` | list of numbers | Only count the answers to these prompts (ids from [`get_prompt_scoreboard`](#get_prompt_scoreboard), [`list_answers`](#list_answers) or [`get_table('prompts')`](#get_table)). Answers "which sources does AI use for this question". |
| `domain` | text | Restrict to one domain, e.g. 'reddit.com'. |
| `search` | text | Filter to URLs containing this text. |
| `segment` | text | all (default); citation\_gaps: sources that cite a competitor but not the brand; mention\_gaps: pages whose content names a competitor but not the brand. |
| `domain_types` | text | Comma-separated site types: News / Media, Corporate / Product, Retail / E-commerce, Social Media, UGC / Forum, Blogs, Reference, Educational, Government / Institutional, Others. 'News' or 'UGC' work too. |
| `page_formats` | text | Comma-separated page formats: Article, Listicle, Comparison, Review, How-to, Product, Forum, Homepage, Other. Pages not analyzed yet have no format and are left out when this is set. |
| `cited` | text | 'yes' for sources actually cited in the answer text, 'no' for read but not cited. |
| `cited_you` | text | 'yes' for sources that backed a mention of the brand, 'no' for the rest. |
| `sort` | text | used (default: how often AI read it), cited (COUNT of times its link appeared in answers: use this for 'most cited'), coverage (share of answers that used it), surfaced (PERCENT of its retrievals that were cited, so a source read once and cited once ranks first), cited\_you (cited for the brand's own mentions), source (A-Z). |
| `order` | text | desc (default) or asc. |
| `limit` | number | Rows to return. Default 25, maximum 200. |
| `page` | number | Page number, from 1, for paging past `limit` rows. |

### `get_source_usage`

*Read only*

Which of this brand's prompts a source is used for: pass one page's url, or a domain for the whole site.

Per prompt: how many answers used the source (`answers`), in how many it was cited in the answer text (`answers_cited`) and backed a mention of the brand (`answers_citing_you`), on which engines, when it was last used, and the latest answer id (open it with [`get_answer`](#get_answer)). `uses` counts every time it was read, like [`list_source_pages`](#list_source_pages)' `used`. Use it to see what questions a page is retrieved for, or to check a content refresh by comparing two periods.

**Also takes:** `brand`, `period`, `models`, `countries`, `topics`, `tags`.

| Argument | Type | What it does |
| :- | :- | :- |
| `url` | text | One page, exactly as [`list_source_pages`](#list_source_pages) returns it. |
| `domain` | text | A whole site, e.g. 'reddit.com'. Give url or domain, not both. |
| `limit` | number | Rows to return. Default 25, maximum 200. |
| `offset` | number | Prompts to skip, for paging. |

### `get_source_content`

*Read only*

Read the extracted text of a page AI engines cite, plus its title, publish date, page format and which brands appear on it.

Use this to compare what a cited page says with what the AI answer claimed, or to find pages carrying outdated information about the brand. Only pages among this organization's own sources can be read.

| Argument | Type | What it does |
| :- | :- | :- |
| `url` | text | The exact source URL, as returned by [`list_source_pages`](#list_source_pages). Required. |
| `max_length` | number | Characters of page text to return. Default 8000. |

### `get_source_gaps`

*Read only*

Domains that cite competitors but not this brand: the outreach and content targets with the clearest evidence behind them.

**Also takes:** `brand`, `period`, `models`, `countries`, `topics`, `tags`.

## Query fan-out

The fan-out queries AI engines run before they answer.

### `list_fanout_queries`

*Read only*

The fan-out queries AI engines actually ran behind this brand's prompts, one row per unique query: how often, on which engines, its intents, whether the brand surfaced, which competitors did, and whether it is new or rising.

Fan-out is the layer under the prompt: it shows the real search intent a model expanded into, which is where content gaps show up before they show up in the answer. Pass prompt\_ids for the fan-out queries behind specific questions, intents to focus on a buying stage (e.g. comparison, alternatives, price\_sensitive), captured='no' for the gaps, and trend='new,rising' for emerging demand. Intents are matched on the query's English wording, not inferred, so queries in other languages mostly read 'other': judge those from the text itself. Only engines that expose their fan-out queries (ChatGPT, Perplexity, Claude) produce them. `total` and `has_more` say whether to page further.

**Also takes:** `brand`, `period`, `models`, `countries`, `topics`, `tags`.

| Argument | Type | What it does |
| :- | :- | :- |
| `prompt_ids` | list of numbers | Only the fan-out queries behind these prompts' answers (ids from [`get_prompt_scoreboard`](#get_prompt_scoreboard), [`list_answers`](#list_answers) or [`get_table('prompts')`](#get_table)). Answers "what does AI search for when it answers this question". |
| `search` | text | Filter to queries containing this text. |
| `captured` | text | 'yes' for queries where the brand surfaced, 'no' for the gaps. |
| `intents` | text | Comma-separated search intents, any of: ranking, comparison, segmentation, price\_sensitive, how\_to, review, feature\_specific, use\_case, problem\_solution, alternatives, location\_based, temporal, question\_based, transactional, navigational, other. A query can carry several. |
| `trend` | text | 'new' (first seen this period), 'rising' (ran more often than in the previous period), or both. |
| `sort` | text | volume (default: how often AI ran it), trend (new first, then rising), captured, last\_seen, or query (A-Z). |
| `order` | text | desc (default) or asc. |
| `limit` | number | Rows to return. Default 25, maximum 200. |
| `page` | number | Page number, from 1, for paging past `limit` rows. |

## Recommendations

Oppin's growth actions and where each one stands.

### `list_opportunities`

*Read only*

The growth recommendations Oppin generated for this brand, newest first.

These are produced from the brand's own answer, mention and source data rather than generic advice. Call [`get_opportunity`](#get_opportunity) for the full playbook behind one.

**Also takes:** `brand`.

| Argument | Type | What it does |
| :- | :- | :- |
| `category` | text | 'owned' (your own site and content) or 'earned' (third-party). |
| `impact` | text | low, medium or high. |
| `status` | text | new, viewed, completed or dismissed. Omit to see everything except dismissed. |

### `get_opportunity`

*Read only*

The full detail of one recommendation: why it was raised, the evidence from this brand's data, and the steps to act on it.

| Argument | Type | What it does |
| :- | :- | :- |
| `opportunity_id` | number | The opportunity id, from [`list_opportunities`](#list_opportunities). Required. |

### `set_opportunity_status`

*Needs write access*

Mark a recommendation as viewed, completed or dismissed.

Marking one viewed is a side effect of reading it and needs no write access. Completing or dismissing is workflow and does. Completed is final: a completed recommendation cannot be moved back.

| Argument | Type | What it does |
| :- | :- | :- |
| `opportunity_id` | number | The opportunity id, from [`list_opportunities`](#list_opportunities). Required. |
| `status` | text | viewed, completed or dismissed. Required. |

## Raw tables

The tables behind the [data export](https://docs.oppin.ai/data-model.md), for anything the tools above do not cover.

### `list_tables`

*Read only*

List the raw analytics tables [`get_table`](#get_table) can return, with what one row of each means and how they join.

Returns an index by default. Pass `table` for one table's full column list with types and descriptions. Use this when no other tool covers the question and you want the underlying rows.

| Argument | Type | What it does |
| :- | :- | :- |
| `table` | text | Optional: one table name, to get its full column list instead of the index. |

### `get_table`

*Read only*

Rows from one of Oppin's analytics tables, paged.

The escape hatch for anything the named tools do not cover: per-brand-per-day metrics ('brand\_daily'), raw mentions, raw sources, the prompt library, and more. Always prefer a named tool when one fits, because these tables are wide.

**Also takes:** `brand`, `period`, `models`, `countries`, `topics`, `tags`.

| Argument | Type | What it does |
| :- | :- | :- |
| `table` | text | One of the table names from [`list_tables`](#list_tables), e.g. 'brand\_daily'. Required. |
| `limit` | number | Rows to return. Default 25, maximum 200. |
| `offset` | number | Rows to skip, for paging through a large table. |

## Brands

Add a brand, and keep its profile current.

### `create_brand`

*Needs write access*

Add a new brand to track, with its competitors and first questions, in one step.

Only a workspace admin's connection (or a write key, which only admins can create) may add a brand, and the plan's brand and prompt limits apply. The starter questions are answered within minutes, so the new brand has data in the same conversation. Read the brand's website first and confirm the details with the user: website and competitor domains are matching keys, never guess them. Removing a brand is done by an admin in Oppin, not from here.

| Argument | Type | What it does |
| :- | :- | :- |
| `name` | text | The brand's name. Required. |
| `website` | text | The brand's own website, e.g. 'nike.com'. Required. |
| `country` | text | Its main market, name or ISO code. Prompts ask from here by default. Required. |
| `industry` | text | What it is, in a few words, e.g. 'Running shoes'. Comma-separate several. Required. |
| `prompts` | list of text | 1 to 20 starter questions a buyer would ask AI, written the way they would type them. Required. |
| `description` | text | One or two sentences on what it sells and to whom. Improves drafted prompts and recommendations. |
| `competitors` | list of valuess | Up to 20 competitors, each with its real website when known. |
| `models` | text | AI engines the starter questions run on, comma-separated. Up to 3 plan engines, plus Claude when the workspace has seats. Defaults to ChatGPT. |
| `language` | text | Language the questions are in, name or ISO code. Defaults to English. |
| `business_model` | text | B2B, B2C or Hybrid, if known. |
| `aliases` | text | Comma-separated other names AI answers use for it. |
| `state` | text | US state it serves, name or code (e.g. 'Texas'), when its market is the United States. Its starter questions ask from there. Omit for the whole country. |

### `update_brand_profile`

*Needs write access*

Update a brand's profile: name, website, main market, default US state, language, description, industry, business model and the other domains it owns.

The description and industry shape the questions Oppin drafts and the recommendations it makes; domains decide which sources count as the brand's own. Only the fields you pass change. Competitors and other names have their own tools. Can be undone with [`undo_change`](#undo_change).

**Also takes:** `brand`.

| Argument | Type | What it does |
| :- | :- | :- |
| `name` | text | Rename the brand. |
| `website` | text | Its main website, e.g. 'nike.com'. |
| `country` | text | Its main market, name or ISO code. |
| `language` | text | Its main language, name or ISO code. |
| `description` | text | What it sells and to whom, in a sentence or two. Pass an empty string to clear. |
| `industry` | text | Replace its industry, comma-separated, e.g. 'Running shoes'. |
| `business_model` | text | B2B, B2C or Hybrid. |
| `domains` | text | Replace the OTHER domains it owns (regional sites), comma-separated. Pass an empty string to clear. |
| `state` | text | Its default US state (name or code) for new prompts, or 'nationwide'. United States brands only. Existing prompts keep their own location. |

## Prompts and topics

What the brand tracks, and how it is organized.

### `create_prompts`

*Needs write access*

Start tracking one or more prompts for a brand.

Each prompt is created active. New prompts are answered within minutes, up to the plan's prompt allowance per workspace per day (`first_answers` says how many); the rest are answered at the next daily collection. Plan limits apply and a prompt that would exceed them is refused rather than silently dropped, so add in batches you can check. Claude is only available where its web search is supported; if you ask for it in an unsupported country the call is refused and names the reason. The change can be undone with [`undo_change`](#undo_change).

**Also takes:** `brand`.

| Argument | Type | What it does |
| :- | :- | :- |
| `prompts` | list of text | The prompt texts to start tracking, as a buyer would type them. Required. |
| `topic` | text | Topic name or id to file these under. Omit to leave them untopiced. |
| `models` | text | AI engines to run these on, comma-separated. Defaults to ChatGPT. |
| `country` | text | Country to ask from, name or ISO code. Defaults to the brand's own country. |
| `tags` | text | Comma-separated tag names to attach. |
| `language` | text | Language the prompts are written in, name or ISO code (e.g. 'Spanish' or 'ES'). Defaults to the brand's language. |
| `state` | text | US state to ask from, name or code (e.g. 'Texas' or 'TX'), for United States prompts. Defaults to the brand's own state when asking from the brand's country; 'nationwide' asks for the whole country. To compare states, create one prompt per state. |

### `update_prompt`

*Needs write access*

Change one tracked prompt's text, engines, country, US state or topic.

Only the fields you pass change. Switching an engine on is checked against country coverage, so a model that cannot search from this prompt's country is refused with the reason. To change the engines on many prompts at once, use [`set_prompt_models`](#set_prompt_models). Can be undone with [`undo_change`](#undo_change).

**Also takes:** `brand`.

| Argument | Type | What it does |
| :- | :- | :- |
| `prompt_id` | number | The prompt id to change. Required. |
| `text` | text | New prompt text. Omit to keep it. |
| `models` | text | Replace the AI engines it runs on. |
| `country` | text | Replace the country it asks from. |
| `topic` | text | Move it to this topic (name or id). Omit to keep its current topic; pass an empty string to remove it from one. |
| `state` | text | Replace the US state it asks from (name or code), or 'nationwide' for the whole country. United States prompts only. Omit to keep it. |

### `set_prompt_models`

*Needs write access*

Switch AI engines on or off for many tracked prompts at once, for example Claude on the prompts that matter most, or a better engine mix for one country.

Each prompt keeps its wording, country, topic and tags. Plan limits (engines per prompt), Claude seats and country coverage apply per prompt: one that cannot take the change is listed under `failed` with the reason, and a Claude seat shortage stops the batch. A prompt must keep at least one engine. Can be undone with [`undo_change`](#undo_change).

**Also takes:** `brand`.

| Argument | Type | What it does |
| :- | :- | :- |
| `prompt_ids` | list of numbers | Prompt ids, from [`get_table('prompts')`](#get_table), [`get_prompt_scoreboard`](#get_prompt_scoreboard) or [`list_answers`](#list_answers). Required. |
| `models` | text | AI engines, comma-separated, e.g. 'Claude' or 'ChatGPT,Perplexity'. Required. |
| `mode` | text | add (default): switch these engines on and keep the rest. remove: switch these off. replace: each prompt runs on exactly these. |

### `set_prompts_active`

*Needs write access*

Start or stop tracking prompts, without deleting anything.

A stopped prompt keeps all its past answers and stops costing quota. Restarting is subject to plan limits. This is the reversible way to reduce what a brand tracks, and [`undo_change`](#undo_change) reverses it.

**Also takes:** `brand`.

| Argument | Type | What it does |
| :- | :- | :- |
| `prompt_ids` | list of numbers | Prompt ids, from [`get_table('prompts')`](#get_table), [`get_prompt_scoreboard`](#get_prompt_scoreboard) or [`list_answers`](#list_answers). Required. |
| `active` | true or false | True to start tracking again, False to stop. Required. |

### `delete_prompts`

*Needs write access*

Delete prompts that are already stopped.

Deleting is soft and only works on prompts that are not currently tracked: stop them first with [`set_prompts_active`](#set_prompts_active). Nothing is actually removed: the prompt's past answers, mentions and sources all stay, and they keep counting toward the monthly quota. The call is all-or-nothing: if any selected prompt is still active, none are deleted.

**Also takes:** `brand`.

| Argument | Type | What it does |
| :- | :- | :- |
| `prompt_ids` | list of numbers | Prompt ids, from [`get_table('prompts')`](#get_table), [`get_prompt_scoreboard`](#get_prompt_scoreboard) or [`list_answers`](#list_answers). Required. |

### `create_topic`

*Needs write access*

Create a topic to group a brand's prompts under.

Topics drive the per-topic breakdowns in visibility and share of voice, so they are worth matching to how the business thinks about its market rather than to prompt wording.

**Also takes:** `brand`.

| Argument | Type | What it does |
| :- | :- | :- |
| `name` | text | The topic name, e.g. 'Pricing'. Required. |

### `update_topic`

*Needs write access*

Rename a topic, or remove one that has no tracked prompts left.

Renaming changes how every report labels it; nothing about the prompts changes. Removing is soft: past answers stay in the data. Either can be undone with [`undo_change`](#undo_change).

**Also takes:** `brand`.

| Argument | Type | What it does |
| :- | :- | :- |
| `topic` | text | The topic to change, name or id. Required. |
| `name` | text | Rename it to this. |
| `delete` | true or false | True to remove the topic. Only works once none of its prompts are tracked (move or stop them first); its stopped prompts are removed with it, their answers kept. Default: `False`. |

### `move_prompts`

*Needs write access*

Move tracked prompts into a different topic.

Topics are how a brand's prompts are grouped for reporting, so moving prompts changes which topic their results roll up under. Nothing about the prompts themselves changes.

**Also takes:** `brand`.

| Argument | Type | What it does |
| :- | :- | :- |
| `prompt_ids` | list of numbers | Prompt ids, from [`get_table('prompts')`](#get_table), [`get_prompt_scoreboard`](#get_prompt_scoreboard) or [`list_answers`](#list_answers). Required. |
| `topic` | text | Destination topic name or id. Required. |

### `set_prompt_tags`

*Needs write access*

Tag existing prompts, to build or clean up a tag taxonomy.

Tags are the second way to slice every report (topics are the first), so they are worth keeping consistent. Defaults to adding, so a prompt's other tags are kept. Removing every tag takes mode='clear', said on purpose. Changes nothing about what is tracked or what it costs.

**Also takes:** `brand`.

| Argument | Type | What it does |
| :- | :- | :- |
| `prompt_ids` | list of numbers | Prompt ids, from [`get_table('prompts')`](#get_table), [`get_prompt_scoreboard`](#get_prompt_scoreboard) or [`list_answers`](#list_answers). Required. |
| `tags` | text | Comma-separated tag names, or ids (a number is always read as an id). A name the brand does not have yet is created. Not used with mode='clear'. |
| `mode` | text | add (default): keep each prompt's tags and add these. remove: take these off. replace: each prompt ends up with exactly these. clear: remove every tag. |

## AI-drafted prompts

Prompts Oppin drafts for you to accept or reject.

### `generate_prompts`

*Needs write access*

Ask Oppin to draft prompts for a topic, using what it knows about this brand.

Returns immediately. The drafts are NOT tracked yet: poll with [`get_generated_prompts`](#get_generated_prompts) and then accept the good ones with [`review_generated_prompts`](#review_generated_prompts). Generation is capped per day by plan.

**Also takes:** `brand`.

| Argument | Type | What it does |
| :- | :- | :- |
| `topic` | text | What the generated prompts should be about, e.g. 'Pricing'. Required. |
| `models` | text | AI engines the generated prompts should run on. |
| `country` | text | Country they should ask from. |
| `state` | text | US state they should ask from (name or code), for United States prompts. Defaults to the brand's own state when asking from its country; 'nationwide' for the whole country. |

### `get_generated_prompts`

*Read only*

The AI-drafted prompts waiting for a decision.

Drafts are not tracked and cost nothing until accepted. Reading them needs no write scope; accepting them ([`review_generated_prompts`](#review_generated_prompts)) does. Pass include\_runs to see whether a generation you started has finished.

**Also takes:** `brand`.

| Argument | Type | What it does |
| :- | :- | :- |
| `status` | text | pending, accepted or rejected. Default pending. |
| `limit` | number | Rows to return. Default 25, maximum 200. |
| `include_runs` | true or false | Also return the recent generation runs and their status. Default false. |

### `review_generated_prompts`

*Needs write access*

Accept or reject AI-drafted prompts.

Accepting starts tracking them and is subject to plan limits. Claude is dropped from an accepted prompt whose country its web search cannot reach, and the response says so.

**Also takes:** `brand`.

| Argument | Type | What it does |
| :- | :- | :- |
| `prompt_ids` | list of numbers | Prompt ids, from [`get_table('prompts')`](#get_table), [`get_prompt_scoreboard`](#get_prompt_scoreboard) or [`list_answers`](#list_answers). Required. |
| `accept` | true or false | True to start tracking them, False to reject. Required. |

## Competitors and brand names

Who the brand is compared with, and the other names AI uses for each.

### `add_competitor`

*Needs write access*

Start tracking a competitor, so they appear in share of voice, gaps and the scoreboard.

Give the real domain when you know it: it is a matching key, and a wrong one mis-attributes their mentions. Never guess a domain from the name. Past answers count straight away. Can be undone with [`undo_change`](#undo_change).

**Also takes:** `brand`.

| Argument | Type | What it does |
| :- | :- | :- |
| `name` | text | The competitor's brand name. Required. |
| `website` | text | Their domain, e.g. 'adidas.com'. Strongly recommended. |
| `aliases` | text | Comma-separated other names AI answers use for them. |
| `domains` | text | Comma-separated OTHER domains they own (regional sites, e.g. 'adidas.de,adidas.co.uk'). Only ones you know; never guessed. |

### `update_competitor`

*Needs write access*

Change a competitor's name, domain, aliases, other domains, or whether they are actively tracked.

Alias and domain edits are retroactive: past mentions re-attribute with no reprocessing, because matching happens at read time. Can be undone with [`undo_change`](#undo_change).

**Also takes:** `brand`.

| Argument | Type | What it does |
| :- | :- | :- |
| `competitor_id` | number | The competitor id, from [`describe_brand`](#describe_brand) or [`get_competitor_scoreboard`](#get_competitor_scoreboard). Required. |
| `name` | text | Rename them. |
| `website` | text | Replace their domain. Pass an empty string to remove it. |
| `aliases` | text | Replace their alias list, comma-separated. Pass an empty string to clear it. |
| `tracked` | true or false | True to track them, False to move them to the watchlist. |
| `domains` | text | Replace their OTHER domains (regional sites), comma-separated. Pass an empty string to clear. |

### `remove_competitor`

*Needs write access · most apps ask you to confirm before it runs*

Stop tracking a competitor and remove them from this brand's comparisons.

Their past mentions stay in the data; they simply stop being named as a tracked brand. To keep them visible but inactive, use [`update_competitor`](#update_competitor) with tracked=false instead. [`undo_change`](#undo_change) adds them back with the same name, website and other names.

**Also takes:** `brand`.

| Argument | Type | What it does |
| :- | :- | :- |
| `competitor_id` | number | The competitor id to remove. Required. |

### `update_brand_aliases`

*Needs write access · most apps ask you to confirm before it runs*

Replace the other names AI answers use for this brand, so those mentions are attributed to it.

Retroactive: past mentions re-attribute immediately, because matching happens at read time. This is the fix for a brand being called something short or abbreviated in answers. The list you pass REPLACES the current one, so include the aliases you want to keep.

**Also takes:** `brand`.

| Argument | Type | What it does |
| :- | :- | :- |
| `aliases` | list of text | The complete alias list. Replaces what is there. Required. |

## Changes and undo

Everything an assistant changed, and how to take it back.

### `list_changes`

*Read only*

List the changes AI assistants made to this organization's tracking, newest first: what changed, on which brand, through which app, and whether it can still be undone.

Use it to answer "what did you change?" and before [`undo_change`](#undo_change), which takes a change id from here. Every write tool also returns the `change_id` of what it just did.

| Argument | Type | What it does |
| :- | :- | :- |
| `brand` | text | Brand name or id to limit to. Omit for every brand in the organization. |
| `limit` | number | Rows to return. Default 25, maximum 200. |
| `page` | number | Page number, from 1, for paging past `limit` rows. |

### `undo_change`

*Needs write access*

Reverse a change an AI assistant made in Oppin, from [`list_changes`](#list_changes).

Refuses, and says why, when the change cannot be undone (a new brand, a completed recommendation), was already undone, or when something was edited again since (undoing would overwrite that). Plan limits apply to the undo like to any change.

| Argument | Type | What it does |
| :- | :- | :- |
| `change_id` | number | The change to reverse, from [`list_changes`](#list_changes) or a write tool's change\_id. Required. |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.