[go: up one dir, main page]

Skip to main content
The Peec AI MCP Server exposes two sets of tools:

Read tools (50) return data:

  • Projects, brands, model channels
  • Prompts and prompt suggestions
  • Chats and chat reports
  • Brand/domain/URL reports
  • Actions
  • Brand perception attributes and objections
  • Fact-checking facts
  • Scraped source content
  • Custom classifications
  • The Brand Profile
  • Products, merchants and the shopping catalog
  • Shopping performance/demand/trend metrics
  • The Peec documentation
  • AI referral traffic
  • Agent Analytics (known bots and access-log visit counts)

Write tools (42) create, update, archive, or delete:

  • Brands, prompts, tags, tag groups, topics
  • Products, categories, facts
  • Custom domain/URL classifications
  • Attribute clusters
  • Action statuses
  • The Brand Profile
  • Generate topics and prompt suggestions
Your AI assistant calls these tools automatically based on your questions. You don’t need to invoke them directly, but this reference helps you understand what is available. A few tools are only available when the feature behind them is enabled for your project:
  • Fact tools → Fact-checking
  • Action tools → New Actions
  • get_ai_referrals → My website
A Company Member can turn these on under Settings → Company Settings → Early access. Until a feature is enabled, your assistant doesn’t see its tools at all. Calling one by name will return “tool not found”.
All tools except list_projects, search_docs, read_doc, and list_referral_sources require a project_id. Your AI assistant handles this automatically after you pick a project.Write tools require company member access on the project. Any project member can use the read tools.Tool calls are rate limited to 1,000 calls per minute per user. If you hit the limit, the server tells your assistant to retry after a few seconds.

Response format

Most tools return compact columnar JSON:
Each row is an array of values matching the columns order. List tools (list_brands, list_topics, list_tags, list_prompts, list_chats, list_search_queries, list_shopping_queries, list_products, list_categories, list_global_brands, list_shopping_demand, list_shopping_performance, list_domain_classifications, list_url_classifications) also return a totalCount field with the total matching records across pages, so you can tell whether to paginate. get_chat, get_url_content, get_project_profile, get_product, get_shopping_trend, get_shopping_attributes, read_doc, list_bots, and get_agent_visits are exceptions: they return their object directly.

list_projects

Lists all projects your account has access to. This is always called first. Columns: id, name, status

list_brands

List brands (your brand and tracked competitors) in a project. Columns: id, name, domains, aliases, is_own, regex, color, source aliases are alternate names the brand is matched under. is_own indicates whether this is your brand (true) or a competitor (false). A nonempty regex overrides name and alias matching; null means none is set. color is the brand’s hex color, or null when none is set and Peec shows an automatic one. source is how the brand was added: onboarding for competitors Peec suggested when the project was created, suggestion for a brand suggestion someone accepted, and manual for a brand created in the app, through the API, or through MCP. null means the brand was added before Peec recorded this.

list_topics

Lists topic groupings in a project. Each prompt belongs to one topic. Columns: id, name

list_tags

Lists tags (cross-cutting labels) in a project. Columns: id, name, is_system, group System tags (is_system: true) are Peec-managed branding/intent tags; their group is branding or intentType. User tags carry their user-defined group name in group (or null when ungrouped). Use list_tag_groups to enumerate the user-defined groups.

list_tag_groups

Lists the user-defined tag groups in a project, each with its shared color and tag count. System groups (branding/intentType) are not included — see list_tags. Returns: { data: [{ group, color, tag_count }] }.

list_models

Lists all AI engines (models) configured for a project. Use this to resolve model names (e.g. “ChatGPT”, “Perplexity”) to IDs before filtering reports, and to label model IDs with human-readable names when presenting results. Columns: id, name, is_active The is_active field indicates whether the model is enabled for this project. Inactive models return empty data in reports.
Filtering and breaking down reports by model_id is deprecated. Prefer model_channel_id (see list_model_channels) — channels are stable engine identifiers that survive model version upgrades.

list_model_channels

Lists the AI engine channels tracked by Peec. A model channel is a stable identifier for an engine (e.g. openai-0 = ChatGPT UI) that persists as the underlying model is upgraded. Use it to filter or break down reports without tying yourself to a specific model version. Columns: id, description, current_model_id, is_active, unsupported_country_codes
  • current_model_id is the model ID currently active in the channel. Pass this as model_id if a report still requires the deprecated filter.
  • is_active mirrors the engine’s status for this project. Inactive channels return empty data.
  • unsupported_country_codes lists ISO 3166-1 alpha-2 codes the channel can’t serve. Chats requested for those countries are not created.

list_prompts

Lists prompts in a project. You can filter by topic or tag. Columns: id, text, tag_ids, topic_id, volume tag_ids is an array of tag IDs. topic_id is the topic ID or null. volume is a relative search-volume bucket: very low, low, medium, high, very high, or null when the prompt does not have a volume signal yet.

list_prompt_suggestions

Lists the prompts Prompt discovery generated and left awaiting review. A suggestion isn’t tracked and produces no data until you accept it, so this is the review queue rather than part of your prompt set. Filter by topic_id to work through one topic at a time. Columns: id, text, topic_id, tag_ids, country, volume Accept or reject them with finalize_prompt_suggestions, or edit one first with update_prompt_suggestions.

get_prompt_suggestion_generation

Reads the status of a generation run started by generate_prompt_suggestions. QUEUED and RUNNING mean it’s still working. SUCCEEDED and FAILED are final, and a successful run can still produce zero suggestions. Once a run succeeds, read what it produced with list_prompt_suggestions.

list_chats

List individual AI responses (chats) for a project over a date range. Each chat is one prompt run against one AI engine on a given date. Combine with get_chat to inspect the full response. Columns: id, prompt_id, model_id, model_channel_id, date, features features is an array of feature flags marking special elements detected in the assistant response. Use the same values listed under the features filter above. By default, chats are excluded if their prompt has been deleted or archived. Pass include_archived_prompts=true to include chats for archived prompts (e.g. for a historical lookback against a prompt no longer being tracked). Chats for deleted prompts are always excluded.

get_chat

Get the full content of a single chat: the user prompt, the AI response, every source URL the model retrieved, every brand it mentioned, every search query it issued, and any extracted products. Returns:

get_chats_report

Aggregate counts and rich-answer shares across a project’s chats over a date range. Reach for it instead of paging through list_chats when the question is how many chats there were, what share of answers rendered a shopping gallery or a map, or how many distinct prompts and engines a tag spans.

Parameters

Response fields

Percentages are 0-1 ratios of chat_count, so 0.75 means 75%. Rows grouped by tag_id, topic_id or model_channel_id also carry a matching *_name column.
Coverage counts collapse to 1 for whichever dimension you group by, so read prompt_count, model_channel_count and country_count against dimensions you didn’t split on. Grouping by prompt_id makes prompt_count 1 in every row.
For a time or high-cardinality breakdown, raise limit to the row count you need rather than to the maximum. If rowCount comes back equal to limit, the results were truncated.

list_search_queries

Lists the search sub-queries an AI engine fanned out to while answering prompts in a project over a date range. Each row is one sub-query issued for a given chat. Combine with get_chat to inspect the full response. Columns: prompt_id, chat_id, model_id, model_channel_id, date, query_index, query_text

list_shopping_queries

Lists the product/shopping sub-queries an AI engine fanned out to while answering prompts. Each row is one shopping sub-query and the distinct products returned for it in a given chat. Columns: prompt_id, chat_id, model_id, model_channel_id, date, query_text, products products is an array of product names extracted for that sub-query.

list_products

List a project’s products with headline AI-visibility metrics over a date range. Columns: id, name, brand, image_url, price_range, categories, mention_count, win_count, avg_position, visibility, share_of_voice

get_product

Detailed metrics for one product over a date range — the drill-down companion to list_products. Returns: { data, primary_currency }. data is null if the product isn’t in the project, otherwise: id, name, brand, description, image_url, source, first_seen_at, price_range, visibility, win_rate, avg_position, mention_count, a *_delta for each metric (vs the immediately preceding equal-length period), and ai_price_map / ai_price_delta_map (per-currency median price across the product’s AI mentions).

get_shopping_attributes

The LLM-extracted attribute grid — characteristics the AI associates with a product (or the whole catalog), compared against competitors. Returns: a nested grid { tab, competitors[], groups[], total_groups } (not columnar). Every group’s per-competitor arrays align to the competitors order. Group shape depends on tab (characteristics, facts, or dimensions). Deltas are computed against an explicit comparison window (previous_start_date / previous_end_date) or the equal-length window immediately before.

get_shopping_summary

Aggregate shopping metrics for a project over a date range, as a single columnar row. Deltas compare against the explicit previous_start_date / previous_end_date window when given, otherwise the auto-derived previous period. Columns: avg_visibility, avg_visibility_delta, avg_win_rate, avg_win_rate_delta, avg_position, avg_position_delta

get_shopping_trend

A product or brand shopping time series. Requires bucket and exactly one of product_ids or brand_ids. Returns: a nested object { entity_type, series } (not columnar). Each series entry is { entity_id, points }, and each point carries date, visibility, win_rate, avg_position, sov, has_data.

list_shopping_demand

Ranked shopping queries, search fan-out queries, or query terms over a date range — what shoppers are asking that surfaces your category. Columns: kind, text, distinct_chat_count, distinct_chat_count_previous, delta

list_shopping_performance

Ranked product or category shopping performance over a date range. Columns: entity_type, entity_id, name, visibility, visibility_delta, win_rate, win_rate_delta, avg_position, avg_position_delta, appearances, appearances_delta

list_merchants

Ranks the merchants whose product offers surfaced in AI answers over a date range, so you can see which sellers own the buy box for your category. A merchant is a seller such as Amazon or eBay, not a brand. Columns: merchant_id, name, domain, mention_count, share_of_voice, win_rate, avg_position, avg_rating, and a *_delta for each metric against the previous window. Merchants with no mentions in the current window are left out entirely.
Pass a merchant_id from here into get_product as merchant_ids to see that seller’s rating and price for a specific product.

list_categories

List the project’s product categories. Categories are an org-wide tree (e.g. Footwear > Shoes > Running Shoes); each row carries its full path and parent_id, so the flat list rebuilds the tree. Use a row’s id as a category_id when creating or updating products. Columns: id, name, path, parent_id

list_global_brands

Search Peec’s global brand catalog — the shared registry of real-world brands (e.g. Nike, Apple) that products attach to. Use it to find the global_brand_id before create_products. This is not the same as list_brands: that returns the brands tracked inside a project, while this searches every brand in Peec’s catalog. The two have different ids. Columns: id, name, domain, description, mention_count, is_own

list_bots

Lists every AI agent bot tracked in Agent Analytics. Each entry has the bot’s ID (the user agent string Peec matches), its provider, and its type. Use the returned IDs with get_agent_visits to filter visit counts by specific bots. Returns: { data: [{ id, provider, type }] }. Bot types:
  • training — crawlers that collect data to build or refine AI models (e.g. GPTBot, ClaudeBot)
  • search — bots that browse the web to find up-to-date information for AI-powered search (e.g. PerplexityBot)
  • userQuery — bots triggered by a real-time user query that fetch content on the user’s behalf
  • other — miscellaneous bots
Agent Analytics requires a connected data source (Cloudflare Workers or a CSV/CLF log upload). See Crawl Insights for setup.

get_agent_visits

Aggregate AI bot visit counts from your connected access logs over a date range. Without group_by, returns the total as a single { visits: N } row. With group_by, returns one row per distinct value of the chosen dimension(s), sorted by visits descending.

Group-by dimensions

Multiple values produce a cross-dimensional breakdown — for example, ["bot_id", "response_status"] gives per-bot, per-status counts. Combine with time_bucket to get e.g. per-bot, per-day counts.

Response fields

{ data: [...], totalCount }.
Pair get_agent_visits with the report tools to connect bot activity to AI visibility. For example, request_path grouping surfaces which of your pages bots hit most; get_url_report shows how those same pages perform as AI sources.

get_ai_referrals

People who arrived on your own website from an AI assistant, measured through the project’s connected Google Analytics property. This is traffic that reached your site, which is a different question from whether AI answers cite you (get_url_report) or whether AI crawlers fetch your pages (get_agent_visits).

Group-by dimensions

Response fields

{ columns, rows, rowCount, total_count, currency }. Unknown dimension values come back as (not set).
There’s no list_event_names or list_countries tool. To discover a dimension’s values, call this with group_by set to that one dimension. When you build a filter, don’t also filter on the dimension you’re listing, or every option you haven’t already picked disappears.
Referral figures are a lower bound. Only referrer-visible traffic reaches GA4, so assistant native apps land as Direct and Gemini often counts as Organic Search.

list_referral_sources

Every AI assistant Peec can attribute referral traffic to, whether or not your project has seen traffic from it. Use it to resolve the exact display name for the assistants filter on get_ai_referrals, and to recognize a raw host in that tool’s results. Columns: source, assistant, platform One row per referrer host, so an assistant reachable on several hosts appears once per host. The list is maintained by hand and reviewed quarterly, so a very new assistant may be missing.
This tool takes no project_id and no date range. For the assistants that actually sent your project traffic, call get_ai_referrals with group_by: ["assistant"] instead.

list_domain_classifications

Lists the custom domain classifications defined for a project. These complement the built-in classifications (Corporate, Competitor, Editorial, Institutional, Other, Reference, UGC, You, Related) and can be assigned to specific domains via assign_domain_classification. Columns: name, color

list_url_classifications

Lists the custom URL classifications defined for a project. These complement the built-in classifications (Homepage, Category Page, Product Page, Listicle, Comparison, Profile, Alternative, Discussion, How-To Guide, Article, Other) and can be assigned to specific URLs via assign_url_classification. Columns: name, color

get_brand_report

Returns brand visibility, sentiment, position, and share of voice across AI search engines.

Parameters

Response fields

The response also includes raw aggregation fields (visibility_count, visibility_total, sentiment_sum, sentiment_count, position_sum, position_count) for custom calculations across segments.

get_domain_report

Returns source domain retrieval and citation metrics across AI search engines.

Parameters

Response fields


get_url_report

Returns URL-level retrieval and citation metrics across AI search engines.

Parameters

Response fields


get_url_content

Returns the scraped markdown content of a source URL Peec has indexed. Use this after get_url_report to inspect the actual content an AI engine read. Useful for content gap analysis and comparing why a competitor URL wins citations.

Response fields

Returns a 404 if the URL has never been retrieved by any Peec project. Peec only scrapes URLs that appear as AI sources.

get_brand_perception_brand_attributes

How AI models describe your own brand: attribute clusters such as “Luxury” or “Racing Heritage”, each with a prominence score. This is the Brand Perception market view, read as data. Columns: name, score, members This one is a snapshot of the latest brand-perception run, where the ranking and competitive-breakdown tools below aggregate across many runs. An empty result means the first run hasn’t completed yet.
Scores here are not ratios. Display them as returned and never multiply by 100. Brand Perception carries no date range, so none of these tools accepts one.

get_brand_perception_attribute_rankings

Where your own brand places against competitors on each brand-perception attribute, and which attributes it has never surfaced on at all. Columns: name, ranking, competitors Rows come back best-ranked first, with unranked last. A ranking of null means your brand has never once been described that way, which is a different problem from ranking fourth. The response also reports the industry and target_market it read, and lists your other industries under industries when the project has more than one. Say which industry a number describes whenever that field is present. The target market is always the industry’s most recently completed one and can’t be picked.
Pass a returned name to get_brand_perception_attribute_sources to see which pages are feeding that attribute.

get_brand_perception_competitive_breakdown

The full attribute by brand matrix: for every attribute, the average prominence of your brand and each competitor across AI answers. Columns: attribute, brand, score, is_own score is 0-100, where higher means the brand tends to be mentioned earlier when AI talks about that attribute. is_own marks your brand. One row per attribute and brand cell, with attributes sorted by your own score, strongest first, and brands sorted by score within each attribute.
limit and offset paginate attributes, not rows. Each attribute contributes one row per brand, and totalCount is the attribute count. Set limit generously and check totalCount before assuming you have the whole matrix.

get_brand_perception_attribute_sources

The pages feeding one attribute: the URLs AI answers cited while describing your brand that way. These are the pages to go after when you want to change how AI describes you on it. Columns: url, title, domain, url_classification, domain_classification, occurrences, retrievals, citation_rate
Pass the attribute name verbatim. An unknown name returns an empty result rather than an error, so a paraphrase looks like “no sources”. Unlike the rankings and breakdown tools, this one isn’t scoped to an industry and takes no industry argument.

citation_rate is an average, not a percentage. It can exceed 1. Display it as returned.

get_brand_perception_objections

The recurring arguments AI makes against your brand when a buyer is deciding. An attribute measures how strongly AI links you to a quality. An objection is the engine arguing against buying you at all. Columns: name, score, members score is average prominence per AI answer from 0 to 100, displayed as returned. members holds the raw phrasings folded into each objection: a “Pricing” objection made of expensive for what you get is a different problem from one made of pricing is hard to find. There’s no competitor dimension and no ranking here, because the objection is about your brand alone. Data aggregates across every objection run and takes no industry argument.

get_brand_perception_objection_sources

The pages AI models retrieved when asked about one objection. Returns the same columns as get_brand_perception_attribute_sources, with the same meanings. An unknown objection name returns an empty result rather than an error, and citation_rate is an average rather than a percentage.

list_brand_perception_attribute_clusters

The editable attribute taxonomy behind Brand Perception: every cluster with its ID, its label, and the raw extracted attributes grouped under it. Read this when an attribute looks mislabeled, duplicated or split, and to resolve the cluster_id values that edit_brand_perception_attribute_clusters needs. Returns: { columns, rows, rowCount, totalCount, unassigned }. Columns: cluster_id, name, is_custom, members This tool carries no scores, so use get_brand_perception_brand_attributes when the question is about scores. It does list clusters that have no score yet, which that tool won’t show.

list_facts

The facts your project uses to check claims found in AI answers. A manual fact was added by a person; a website fact was extracted from your own site. Columns: id, text, origin, is_active, edited_at, created_at Results are newest first. An inactive fact stays visible here but is left out of future fact-checking. Deleted facts are never returned.
Call this first to resolve fact IDs before update_facts or delete_facts.

get_actions

Returns Peec’s opportunity-scored action recommendations for a project and date range. Use this whenever the user asks what to do next, how to improve visibility, or wants ranked next steps instead of raw data. The tool is two-step: always call scope=overview first to see which slices have the biggest opportunity, then drill into owned, editorial, reference, or ugc for the actual textual recommendations.

Parameters

Response (scope=overview)

Each overview row surfaces exactly one of url_classification or domain. Pass that value into the matching scope in the follow-up call.

Response (scope=owned | editorial | reference | ugc)

For example: scope=overview returns a row {action_group_type: "UGC", domain: "youtube.com", opportunity_score: 0.30, ...}. Follow up with scope=ugc, domain="youtube.com" to get ranked recommendations like “Contact AutoPedia. Ask them for a collaboration.”

list_actions

The actions Peec generated for your project, the same set the Actions page shows. Each action names a page or a site and a concrete change to make to it, with the impact expected if you do it. Columns: id, type, status, title, group, category, target, archetype, platform, domain, topic_id, source, country_codes, model_channel_ids, impact, step_count, completed_step_count, created_at, status_updated_at The published types differ in what they ask of you. CONTRADICTIONS_EXTERNAL_SOURCES requests a correction to one third-party source page, while CONTRADICTIONS_OWNED_SOURCES corrects one source page on a domain you own. TEMPLATE_ACTION is a per-platform playbook filled in for one page, such as pitching an editor or growing reviews. CONTENT_BRIEF is net-new content to write, with an outline. CATEGORY_SITUATION_BRIEF is also net-new content, with ready-to-use briefs carried in its steps rather than an outline. SEO_ISSUE is a technical fix to a site you control, and applies to the whole site rather than one page. ROBOTS_TXT says a site’s robots.txt blocks AI crawlers. impact is how much the action is expected to gain, banded against every action in the project, so it reads the same whatever filters you apply. On an SEO_ISSUE it bands the issue’s severity instead. It’s the only measure of expected gain this tool returns.
Filters combine with AND, with one exception: targets, groups, archetypes and platforms combine with OR across the four, so passing an owned target alongside a platform widens the answer instead of narrowing it.
get_actions is a different, older opportunity-rollup tool. Fall back to it only when this one reports the feature isn’t enabled for the project.

get_action

One action in full: what to do, the content brief when there is one, and the competitor demand behind it. Everything list_actions returns is here too. Always returned: title, description (the case for the action, with its sources), content_brief_outline (content briefs only, holding the headline options, meta title and description, your angle, the facts you may claim, the points to cover, and the whole brief as one markdown document), and opportunity (the competitor demand a brief answers, also briefs only). A site-audit action, SEO_ISSUE or ROBOTS_TXT, carries neither, and its description and steps are the whole fix.
steps and outline_points are each most of the response for their kind of action, so ask for them when you’re about to do the work rather than while browsing.
An ID this project has no published action for is an error, whether it belongs to another project, to an action type this tool doesn’t publish, or to nothing at all.

list_action_platforms

The third-party sites your project has actions on, alphabetically. These are the values list_actions accepts in its platforms filter. Columns: platform A platform is whichever domain an AI engine cited for your brand, so unlike the other filter dimensions it’s per project and open-ended. Own-site actions carry no platform and never appear here.

get_project_profile

Read the project’s brand profile: the description, industry, brand-identity adjectives, target markets, audience distribution, and product or service list that Peec uses to generate prompt suggestions. Call this before set_project_profile so the assistant can show you the current values before changing anything. Returns: { profile }. profile is null if the project hasn’t been profiled yet, otherwise an object with the fields described under set_project_profile.

search_docs

Search the Peec product documentation at docs.peec.ai and return the most relevant pages. The assistant uses this for any question about how Peec works — what a metric means, how a feature behaves, setup steps, plan and credit rules — then reads the best result with read_doc. Needs no project_id or project access. Columns: title, path, url, snippet Pass a result’s path to read_doc.

read_doc

Read the full markdown content of a single documentation page. Pass the path returned by search_docs (e.g. metrics/brand-metrics/visibility). Needs no project_id or project access. Returns: { title, path, url, content }. Returns a 404 if no page matches the path.

Write tools

Write tools let the assistant edit your project configuration: brands, prompts, tags, topics, products, categories, and the brand profile. Every write tool is flagged readOnlyHint: false, and every delete_* tool is flagged destructiveHint: true. Clients that honor MCP annotations (Claude, Cursor, and most others) prompt for explicit confirmation before the call runs. Some deletes cascade, as noted below. Brands, prompts, tags, and topics also have bulk variants (create_brands, update_brands, delete_brands, create_prompts, update_prompts, delete_prompts, create_tags, update_tags, delete_tags, create_topics, update_topics, delete_topics) for handling up to 50 items in one call. Bulk tools return per-item results so partial failures don’t block the rest of the batch. Products and categories are managed only in bulk (create_products, update_products, delete_products, create_categories, update_categories, delete_categories), up to 1000 items per call. Prompts can also be archived (archive_prompt / unarchive_prompt) to stop or resume running them without deleting their history. There’s also a small CRUD set for custom domain and URL classifications that extends the built-in classification taxonomy. Create the classification once, then assign it to specific domains or URLs as you find them.
All write tools require organization-owner access and a project_id. Ask the assistant to look up IDs with the matching list_* tool before any write call so you see exactly what is about to change.

create_brands

Create up to 50 brands in a single call. Duplicates (matched case-insensitively on name) are returned in skipped instead of failing the batch. Returns: { created, skipped }.
  • created: [{ id, name }]
  • skipped: [{ name, reason: "duplicate" }]

delete_brands

Soft-delete up to 50 brands in a single call. Destructive. Returns: { deleted, skipped }.
  • deleted: [{ id }]
  • skipped: [{ id, reason: "not_found" | "already_deleted" }]

update_brands

Update up to 50 brands in a single call. Per item, set any of name, regex, aliases, domains, color. Changes to name, regex, or aliases trigger a background metric recalculation per brand; a brand updated mid-recalculation is rejected. Returns: { updatedCount, skipped, rejected }. Successful items collapse to updatedCount; skipped and rejected list any items that didn’t apply.

create_prompts

Create up to 50 prompts in a single call. May consume plan credits. Accepts existing topic_id and tag_ids only. This tool does not auto-create topics or tags; unknown IDs land in rejected. Returns: { created, skipped, rejected, warning? }.
  • created: [{ id, text, country_code }]
  • skipped: [{ text, country_code, reason: "duplicate" }]
  • rejected: [{ text, country_code, reason: "limit_exceeded" | "invalid_topic" | "invalid_tag", message }]
  • warning: optional plan-credit warning string when the batch was partially accepted

delete_prompts

Soft-delete up to 50 prompts. Destructive. Each delete is enqueued asynchronously; the response reports which IDs were queued, skipped, or could not be enqueued. Returns: { queued, skipped, rejected }.
  • queued: [{ id }]
  • skipped: [{ id, reason: "not_found" | "already_deleted" }]
  • rejected: [{ id, reason: "enqueue_failed", message }]

update_prompts

Update the topic and/or tags of up to 50 prompts in a single call. Per item, pass tag_ids to fully replace the prompt’s tag set, or topic_id: null to detach its topic. Topic and tag IDs must already exist. Returns: { updatedCount, skipped, rejected }. Successful items collapse to updatedCount; skipped and rejected list any items that didn’t apply.

archive_prompts

Archive up to 50 prompts in one call, setting is_archived = true so they stop running while their chats and history stay intact. Prefer this over delete_prompts whenever the data should be kept. Returns: { archivedCount, skipped, rejected }. skipped lists prompt IDs that weren’t found.

unarchive_prompts

Unarchive up to 50 prompts, setting is_archived = false so they resume running. Returns: { unarchivedCount, skipped, rejected }. Prompts that would take you past your plan’s active-prompt limit come back under rejected with plan_limit.

create_tags

Create up to 50 tags in a single call. Duplicates (matched case-insensitively on name) land in skipped. Returns: { created, skipped }.
  • created: [{ id, name }]
  • skipped: [{ name, reason: "duplicate" }]

delete_tags

Soft-delete up to 50 tags in a single call and detach them from every prompt they’re attached to. Destructive. Returns: { deleted, skipped }.
  • deleted: [{ id }]
  • skipped: [{ id, reason: "not_found" }]

update_tags

Update up to 50 tags in a single call (name and/or color per item). System tags are skipped. Returns: { updatedCount, skipped, rejected }. Successful items collapse to updatedCount; skipped (includes system tags) and rejected list any items that didn’t apply.

update_tag_groups

Rename or recolor up to 50 tag groups in one call. The change applies to every tag in each group. Returns: each updated group with its affected tag count, plus skipped and rejected items. A group with neither a new name nor a new color is rejected.

delete_tag_groups

Delete up to 50 tag groups. By default each group’s tags survive and are simply ungrouped. Returns: each group with its affected tag count, plus skipped and rejected items.
Setting delete_tags: true deletes the group’s tags outright and detaches them from every prompt, which can’t be undone. Leave it false to keep the tags and only drop the grouping.

create_topics

Create up to 50 topics in a single call. Duplicates (matched case-insensitively on name) land in skipped. Items beyond the project’s topic limit land in rejected. Returns: { created, skipped, rejected }.
  • created: [{ id, name }]
  • skipped: [{ name, reason: "duplicate" }]
  • rejected: [{ name, reason: "limit_exceeded", message }]

delete_topics

Soft-delete up to 50 topics in a single call. Destructive. Associated prompts are detached (not deleted); any AI-generated prompt suggestions under the topics are deleted. Returns: { deleted, skipped }.
  • deleted: [{ id }]
  • skipped: [{ id, reason: "not_found" | "already_deleted" }]

update_topics

Rename up to 50 topics in a single call. Returns: { updatedCount, skipped, rejected }. Successful items collapse to updatedCount; skipped and rejected list any items that didn’t apply.

generate_topics

Composes candidate topics for your project from its Brand Profile, the same composition Prompt discovery runs in the app. Returns: { topics: [name, ...] }. Nothing is saved. Review the returned names, then create the ones you want with create_topics. Composition already accounts for your existing topics, so it proposes only what fills a gap and can come back empty when your set is already well covered.
Needs the Brand Profile to name your products and services, which you set with set_project_profile. It spends one of the project’s hourly topic generations, so it’s never called in a loop.

generate_prompt_suggestions

Generates prompt suggestions for your project, the same generation Prompt discovery runs in the app. Generation happens in the background. Returns: { queued: true, generation_id }. Poll it with get_prompt_suggestion_generation, then read the results with list_prompt_suggestions and resolve them with finalize_prompt_suggestions. topic_id, prompt_suggestion_id and segment are mutually exclusive and each narrow the run. With none of them, every topic awaiting review is generated for again and its current suggestions are replaced, so pass a scope unless you actually want a full refresh.
Needs prompt_builder.distribution, the branding and intent split, set through set_project_profile. Markets are optional: without them your own country and language are used. It spends one of the project’s hourly prompt generations, so it’s never called in a loop.

update_prompt_suggestions

Edit up to 50 pending suggestions before you finalize them: rewrite the text, replace the tag set, or both. Prefer this over rejecting and regenerating when a suggestion is close but not quite right. Returns: { updatedCount, skipped, rejected }. Successful items aren’t echoed back. Editing keeps a suggestion pending, so accept it with finalize_prompt_suggestions to create the tracked prompt. tag_ids fully replaces the item’s tags and must be existing IDs from list_tags; system tags keep at most one per group, and the last one passed wins.

finalize_prompt_suggestions

Resolves prompt suggestions in one pass over a reviewed set. IDs in accepted_ids become tracked prompts and promote their topics into the project; IDs in rejected_ids are deleted from the review list. Pass either or both, up to 50 IDs across the two lists, targeting 40 or fewer per call. At least one ID is required. Returns: a count per outcome, any IDs that matched no suggestion, and any allowance warning. Rejecting never touches your tracked prompts, since a suggestion has produced none until it’s accepted. A topic left with no suggestions is cleared along with them.
The accepted set is checked against your project’s remaining prompt allowance as a whole and refused as a batch when it doesn’t fit. Trim it and retry rather than splitting it across calls, and note that a refused accept also leaves the rejections unapplied.

create_global_brand

Creates a brand in the shopping catalog and returns its global_brand_id. Use it when list_global_brands finds no match for a brand you need, or when create_products rejects an item with brand_not_found. Returns: { id, name }. The returned name is the brand’s canonical name and can differ slightly from the one you sent.
This is separate from create_brands, which creates the brands a project tracks for AI-visibility reporting. The two carry different IDs and aren’t interchangeable.

create_products

Create products in a project. Up to 1000 per call. Each product needs a global_brand_id (resolve via list_global_brands) and a name unique within that brand. Returns: { created, rejected } per item. Rejection reasons: name_conflict, brand_not_found, category_not_found.

update_products

Update products by id (resolve via list_products). Up to 1000 per call. Per item, set any of name (unique within the brand), description, image_url, price_override (replaces all overrides; {} clears them), category_ids (replaces the product’s categories; [] uncategorizes). Omitted fields are left unchanged. Returns: { updated, skipped, rejected } per item. An item with nothing to apply is skipped; an unsatisfiable change (name conflict, unknown category) is rejected.

delete_products

Delete products by id. Destructive. Up to 1000 per call. Returns: { deleted, skipped } per item (skipped reason: not_found).

create_categories

Create product categories. Up to 1000 per call, applied in order. Each needs a name and an optional parent_id — omit it for a top-level category, or pass another category’s id to nest it underneath. A name must be unique among its siblings. Returns: { created, rejected } per item. Rejection reasons: parent_not_found, name_conflict.

update_categories

Rename and/or move categories by id (resolve via list_categories). Up to 1000 per call. Each item sets name (rename), parent_id (move under that category, or null to promote to the top level), or both. Returns: { updated, rejected } per item. Rejection reasons: not_found, name_conflict, invalid_move (nesting a category inside itself).

delete_categories

Delete categories by id. Destructive. Up to 1000 per call. A deleted category’s children and products move up to its parent — a top-level delete sends children to the top level and its products to Uncategorized. Returns: { deleted, rejected } per item. Rejection reasons: not_found, name_conflict (a child moved up would clash with an existing sibling name).

create_domain_classification

Define a new custom domain classification entity on a project. This creates the classification but does not assign it to any domain — use assign_domain_classification for that. Returns: { id }.

delete_domain_classification

Permanently delete a custom domain classification entity. Destructive. Cascades through the override table — any domain currently assigned this classification falls back to its heuristic classification. To clear a single domain instead, use unassign_domain_classification. Returns: { success: true }.

assign_domain_classification

Assign a built-in classification (Corporate, Competitor, Editorial, Institutional, Other, Reference, UGC, You, Related) or the name of a custom domain classification to a domain. Overrides any heuristic classification. The override applies at apex granularity. If a display label collides with an existing custom classification name, the custom classification wins — pass the built-in enum value (e.g. OTHER) to force the built-in. Returns: { success: true }.

unassign_domain_classification

Clear the classification override on a domain, restoring its heuristic classification. Does not delete the custom classification entity itself. Returns: { success: true }.

create_url_classification

Define a new custom URL classification entity on a project. This creates the classification but does not assign it to any URL — use assign_url_classification for that. Returns: { id }.

delete_url_classification

Permanently delete a custom URL classification entity. Destructive. Cascades through the override table — any URL currently assigned this classification falls back to its heuristic classification. To clear a single URL instead, use unassign_url_classification. Returns: { success: true }.

assign_url_classification

Assign a built-in classification (Homepage, Category Page, Product Page, Listicle, Comparison, Profile, Alternative, Discussion, How-To Guide, Article, Other) or the name of a custom URL classification to a URL. Overrides any heuristic classification. The override applies to the normalized URL form. If a display label collides with an existing custom classification name, the custom classification wins — pass the built-in enum value (e.g. OTHER) to force the built-in. Returns: { success: true }.

unassign_url_classification

Clear the classification override on a URL, restoring its heuristic classification. Does not delete the custom classification entity itself. Returns: { success: true }.

create_facts

Adds up to 50 manual facts in one call. Each fact is a statement about your brand that Peec checks claims from AI answers against. Returns: every created fact with its new ID.

update_facts

Updates the wording or the active state of up to 50 facts. Returns: { updatedCount, skipped, rejected }. Changing text creates a new version and preserves the old wording for verdicts already reached. Setting is_active: false keeps the fact visible but leaves it out of future fact-checking, so it parks a fact without deleting it.

delete_facts

Deletes up to 50 facts. Deleted facts disappear from the fact list and are left out of future fact-checking, while verdicts already reached keep their original fact versions. Returns: { deletedCount, skipped }.
Deletion is a soft delete, but the Peec app has no undo for it. Your assistant reads the exact statements back to you before calling.

edit_brand_perception_attribute_clusters

Renames, deletes and reassigns Brand Perception attribute clusters, the same edits the Manage attributes screen makes. Use it when an attribute is mislabeled, duplicated or split across two clusters. Pass any combination, and at least one. Resolve every cluster_id and attribute with list_brand_perception_attribute_clusters first, and copy both verbatim. Returns: the counts applied. Errors come back as invalid (a repeated target), not_found (unknown cluster or attribute), or conflict (a new label collides with another cluster, or a deleted cluster still holds attributes). The whole call is one transaction, so if any edit is rejected nothing is applied. Edits run in the order reassign, rename, delete however you list them, which makes merging two clusters a single call: reassign every attribute out of the losing cluster, then delete it. Name each attribute and each cluster at most once per call, since two edits naming the same one would conflict.
Scores re-aggregate on the next read, so the change is immediate and needs no new run. It rewrites a taxonomy the whole project shares and there’s no undo, so your assistant shows you the exact edits and waits for your confirmation.

update_actions_status

Moves up to 50 actions to a status, the same ones the Actions page writes: ACCEPTED to take one on, REJECTED to decline it, COMPLETED to record that the work is done, PENDING to put a resolved action back on the undecided pile, DELETED to take it off the list altogether. Returns: a count of updated actions plus skipped and rejected items. Complete an action only once the change is actually live on the page. The status is what tells everyone where the work stands, and it doesn’t itself affect visibility. An action that’s already deleted reads as absent, so a second call naming one comes back skipped.

update_action_steps

Records which of an action’s steps you’ve done, across up to 50 actions in one call. Each step in turn either sets completed for all of its options or names options individually, each with its own completed, so one call can tick some and untick others. Setting completed and listing parts at the same level is rejected. Passing false puts a step or option back to not-done, so a step marked off by mistake can be corrected. Returns: updatedCount plus skipped and rejected items, keyed on action_id. An action is all or nothing: anything that can’t be applied leaves every step on it untouched, so you never have to read an action back to find out what landed. Other actions in the same call still go through.
Read the step and option IDs with get_action and fields: ["steps"] first. They aren’t in list_actions, and an ID from an earlier read can be stale.

This records work you’ve already finished. It does nothing to the pages the engines read, and completing every step doesn’t move the action to COMPLETED. The action’s own status changes in the Peec app or through update_actions_status.

set_project_profile

Replace the project’s brand profile. Every field is required, so call get_project_profile first, merge your changes into the existing values, then send the complete profile here. Saving triggers a background refresh of the project’s prompt suggestions. The project display name is not part of the profile and can’t be changed via this tool. marketSize is one of: Neighborhood, City, State/Province, National, Continental Bloc, Global. Returns: { success: true }.

list_facts

List the facts a project checks claims against. Manual facts were added by a person, website facts were extracted from the project’s site. An inactive fact stays in the list but is left out of future fact-checking, and soft-deleted facts are never returned. Call this to resolve fact IDs before update_facts or delete_facts. Returns: columnar JSON { columns, rows, rowCount, totalCount, fact_limit, active_fact_count }, newest first. Columns: id, text, origin, is_active, edited_at, created_at. fact_limit is how many active facts the project’s plan allows, and null means unlimited. active_fact_count is how many it holds now, so the difference is the room left before create_facts is rejected.

create_facts

Add up to 50 manual facts in one call. Each fact is a statement about the brand that Peec checks claims in future AI answers against. Confirm the exact statements with the user first, because this changes shared project data. Returns: { created, skipped?, rejected? }. Created facts come back in full with their new IDs.

update_facts

Update the wording or the active state of up to 50 facts in one call. Changing the text creates a new version and keeps the old wording on the verdicts already given against it. Setting is_active to false keeps the fact but leaves it out of future fact-checking. Returns: { updatedCount, skipped?, rejected? }.

delete_facts

Soft-delete up to 50 facts. Destructive. Deleted facts leave the fact list and future fact-checking; verdicts already given keep the fact version they were judged against. There is no undo in the Peec app, so show the user the exact statements first. Returns: { deletedCount, skipped? }.
The fact tools appear only on projects with fact-checking enabled. Writing facts also requires owner access to the project, while list_facts is available to any viewer.

Report filters and dimensions

Filtering

The three report tools support filters to narrow results. Each filter looks like this:

Standard filter fields

These all use in / not_in operators with a values array.

Numeric filters

Domain and URL reports also accept two numeric filters. These use gt / gte / lt / lte operators with a single value (not values). mentioned_brand_count: filter by number of unique brands mentioned alongside a source.
gap: gap analysis. Excludes sources where your own brand is mentioned, then filters by how many competitor brands are present. This is Peec’s most actionable competitive filter: it finds content where competitors appear but you don’t.
The example above returns domains or URLs where the own brand is absent but at least 2 competitors are mentioned.

Operators

You can combine multiple filters. They’re joined with AND logic.

Sorting

The three report tools accept an order_by array that sorts results before pagination. Each entry is { field, direction }. direction is asc or desc and defaults to desc. Multiple entries create a multi-key sort, applied in order.
Sortable fields by report: When order_by is omitted, each report falls back to a sensible default ordering.

Dimensions

Dimensions break down results into rows grouped by a specific field. Without dimensions, results are totals for the entire date range. You can combine dimensions. For example, ["date", "model_channel_id"] gives you daily trends per AI engine.