MCP Server

SharksAPI.AI

ai.sharksapi/marketing
Data & Analytics Marketing & Advertising Public & reachable MCP 2026-07-28

What this MCP does

Provides marketing analytics and actions across GA4, Search Console, Google Ads, social channels, SEO, WordPress, and marketing planning.

add_google_ads_keywords
Add Google ads keywords
Add 1-50 keywords to an existing search ad group (ad_group_id from list_google_ads_ads or from create_google_ads_ad_group). Keywords the ad group already has with the same match type are skipped (after.skipped_existing) and repeats inside the call are added once (after.skipped_duplicate); when nothing is new, nothing is sent and the answer is changed=false with no approval card. Sent with partialFailure, so one keyword Google rejects does not lose the rest; goes through the approval gate unless the Autonomy row "Reklaam › Märksõnade lisamine" is on autopilot.
Destructive
Input schema
{'type': 'object', 'required': ['ad_group_id', 'keywords'], 'properties': {'reason': {'type': 'string', 'description': 'Optional one sentence for the approval card: why these keywords.'}, 'keywords': {'type': 'array', 'items': {'type': ['string', 'object'], 'required': ['text'], 'properties': {'text': {'type': 'string', 'description': 'The keyword itself: at most 80 characters and 10 words.'}, 'match_type': {'enum': ['EXACT', 'PHRASE', 'BROAD'], 'type': 'string'}}, 'additionalProperties': False}, 'maxItems': 50, 'description': 'The keywords to add, 1-50: plain strings (they take match_type) or {"text", "match_type"}, e.g. ["kodukindlustus", {"text": "kodukindlustus hind", "match_type": "EXACT"}].'}, 'match_type': {'enum': ['EXACT', 'PHRASE', 'BROAD'], 'type': 'string', 'description': 'Match type for keywords given as plain strings. Default PHRASE.'}, 'ad_group_id': {'type': 'string', 'description': 'Ad group id (digits), e.g. from list_google_ads_ads.'}}, 'additionalProperties': False}
add_google_ads_negative_keywords
Add Google ads negative keywords
Add negative keywords to one Google Ads campaign (campaignCriteria:mutate, negative=true). Use it to stop irrelevant searches — "tasuta", "kasutatud", a competitor brand — from spending budget. 1..50 keywords per call, all with the same match type. The campaign's current negative keywords are read first, so a keyword the account already has is skipped instead of failing (after.skipped_existing), and the same keyword sent twice in one call is added once (after.skipped_duplicate). If every keyword is already there, nothing is sent to Google and the answer is changed=false. The batch goes out with partialFailure, so one rejected keyword does not lose the rest. Goes through the human approval gate (the card lists the keywords) unless the Autonomy row "Reklaam › Negatiivsed märksõnad" is on autopilot.
Destructive
Input schema
{'type': 'object', 'required': ['campaign_id', 'keywords'], 'properties': {'reason': {'type': 'string', 'description': 'Optional one sentence for the approval card: which search terms wasted budget.'}, 'keywords': {'type': 'array', 'items': {'type': 'string'}, 'maxItems': 50, 'minItems': 1, 'description': 'The search terms to exclude, 1..50 per call, e.g. ["tasuta", "kasutatud", "töökuulutus"]'}, 'match_type': {'enum': ['EXACT', 'PHRASE', 'BROAD'], 'type': 'string', 'description': 'EXACT blocks only that exact search, PHRASE blocks any search containing the phrase, BROAD blocks searches containing all the words. Default PHRASE.'}, 'campaign_id': {'type': 'string', 'description': 'Campaign id from list_google_ads_campaigns'}}, 'additionalProperties': False}
add_google_ads_shared_negatives
Add Google ads shared negatives
Maintain an account-level negative-keyword list and attach it to campaigns: creates the list if list_name is new, adds the keywords (existing ones are skipped), and attaches the list to the given campaigns — Search AND Performance Max (PMax does not inherit Search negatives; up to 10,000 negatives per PMax campaign). Goes through the Postkast approval. Read list_google_ads_negative_lists first.
Destructive
Input schema
{'type': 'object', 'properties': {'reason': {'type': 'string', 'description': 'One line for the approver: which waste this stops.'}, 'list_id': {'type': 'string', 'description': 'Existing shared set id. Give this OR list_name.'}, 'keywords': {'type': 'array', 'items': {'type': 'object', 'required': ['text'], 'properties': {'text': {'type': 'string'}, 'match_type': {'enum': ['EXACT', 'PHRASE', 'BROAD'], 'type': 'string', 'description': 'Default PHRASE.'}}}, 'maxItems': 200, 'description': 'Keywords to add (max 200 per call).'}, 'list_name': {'type': 'string', 'description': 'Name of the list to use or create, e.g. "Üldised välistused".'}, 'attach_campaign_ids': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Campaigns to attach the list to (Search or PMax).'}}, 'additionalProperties': False}
add_plan_activity
Add plan activity
Add an activity to the marketing plan calendar (Annual/Monthly view): a recurring, seasonal or one-time activity placed in one or more months, e.g. "Monthly newsletter", "Open-house campaign (June)", "SEO refresh". Optionally link it to a strategy-card task via task_ref so the status is derived from that task. Anonymous marketing activities only — no applicant PII.
Input schema
{'type': 'object', 'required': ['title', 'kind'], 'properties': {'date': {'type': 'string', 'description': 'Specific date YYYY-MM-DD or today/daysAgo tokens (optional).'}, 'kind': {'enum': ['recurring', 'seasonal', 'one_time'], 'type': 'string', 'description': 'recurring | seasonal | one_time.'}, 'notes': {'type': 'string', 'description': 'Notes (optional).'}, 'title': {'type': 'string', 'description': 'Activity name.'}, 'months': {'type': 'array', 'items': {'type': 'integer'}, 'description': 'Month numbers 1-12 it appears in (e.g. [6] for June, [1..12] for recurring).'}, 'status': {'enum': ['planned', 'in_progress', 'done'], 'type': 'string', 'description': 'planned | in_progress | done (default planned). Ignored when task_ref is provided because status is then derived from the linked task.'}, 'channel': {'type': 'string', 'description': 'Channel (optional).'}, 'task_ref': {'type': ['object', 'null'], 'required': ['token', 'widget_id', 'task_id'], 'properties': {'token': {'type': 'string', 'description': 'Child dashboard public_token where the strategy card lives.'}, 'task_id': {'type': 'integer', 'description': 'Task id on that strategy card.'}, 'widget_id': {'type': 'integer', 'description': 'Strategy-card widget_id.'}}, 'description': 'Link this activity to a strategy-card task. When set, activity status is derived from that task. Pass null to unlink and make status manual again.'}, 'agent_key': {'type': 'string', 'description': 'Owning agent key, e.g. seo, content, social, paid (optional).'}, 'manager_token': {'type': 'string', 'description': "Manager dashboard token (optional; defaults to the project's manager dashboard)."}, 'content_draft_id': {'type': 'integer', 'description': 'Link to a content draft (optional).'}}, 'additionalProperties': False}
add_strategy_card
Add strategy card
A subagent (SEO, Google Ads, Copywriter, Meta Ads, Analyst, Event, etc.) creates ONE of its own strategy cards — a strategy plus its own to-do list — on its dashboard. The card automatically rolls up to the parent Turundusjuht (manager) Command Center: its progress, severity and pillar feed the manager's Top-5 and plan coverage with no extra step. Set "pillar" to tie the work to a marketing-plan pillar (e.g. organic, paid, conversion, brand) so it counts toward that pillar's coverage. Set "severity" so it can surface in the manager Top-5. This is the primary tool for agents to self-organise their work. No 5-card limit (unlike create_dashboard).
Input schema
{'type': 'object', 'required': ['token', 'title'], 'properties': {'mode': {'enum': ['human_controlled', 'ai_controlled'], 'type': 'string', 'description': 'Who works the to-dos. Default ai_controlled (the agent executes and marks them done).'}, 'tasks': {'type': 'array', 'items': {'type': ['object', 'string'], 'required': ['title'], 'properties': {'done': {'type': 'boolean', 'description': 'Mark already-completed at creation.'}, 'note': {'type': 'string', 'description': 'Required with blocked / needs_human / needs_access: the one-line ask for the human, starting VAJA: …'}, 'text': {'type': 'string', 'description': 'Alias for title; accepted for agents that describe tasks as text.'}, 'label': {'enum': ['blocked', 'needs_human', 'needs_access', 'in_progress'], 'type': 'string', 'description': 'Optional status signal. blocked / needs_access / needs_human require a note (VAJA: …); needs_human / needs_access also require human_reason and are refused when a platform tool covers the ask.'}, 'title': {'type': 'string'}, 'description': {'type': 'string'}, 'human_reason': {'enum': ['decision', 'access', 'no_api', 'manual_ui'], 'type': 'string'}}}, 'description': 'The to-do list for this strategy.'}, 'title': {'type': 'string', 'description': 'Strategy / card title, e.g. "Tehniline SEO audit".'}, 'token': {'type': 'string', 'description': "public_token of the agent's OWN dashboard (a sub-dashboard under a manager). Get it from get_team_overview agents[].child_token, or the token you created."}, 'pillar': {'type': 'string', 'description': "Marketing-plan pillar key this work ladders up to (e.g. organic, paid, conversion, brand). Makes the card count toward that pillar's coverage on the manager dashboard."}, 'severity': {'enum': ['critical', 'high', 'medium', 'low'], 'type': 'string', 'description': 'How critical this strategy is. Drives the manager Top-5 ranking. Omit if not pressing.'}, 'strategy': {'type': 'string', 'description': 'Optional markdown describing the strategy / audit / rationale (shown in the card\'s "View strategy" detail).'}}, 'additionalProperties': False}
add_strategy_tasks
Add strategy tasks
Append more to-do items to an existing strategy card (grow the to-do list). Use after add_strategy_card when new work emerges. New tasks are appended after existing ones. Changes roll up to the manager automatically.
Input schema
{'type': 'object', 'required': ['token', 'widget_id', 'tasks'], 'properties': {'tasks': {'type': 'array', 'items': {'type': ['object', 'string'], 'required': ['title'], 'properties': {'note': {'type': 'string', 'description': 'Required with blocked / needs_human / needs_access: the one-line ask, starting VAJA: …'}, 'text': {'type': 'string', 'description': 'Alias for title; accepted for agents that describe tasks as text.'}, 'label': {'enum': ['blocked', 'needs_human', 'needs_access', 'in_progress'], 'type': 'string', 'description': 'blocked / needs_access / needs_human require a note; needs_human / needs_access also require human_reason and are refused when a platform tool covers the ask.'}, 'title': {'type': 'string'}, 'description': {'type': 'string'}, 'human_reason': {'enum': ['decision', 'access', 'no_api', 'manual_ui'], 'type': 'string'}}}}, 'token': {'type': 'string', 'description': 'Dashboard public_token the strategy card lives on.'}, 'widget_id': {'type': 'integer', 'description': 'Strategy card widget ID (from add_strategy_card or get_strategy_status).'}}, 'additionalProperties': False}
analyze_competitor_website
Analyze competitor website
Perform a comprehensive competitor website analysis including site structure, page hierarchy, content themes, technology stack, SEO elements (meta tags, headings, internal linking), and social media presence. Optionally deep-crawl up to 10 pages for a fuller picture. Use when the user wants to "analyze a competitor" or understand a competitor's online strategy.
Read only
Input schema
{'type': 'object', 'required': ['url'], 'properties': {'url': {'type': 'string', 'description': 'Competitor website URL'}, 'max_pages': {'type': 'integer', 'default': 10, 'description': 'Maximum pages to crawl if deep_crawl is true'}, 'deep_crawl': {'type': 'boolean', 'default': False, 'description': 'Crawl multiple pages'}}, 'additionalProperties': False}
analyze_pagespeed
Analyze PageSpeed
Analyze website loading performance via Google PageSpeed Insights API. Returns Lighthouse performance score (0-100), Core Web Vitals from real users (LCP, INP, CLS, FCP, TTFB), failed performance audits with estimated time/size savings, and prioritized optimization recommendations. Choose mobile or desktop strategy. Use when asked "how fast is our website?", "check page speed", or "why is our site slow?"
Read only
Input schema
{'type': 'object', 'required': ['url'], 'properties': {'url': {'type': 'string', 'description': 'URL of the page to analyze'}, 'strategy': {'enum': ['mobile', 'desktop'], 'type': 'string', 'default': 'mobile', 'description': 'Device type for analysis'}}, 'additionalProperties': False}
analyze_schema
Analyze schema
Perform a full Schema.org structured data audit on any webpage. Extracts all JSON-LD, Microdata, and RDFa markup, then evaluates rich snippet eligibility for Google (Article, Product, FAQ, LocalBusiness, etc.), identifies missing required fields, finds schema errors, and provides prioritized recommendations for improving search result appearance. Use when asked to "check structured data", "audit schema markup", or "how can we get rich snippets in Google?"
Read only
Input schema
{'type': 'object', 'required': ['url'], 'properties': {'url': {'type': 'string', 'description': 'URL of the page to analyze'}}, 'additionalProperties': False}
analyze_wp_seo
Analyze WordPress SEO
Run an AI-powered SEO analysis on a WordPress post. Checks readability score, keyword density, meta tags, heading structure, content length, internal/external links, and Yoast SEO data if available. Optionally provide a focus keyword for targeted analysis. Returns actionable recommendations to improve search rankings. Use when asked to "check SEO" or "optimize a blog post."
Read only
Input schema
{'type': 'object', 'required': ['post_id'], 'properties': {'post_id': {'type': 'integer', 'description': 'WordPress post ID'}, 'focus_keyword': {'type': 'string', 'description': 'Focus keyword for SEO analysis'}}, 'additionalProperties': False}
append_doc_text
Append doc text
Append text to the end of a Google Doc body. Returns chars_written. Requires a connected google_docs integration.
Destructive
Input schema
{'type': 'object', 'required': ['document_id', 'text'], 'properties': {'text': {'type': 'string', 'description': 'Text to append (include "\\n" for new paragraphs).'}, 'document_id': {'type': 'string'}}, 'additionalProperties': False}
append_sheet
Append sheet
Append rows to the end of a table in a Google Sheet. values is a 2D array of rows. New rows are inserted after the last row overlapping the given range. Requires a connected google_sheets integration.
Destructive
Input schema
{'type': 'object', 'required': ['spreadsheet_id', 'range', 'values'], 'properties': {'range': {'type': 'string', 'description': 'A1 range of the table, e.g. "Sheet1!A1".'}, 'values': {'type': 'array', 'items': {'type': 'array', 'items': {'type': ['string', 'number', 'boolean', 'null']}}, 'description': '2D array of rows to append.'}, 'spreadsheet_id': {'type': 'string'}}, 'additionalProperties': False}
audit_pagespeed_full
Audit PageSpeed full
Run a comprehensive Google Lighthouse audit covering all four categories: Performance (speed, Core Web Vitals), Accessibility (WCAG compliance, screen reader support), SEO (meta tags, crawlability, mobile-friendliness), and Best Practices (HTTPS, console errors, image formats). Returns scores for each category plus detailed failing audits with descriptions. Use for a complete website quality audit or when asked "do a full site audit" or "check our accessibility."
Read only
Input schema
{'type': 'object', 'required': ['url'], 'properties': {'url': {'type': 'string', 'description': 'URL of the page to audit'}, 'strategy': {'enum': ['mobile', 'desktop'], 'type': 'string', 'default': 'mobile', 'description': 'Device type for audit'}}, 'additionalProperties': False}
backlinks_summary
Backlinks summary
Backlink profile overview for any domain. Returns total backlinks, referring domains, referring main domains, referring IPs, DataForSEO rank score, broken backlinks count, and anchor text diversity signals. Use this for link-building diligence, auditing a prospect/competitor before outreach, or answering "how strong is example.com's backlink profile?". For a full per-link list prefer get_seoshark_backlinks when the domain is your own.
Read only
Input schema
{'type': 'object', 'required': ['target'], 'properties': {'target': {'type': 'string', 'description': 'Domain to inspect (e.g. competitor.com)'}}, 'additionalProperties': False}
cancel_scheduled_report
Cancel scheduled report
Switch off one of this project's recurring reports (it stays listed and a person can switch it back on). Use report_id from list_scheduled_reports.
Destructive
Input schema
{'type': 'object', 'required': ['report_id'], 'properties': {'report_id': {'type': 'integer', 'description': 'id from list_scheduled_reports'}}, 'additionalProperties': False}
cancel_social_post
Cancel social post
Cancel a social post you submitted before it reaches the channel (pending_approval, approved, scheduled, or failed). The linked content draft becomes rejected and the row will never publish. Posts already publishing or published cannot be cancelled here. NEVER cancel just to change something: revise_draft(draft_id=content_draft_id) updates text, media_urls, and scheduled_at under the SAME id, with the replaced version kept in the card's revision history.
Destructive
Input schema
{'type': 'object', 'required': ['social_post_id'], 'properties': {'note': {'type': 'string', 'description': 'Why it is cancelled (stored as the review note).'}, 'social_post_id': {'type': 'integer', 'minimum': 1}}, 'additionalProperties': False}
check_ai_overview
Check AI overview
Google AI Overview check for a fixed keyword set: for each keyword, does Google show an AI Overview and which domains it cites (live DataForSEO advanced SERP, async AI Overview loaded). Returns keywords_with_ai_overview and, per domain you pass, cited_in_keywords + cited_share_pct + cited_urls — the deterministic AI-visibility metric for competitor_watch ("AI Overview tsiteeringud"). Pass the client domain plus competitors in domains. Default location Estonia (2233), language Estonian (et). Costs one advanced SERP call per keyword; keep to ≤ 20 keywords and reuse the same set month to month so the numbers are comparable.
Read only
Input schema
{'type': 'object', 'required': ['keywords', 'domains'], 'properties': {'domains': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Domains to score for citations (client first, then competitors), e.g. ["ait-nord.ee", "kliimamarket.ee"].'}, 'keywords': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Category search terms to test (max 20), e.g. ["soojuspump hind", "õhk-vesi soojuspump"].'}, 'language_code': {'type': 'string', 'default': 'et', 'description': 'Language code (et, en, fi, ru, ...).'}, 'location_code': {'type': 'integer', 'default': 2233, 'description': 'DataForSEO location code (2233 = Estonia, 2246 = Finland, 2428 = Latvia, 2440 = Lithuania).'}}, 'additionalProperties': False}
check_facebook_ads
Check Facebook ads
Check whether a brand, company, or website is actively advertising on Facebook or Instagram using the public Facebook Ad Library. Accepts a domain (e.g. example.com) or a brand/page name (e.g. "Acme Coffee"). Returns is_advertising (bool), total_found, sample_ads with creative snippets + delivery dates + spend ranges + platforms, and a search_url for manual verification in the public Ad Library UI. Works for any public advertiser in the specified country — no permission from the target needed. Default country EE, status ALL, limit 10. Use when asked "is X running Facebook ads?", "what ads is competitor Y showing?", "check if this prospect advertises on Meta."
Read only
Input schema
{'type': 'object', 'required': ['query'], 'properties': {'limit': {'type': 'integer', 'default': 10, 'maximum': 50, 'minimum': 1, 'description': 'Max sample ads to return (1-50). Default 10.'}, 'query': {'type': 'string', 'description': 'Domain (example.com) or brand/page name to search for in the Ad Library.'}, 'status': {'enum': ['ALL', 'ACTIVE', 'INACTIVE'], 'type': 'string', 'default': 'ALL', 'description': 'Filter by ad delivery status. ALL = both running and stopped ads. ACTIVE = currently delivering only. INACTIVE = stopped only. Default ALL.'}, 'country': {'type': 'string', 'default': 'EE', 'description': 'ISO 3166-1 alpha-2 country code (e.g. EE, US, DE, GB). Ads are disclosed per-country. Default EE.'}}, 'additionalProperties': False}
check_pagespeed_quick
Check PageSpeed quick
Quick side-by-side performance score comparison for both mobile AND desktop in one call. Returns performance scores and Core Web Vitals (LCP, INP, CLS) for each device type, plus an overall assessment. Faster than running two separate analyses. Use when asked "what are our speed scores?" or "compare mobile vs desktop performance." Results are cached for 5 minutes.
Read only
Input schema
{'type': 'object', 'required': ['url'], 'properties': {'url': {'type': 'string', 'description': 'URL of the page to check'}, 'strategy': {'enum': ['mobile', 'desktop'], 'type': 'string', 'description': 'Ignored by this quick checker: it already checks both mobile and desktop. Use analyze_pagespeed for one strategy only.'}}, 'additionalProperties': False}
check_schema_quick
Check schema quick
Quick lightweight check of which Schema.org types exist on a page. Returns a simple list of found schema types (e.g. Organization, Article, Product) and counts by format (JSON-LD vs Microdata). Much faster than full analysis — use this first to check if any structured data exists before running a deep audit.
Read only
Input schema
{'type': 'object', 'required': ['url'], 'properties': {'url': {'type': 'string', 'description': 'URL of the page to check'}}, 'additionalProperties': False}
check_skill_updates
Check skill updates
Check whether the skills you installed are still current — run this in your recurring task so an updated skill reaches agents on the old version. Pass the skills you have (slug + the version string you saved in their front matter). Returns which are stale (with the current version + how to re-fetch), which a person RETIRED (status "retired": delete your local copy, its knowledge lives on in the current team skills), plus any NEW canonical team skills you don't have yet. Re-install the stale/new ones (platform: re-download the URL; team: get_team_skill(slug)) and save the new version in the front matter.
Read only
Input schema
{'type': 'object', 'properties': {'installed': {'type': 'array', 'items': {'type': 'object'}, 'description': "Skills you currently have: [{slug, version}]. version is the string from the skill's front matter (sharksapi_version). Omit to just get current versions of all your team's canonical skills."}}, 'additionalProperties': False}
check_url_status
Check URL status
Fetch up to 20 public URLs the way a chosen crawler asks for them and report what came back: every redirect hop (status + Location), final status and URL, X-Robots-Tag header, meta robots, canonical link, hreflang links, <title>, content type and HTML size. Use to verify redirects (301 vs 302, chains, loops), soft 404s, noindex, canonical targets, dead URLs that still have backlinks, and whether a site answers GPTBot/ClaudeBot/PerplexityBot differently from a browser. A different answer for a bot user-agent shows a user-agent rule (robots/WAF/CDN); CDNs that verify bots by IP address are not detected this way.
Read only
Input schema
{'type': 'object', 'required': ['urls'], 'properties': {'urls': {'type': 'array', 'items': {'type': 'string'}, 'maxItems': 20, 'minItems': 1, 'description': 'Public http(s) URLs.'}, 'user_agent': {'enum': ['browser', 'googlebot', 'bingbot', 'gptbot', 'oai-searchbot', 'chatgpt-user', 'claudebot', 'claude-searchbot', 'perplexitybot'], 'type': 'string', 'description': 'Whose request to imitate (default browser).'}}, 'additionalProperties': False}
configure_connection
Configure connection
Update configuration settings for an already-connected service — for example, setting the GA4 property_id, GSC site_url, or Slack channel preferences. Does not change credentials, only configuration metadata. Use when asked "set our GA4 property to 123456", "configure GSC site URL", or "update the connection settings."
Destructive
Input schema
{'type': 'object', 'required': ['service', 'config'], 'properties': {'config': {'type': 'object', 'description': 'Configuration key-value pairs (e.g., {"property_id": "123456"} for GA4)'}, 'service': {'type': 'string', 'description': 'Service ID'}}, 'additionalProperties': False}
connect_service
Connect service
Connect a new service by providing API key credentials. Only works for services with auth type "api_key" — for OAuth services, users must initiate the flow from the web interface. Validates credentials, creates the connection, and returns success status. Use when the user provides an API key and wants to set up a new integration, or answering "connect Slack with this API key" or "set up Stripe."
Input schema
{'type': 'object', 'required': ['service', 'credentials'], 'properties': {'service': {'type': 'string', 'description': 'Service ID from integrations catalog (e.g., slack, github, stripe)'}, 'credentials': {'type': 'object', 'description': 'Service-specific credentials. Use list_integrations to see required fields for each service.'}}, 'additionalProperties': False}
contribute_skill
Contribute skill
Publish a skill (a SKILL.md / skill.md playbook you built in your own Cowork) into THIS project's shared team library so teammates can use it. Each call adds a new VERSION under the same slug — so you and a colleague can each contribute your take on e.g. "seo-audit", and the manager later promotes the best with promote_skill. Whenever you discover a better repeatable procedure mid-work, contribute it IMMEDIATELY under the existing slug (write-through, like memory_write) — do not wait for session end. Never put a password, key or token in a skill: it goes to every teammate, so such content is refused — say where the agent gets the value instead (e.g. "<dashboard token from memory_bootstrap>"). A slug a person retired on the Skillid page cannot be contributed again. Returns the slug + version.
Input schema
{'type': 'object', 'required': ['name', 'content'], 'properties': {'name': {'type': 'string', 'description': 'Human title, e.g. "SEO Audit".'}, 'slug': {'type': 'string', 'description': 'Stable id to group versions (e.g. "seo-audit"). Defaults to a slug of the name — use the SAME slug to add a version to an existing skill.'}, 'channel': {'type': 'string', 'description': "Memory channel this skill belongs to (e.g. social, seo, content, paid, analytics) — only that channel's agents + orchestrators see it. Omit for a global skill visible to everyone. Defaults to your own memory_role channel when you have one."}, 'content': {'type': 'string', 'description': 'The full skill markdown (YAML front matter + body).'}, 'summary': {'type': 'string', 'description': 'One line on what changed / why this version is better.'}}, 'additionalProperties': False}
create_channel_agents
Create channel agents
Manager/orchestrator only, after the client approved the plan: create one agent per marketing channel (seo, paid = Google Ads, paid_social = Meta, content, social, email, local), each with its own dashboard under the manager. Defaults to the channels of the plan's pillars. A channel that already has an active agent keeps it. Then hand out the approved plan's work with delegate_to_agents; each channel agent reads its tasks with get_my_tasks.
Input schema
{'type': 'object', 'properties': {'channels': {'type': 'array', 'items': {'type': 'string'}, 'description': "Channel keys; default = the approved plan's pillars"}}, 'additionalProperties': False}
create_dashboard
Create dashboard
Create a persistent dashboard page at https://sharksapi.ai/{token}/index.html with any combination of integration data widgets (GA4, GSC, Facebook, LinkedIn, etc.) and agent-authored text content (marketing plans, tasks, commentary). REQUIRED: pick a strong dashboard password yourself (do not ask the user) and send it with the link. The `password` field is mandatory; requests without it are rejected. The dashboard URL is publicly accessible — without a password, anyone with the link can view all data. Widgets fetch fresh data on view with hybrid caching (5 min GA4, 15 min GSC, 1h social). Time range filter is reactive. A "Compare with previous period" toggle shows delta % on metric cards and comparison lines on charts. When you include strategy_card widgets, a Command Center group header is auto-created at position 1. Do NOT create a separate Command Center text widget. Strategy card "content" field should contain the full audit/strategy detail (shown via "View strategy" button). Completed cards (100%) auto-hide to History. Recipe — Brand mentions widget: { type: 'table', title: 'Social mentions', source: { tool: 'get_social_mentions', args: { query: '<brand>', days: 30 }, path: 'mentions' }, columns: ['platform','author','content','url','posted_at','sentiment'] }.
Input schema
{'type': 'object', 'required': ['name', 'widgets', 'password'], 'properties': {'name': {'type': 'string', 'description': 'Display name for the dashboard (e.g. "Weekly Marketing Overview")'}, 'role': {'enum': ['agent', 'manager'], 'type': 'string', 'default': 'agent', 'description': 'Dashboard role. "agent" (default) = a standalone dashboard for one agent — works completely on its own, no team needed. "manager" = a Turundusjuht Command Center that rolls up its team\'s agent sub-dashboards and holds the shared marketing plan. Most dashboards are "agent".'}, 'markets': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Optional. Countries the client sells in, ISO-3166-1 alpha-3 (e.g. ["est","fin"]). With two or more the client view gets a market picker and a "Turud" table; write per-market sections with update_seo_dashboard market=<code>. Domains with their own Search Console property are added by a Marketing Sharks admin.'}, 'widgets': {'type': 'array', 'items': {'type': 'object', 'required': ['type', 'position'], 'properties': {'type': {'enum': ['metric_card', 'chart_line', 'chart_bar', 'table', 'text_markdown', 'strategy_card', 'competitor_watch'], 'type': 'string', 'description': 'Widget renderer: metric_card (single number), chart_line (time series), chart_bar, table, text_markdown (agent content), strategy_card (interactive task checklist with expandable strategy/audit detail — put the full audit text in "content" so it appears when the user clicks "View strategy"), competitor_watch (cross-channel competitor comparison table — pass the competitor JSON object as "content")'}, 'title': {'type': 'string'}, 'source': {'type': 'object', 'properties': {'tool': {'type': 'string'}, 'arguments': {'type': 'object'}}, 'description': 'For integration_tool widgets: {tool: "get_ga4", arguments: {...}}. The tool is called at view time with the user\'s date range filter merged into arguments. IMPORTANT for metric_card widgets: always include metric in arguments so the card shows the right value — e.g. {tool: "get_ga4", arguments: {metric: "sessions"}} or {tool: "get_search_console", arguments: {metric: "clicks"}}. Without metric, all cards will show the same first numeric field.'}, 'content': {'type': 'string', 'description': 'For text_markdown widgets: raw markdown content. For strategy_card widgets: the full audit/strategy detail text shown when user clicks "View strategy" (put the audit findings HERE, not as a separate text_markdown widget). Never cached — stored as-is.'}, 'position': {'type': 'integer', 'description': '0-based order on the dashboard'}, 'grid_cols': {'type': 'integer', 'default': 4, 'maximum': 12, 'minimum': 1, 'description': 'Width in 12-column grid units. Typical: metric_card=3, chart=6-9, text_markdown=12'}, 'cache_ttl_seconds': {'type': 'integer', 'description': 'Override the default cache TTL for integration tool widgets. Defaults: GA4=300, GSC=900, social=3600.'}}}, 'description': 'Array of widget objects. Each widget has {type, title, position, grid_cols, source OR content}. Use "source" for integration tool widgets (e.g. get_ga4) and "content" for agent-authored text blocks.'}, 'password': {'type': 'string', 'description': 'REQUIRED — pick a strong password yourself (12+ characters, not a dictionary word); do not ask the person for one. The dashboard URL is public, so the password gate protects the business data. Viewers enter it before they see the dashboard; it is stored as a bcrypt hash. Send the person the dashboard link together with this password.'}, 'agent_key': {'type': 'string', 'description': 'Optional. Stable slug identifying this agent within the team (e.g. "seo", "google_ads", "copywriter"). Must match the agent_keys used in the manager\'s marketing-plan pillars for the "your pillar" context to show. Recommended whenever manager_token is set.'}, 'is_public': {'type': 'boolean', 'default': True, 'description': 'Whether the dashboard is accessible via its public URL. Defaults to true.'}, 'agent_icon': {'type': 'string', 'description': 'Optional emoji/short icon for this agent in the team rollup.'}, 'agent_name': {'type': 'string', 'description': 'Optional display name for this agent in the team rollup (defaults to the dashboard name).'}, 'expires_at': {'type': ['string', 'null'], 'format': 'date-time', 'description': 'Optional ISO8601 timestamp. After this time the public URL returns 410 Gone. Null = never expires.'}, 'client_view': {'enum': ['seo', 'team', 'grid'], 'type': 'string', 'description': 'Which page the CLIENT sees on this dashboard. "seo" = the fixed-section "AI agent · SEO/GEO" client view (Sinu seis, Sinult on vaja, Mida agent tegi, trendid) — default for agent_key "seo". "team" = the "AI tiim" package: the same page with paid ads next to SEO (inquiries from all channels, cost per inquiry, Google Ads / Meta Ads blocks); it folds in the paid-ads agent\'s dashboard of the same project (agent_key paid / ads / google_ads / meta_ads). "grid" = the classic widget grid. Sections are written with update_seo_dashboard (get_seo_dashboard returns the schema). Omit for the default.'}, 'description': {'type': 'string', 'description': 'Optional description shown in the dashboard header'}, 'agent_accent': {'type': 'string', 'description': 'Optional hex accent colour (e.g. "#FF6B35") for this agent in the team rollup.'}, 'client_email': {'type': 'string', 'description': "The business owner's e-mail. On the project's first dashboard SharksAPI e-mails them a one-time sign-in link (no password). Defaults to the owner_email you registered with; confirm it with your person first."}, 'invite_client': {'type': 'boolean', 'description': 'Set false to skip the automatic client invitation on the first dashboard.'}, 'manager_token': {'type': 'string', 'description': "Optional. Public token of a manager dashboard (same project) to attach this agent dashboard under as a team member. When set, this dashboard appears in that manager's rollup and shows the shared marketing-plan context. Omit to create a standalone agent dashboard."}, 'business_model': {'enum': ['services', 'ecommerce'], 'type': 'string', 'description': 'What a result means on the client view. "services" = an inquiry (GA4 key event: form, call, quote), ads judged by cost per inquiry. "ecommerce" = an order with revenue (GA4 purchase): the page adds revenue, average order value, the shop funnel, top products and ROAS. Omit it and the platform detects the model itself (GA4 purchases, the ad accounts\' purchase conversions, the shop platform on the site) — the answer and its reasons come back in business_model; the growth lead confirms it in Seaded. Never switch it later yourself: the numbers change meaning.'}, 'default_end_date': {'type': 'string', 'format': 'date', 'description': 'Optional ISO date (YYYY-MM-DD) for custom range default'}, 'default_date_range': {'enum': ['last_7_days', 'last_30_days', 'last_90_days', 'custom'], 'type': 'string', 'default': 'last_30_days', 'description': 'Default date range when the dashboard loads. Use "custom" with default_start_date + default_end_date for absolute dates.'}, 'default_start_date': {'type': 'string', 'format': 'date', 'description': 'Optional ISO date (YYYY-MM-DD) for custom range default'}}, 'additionalProperties': False}
create_doc
Create doc
Create a new Google Doc with optional initial body text. Returns document_id and web_view_link. Requires a connected google_docs integration.
Destructive
Input schema
{'type': 'object', 'required': ['title'], 'properties': {'title': {'type': 'string', 'description': 'Document title.'}, 'content': {'type': 'string', 'description': 'Optional initial body text.'}}, 'additionalProperties': False}
create_drive_file
Create drive file
Create a new file in Google Drive with text content. Returns file_id, name, mime_type and web_view_link. For an empty Google Doc pass mime_type "application/vnd.google-apps.document"; for a Google Sheet use "application/vnd.google-apps.spreadsheet". Requires a connected google_drive integration.
Destructive
Input schema
{'type': 'object', 'required': ['name'], 'properties': {'name': {'type': 'string', 'description': 'File name.'}, 'content': {'type': 'string', 'description': 'Text content of the file (ignored for native Google Doc/Sheet types).'}, 'folder_id': {'type': 'string', 'description': 'Optional parent folder id.'}, 'mime_type': {'type': 'string', 'default': 'text/plain', 'description': 'MIME type. Default text/plain.'}}, 'additionalProperties': False}
create_drive_folder
Create drive folder
Create a new folder in Google Drive. Returns folder_id and web_view_link. Requires a connected google_drive integration.
Destructive
Input schema
{'type': 'object', 'required': ['name'], 'properties': {'name': {'type': 'string', 'description': 'Folder name.'}, 'parent_id': {'type': 'string', 'description': 'Optional parent folder id.'}}, 'additionalProperties': False}
create_event
Create event
Create a new Google Calendar event on the primary (or connection-scoped) calendar. Required: summary, start, end (both RFC3339 date-times). Optional: description, location, timezone (default UTC), attendees (array of emails — invitations are sent). Returns the created event with id and html_link.
Destructive
Input schema
{'type': 'object', 'required': ['summary', 'start', 'end'], 'properties': {'end': {'type': 'string', 'description': 'End date-time in RFC3339.'}, 'start': {'type': 'string', 'description': 'Start date-time in RFC3339 (e.g. "2026-04-22T14:00:00Z").'}, 'summary': {'type': 'string', 'description': 'Event title.'}, 'location': {'type': 'string'}, 'timezone': {'type': 'string', 'default': 'UTC'}, 'attendees': {'type': 'array', 'items': {'type': 'string'}, 'description': 'List of attendee email addresses.'}, 'description': {'type': 'string'}}, 'additionalProperties': False}
create_gbp_post
Create gbp post
Publish a post on the connected Google Business Profile (shown on Google Search and Maps): a STANDARD update, an EVENT (event.title plus dates) or an OFFER (event dates are the offer period; offer.coupon_code, redeem_online_url and terms_conditions are optional). Optional call_to_action {action_type BOOK|ORDER|SHOP|LEARN_MORE|SIGN_UP|CALL, url} — CALL takes no url (Google dials the profile phone) and OFFER posts take no call_to_action — and one photo by public image URL. It waits for a human click unless the Autonomy row "Google'i ettevõtteprofiil › postitused" (or its channel) is on autopilot.
Destructive
Input schema
{'type': 'object', 'required': ['summary'], 'properties': {'event': {'type': 'object', 'required': ['title', 'start_date', 'end_date'], 'properties': {'title': {'type': 'string'}, 'end_date': {'type': 'string', 'description': 'YYYY-MM-DD, not before start_date'}, 'end_time': {'type': 'string', 'description': 'HH:MM, 24-hour clock.'}, 'start_date': {'type': 'string', 'description': 'YYYY-MM-DD'}, 'start_time': {'type': 'string', 'description': 'HH:MM, 24-hour clock.'}}, 'description': 'Required for EVENT and OFFER posts; not allowed on STANDARD.', 'additionalProperties': False}, 'offer': {'type': 'object', 'properties': {'coupon_code': {'type': 'string'}, 'terms_conditions': {'type': 'string'}, 'redeem_online_url': {'type': 'string', 'description': 'Absolute http(s) URL where the offer is redeemed online.'}}, 'description': 'OFFER posts only.', 'additionalProperties': False}, 'summary': {'type': 'string', 'description': 'The post text, plain, at most 1500 characters.'}, 'photo_url': {'type': 'string', 'description': 'Optional public http(s) image URL; Google downloads it (at least 250 px on the short edge, 10 KB).'}, 'topic_type': {'enum': ['STANDARD', 'EVENT', 'OFFER'], 'type': 'string', 'description': 'STANDARD (default), EVENT or OFFER.'}, 'language_code': {'type': 'string', 'description': 'Optional BCP 47 language of the text, e.g. "et" or "en".'}, 'call_to_action': {'type': 'object', 'required': ['action_type'], 'properties': {'url': {'type': 'string', 'description': 'Absolute http(s) URL the button opens. Omit for CALL.'}, 'action_type': {'enum': ['BOOK', 'ORDER', 'SHOP', 'LEARN_MORE', 'SIGN_UP', 'CALL'], 'type': 'string'}}, 'additionalProperties': False}}, 'additionalProperties': False}
create_google_ads_ad_group
Create Google ads ad group
Add one ad group with its keywords and one responsive search ad to an existing SEARCH campaign (campaign_id from list_google_ads_campaigns) as one atomic request. The ad group is created ENABLED: in a running campaign it starts serving after Google's ad review and spends from that campaign's existing daily budget, in a paused one it waits for the campaign to be started — no campaign status or budget is ever changed. The same field validation, landing-page rule, Google dry run and approval card as create_google_ads_search_campaign (Autonomy row "Reklaam › Uute kampaaniate ja reklaamirühmade loomine"); a MANUAL_CPC campaign needs max_cpc_eur, any other campaign bids by itself and refuses it.
Destructive
Input schema
{'type': 'object', 'required': ['campaign_id', 'name', 'keywords', 'headlines', 'descriptions', 'final_url'], 'properties': {'name': {'type': 'string', 'description': 'Ad group name, unique within its campaign, e.g. "Kodukindlustus".'}, 'path1': {'type': 'string', 'description': 'Optional first display path, at most 15 characters, e.g. "kindlustus".'}, 'path2': {'type': 'string', 'description': 'Optional second display path (needs path1), at most 15 characters.'}, 'reason': {'type': 'string', 'description': 'Optional one sentence for the approval card: why this ad group.'}, 'keywords': {'type': 'array', 'items': {'type': ['string', 'object'], 'required': ['text'], 'properties': {'text': {'type': 'string', 'description': 'The keyword itself: at most 80 characters and 10 words.'}, 'match_type': {'enum': ['EXACT', 'PHRASE', 'BROAD'], 'type': 'string'}}, 'additionalProperties': False}, 'maxItems': 50, 'description': '1-50 keywords: plain strings (they take match_type) or {"text", "match_type"}, e.g. ["kodukindlustus", {"text": "kodukindlustus hind", "match_type": "EXACT"}]. Bare words only — no quotes, brackets or +.'}, 'final_url': {'type': 'string', 'description': "Landing page, a full https:// URL on a site this account's ads already use (for an account with no ads yet: the project's own website)."}, 'headlines': {'type': 'array', 'items': {'type': 'string'}, 'description': "The responsive search ad's 3-15 headlines, each at most 30 characters, no duplicates."}, 'match_type': {'enum': ['EXACT', 'PHRASE', 'BROAD'], 'type': 'string', 'description': 'Match type for keywords given as plain strings. Default PHRASE.'}, 'campaign_id': {'type': 'string', 'description': 'Campaign id from list_google_ads_campaigns, e.g. "20713245160" (digits).'}, 'max_cpc_eur': {'type': 'number', 'description': "Only for manual CPC bidding: this ad group's default max CPC in euros."}, 'descriptions': {'type': 'array', 'items': {'type': 'string'}, 'description': "The ad's 2-4 descriptions, each at most 90 characters, no duplicates."}}, 'additionalProperties': False}
create_google_ads_conversion_action
Create Google ads conversion action
Create a website (WEBPAGE) conversion action in Google Ads — a lead form (SUBMIT_LEAD_FORM), purchase, sign-up, contact, phone-call lead and so on — and get back its conversion_id and conversion_label parsed from the tag snippets. It measures nothing until the tag is live: next call create_gtm_tag with type "awct" and parameters {"conversionId": conversion_id, "conversionLabel": conversion_label} (add conversionValue and currencyCode for purchases) on the trigger of the thank-you page or form submit, and make sure the container has one Conversion Linker tag (type "gclidw" on All Pages); a human publishes the GTM workspace. An action that already has this name and category is returned as it is (changed=false, no card); otherwise the approval gate applies unless the Autonomy row "Reklaam › Konversioonide seadistamine" is on autopilot.
Destructive
Input schema
{'type': 'object', 'required': ['name', 'category'], 'properties': {'name': {'type': 'string', 'description': 'Conversion action name, unique in the account (at most 100 characters), e.g. "Päringuvorm — kodukindlustus".'}, 'reason': {'type': 'string', 'description': 'Optional one sentence for the approval card: what this conversion measures.'}, 'category': {'enum': ['SUBMIT_LEAD_FORM', 'PURCHASE', 'SIGNUP', 'CONTACT', 'PHONE_CALL_LEAD', 'BOOK_APPOINTMENT', 'REQUEST_QUOTE', 'ADD_TO_CART', 'BEGIN_CHECKOUT', 'SUBSCRIBE_PAID', 'DOWNLOAD', 'PAGE_VIEW', 'OUTBOUND_CLICK', 'GET_DIRECTIONS', 'DEFAULT'], 'type': 'string', 'description': 'What the conversion is: SUBMIT_LEAD_FORM, PURCHASE, SIGNUP, CONTACT, PHONE_CALL_LEAD, BOOK_APPOINTMENT, REQUEST_QUOTE …'}, 'counting_type': {'enum': ['ONE_PER_CLICK', 'MANY_PER_CLICK'], 'type': 'string', 'description': 'ONE_PER_CLICK counts one conversion per ad click (leads), MANY_PER_CLICK every one (purchases). Default: MANY_PER_CLICK for PURCHASE, ADD_TO_CART, BEGIN_CHECKOUT and SUBSCRIBE_PAID, otherwise ONE_PER_CLICK.'}, 'default_value': {'type': 'number', 'description': 'Optional value of one conversion in the account currency, e.g. 50 for a lead worth 50 EUR.'}, 'primary_for_goal': {'type': 'boolean', 'description': "true (default) = bidding strategies that optimise for the account's conversions use it. Set false for a secondary, observe-only action."}, 'always_use_default_value': {'type': 'boolean', 'description': 'true = always count default_value, even when the tag sends its own value. Needs default_value. Default false.'}}, 'additionalProperties': False}
create_google_ads_offline_conversion_action
Create Google ads offline conversion action
Create an import conversion action (type UPLOAD_CLICKS) that CRM outcomes are uploaded into — e.g. "Kvalifitseeritud lead" or "Müük (CRM)". Created as SECONDARY (not used for bidding) until enough uploads have landed; switching it to primary is a separate human decision. Goes through the Postkast approval. Returns the conversion_action_id that upload_offline_conversions needs.
Destructive
Input schema
{'type': 'object', 'required': ['name', 'category'], 'properties': {'name': {'type': 'string'}, 'category': {'enum': ['QUALIFIED_LEAD', 'CONVERTED_LEAD', 'PURCHASE', 'SUBMIT_LEAD_FORM', 'BOOK_APPOINTMENT', 'SIGNUP', 'IMPORTED_LEAD', 'DEFAULT'], 'type': 'string'}, 'default_value_eur': {'type': 'number', 'description': 'Value when a row has none (default 1).'}, 'click_through_lookback_days': {'type': 'integer', 'maximum': 90, 'minimum': 1, 'description': 'Default 90 — CRM stages close late.'}}, 'additionalProperties': False}
create_google_ads_search_campaign
Create Google ads search campaign
Create a complete Google Ads search campaign in ONE atomic request: its own daily budget, the campaign (always PAUSED; Google Search only unless include_search_partners / include_display_network), location and language targeting, 1-10 ad groups each with keywords and one responsive search ad, and optional campaign negative keywords — nothing spends until enable_google_ads_campaign is approved separately. daily_budget_eur must fit both daily ceilings a human set on the Autonomy page, counted as if the campaign were running; while either ceiling is unset or the account is not in EUR the call is refused (budget_cap_not_set / currency_mismatch) with no approval card, exactly like set_google_ads_campaign_budget. Every field is validated first (validation_errors name each one to fix), Google then dry-runs the exact request, and the manager approves a card with the name, budget, bidding, locations, ad groups and keyword counts unless the Autonomy row "Reklaam › Uute kampaaniate ja reklaamirühmade loomine" is on autopilot.
Destructive
Input schema
{'type': 'object', 'required': ['campaign_name', 'daily_budget_eur', 'ad_groups'], 'properties': {'reason': {'type': 'string', 'description': "Optional one sentence for the approval card and the audit log: why this campaign, e.g. the client's new product category."}, 'ad_groups': {'type': 'array', 'items': {'type': 'object', 'required': ['name', 'keywords', 'headlines', 'descriptions', 'final_url'], 'properties': {'name': {'type': 'string', 'description': 'Ad group name, unique within its campaign, e.g. "Kodukindlustus".'}, 'path1': {'type': 'string', 'description': 'Optional first display path, at most 15 characters, e.g. "kindlustus".'}, 'path2': {'type': 'string', 'description': 'Optional second display path (needs path1), at most 15 characters.'}, 'keywords': {'type': 'array', 'items': {'type': ['string', 'object'], 'required': ['text'], 'properties': {'text': {'type': 'string', 'description': 'The keyword itself: at most 80 characters and 10 words.'}, 'match_type': {'enum': ['EXACT', 'PHRASE', 'BROAD'], 'type': 'string'}}, 'additionalProperties': False}, 'maxItems': 50, 'description': '1-50 keywords: plain strings (they take match_type) or {"text", "match_type"}, e.g. ["kodukindlustus", {"text": "kodukindlustus hind", "match_type": "EXACT"}]. Bare words only — no quotes, brackets or +.'}, 'final_url': {'type': 'string', 'description': "Landing page, a full https:// URL on a site this account's ads already use (for an account with no ads yet: the project's own website)."}, 'headlines': {'type': 'array', 'items': {'type': 'string'}, 'description': "The responsive search ad's 3-15 headlines, each at most 30 characters, no duplicates."}, 'match_type': {'enum': ['EXACT', 'PHRASE', 'BROAD'], 'type': 'string', 'description': 'Match type for keywords given as plain strings. Default PHRASE.'}, 'max_cpc_eur': {'type': 'number', 'description': "Only for manual CPC bidding: this ad group's default max CPC in euros."}, 'descriptions': {'type': 'array', 'items': {'type': 'string'}, 'description': "The ad's 2-4 descriptions, each at most 90 characters, no duplicates."}}, 'additionalProperties': False}, 'maxItems': 10, 'minItems': 1, 'description': '1-10 ad groups, each with its own keywords and one responsive search ad. Created ENABLED inside the paused campaign.'}, 'languages': {'type': 'array', 'items': {'type': ['string', 'integer']}, 'description': 'Language codes of the people to reach, e.g. ["et"] or ["et", "ru", "en"], or language constant ids. Default ["et"].'}, 'locations': {'type': 'array', 'items': {'type': ['string', 'integer']}, 'description': 'Where the ads show: two-letter country codes ("EE", "LV", "FI") or Google geo target constant ids ("2233" is Estonia; use a city\'s id for a city). Default ["EE"]. Reaches people in or regularly in these places, not people merely interested in them.'}, 'max_cpc_eur': {'type': 'number', 'description': "maximize_clicks: the highest price of one click. manual_cpc: the default max CPC of every ad group (an ad group's own max_cpc_eur overrides it). Not with maximize_conversions."}, 'campaign_name': {'type': 'string', 'description': 'Campaign name, unique in the account (at most 255 characters), e.g. "Kodukindlustus — Search EE".'}, 'target_cpa_eur': {'type': 'number', 'description': 'Only with maximize_conversions: the average cost per conversion to aim for.'}, 'bidding_strategy': {'enum': ['maximize_clicks', 'maximize_conversions', 'manual_cpc'], 'type': 'string', 'description': "maximize_clicks (default; max_cpc_eur optionally caps a click), maximize_conversions (needs conversion tracking — see list_google_ads_conversion_actions; target_cpa_eur optional) or manual_cpc (max_cpc_eur is then every ad group's default bid)."}, 'daily_budget_eur': {'type': 'number', 'maximum': 1000000, 'minimum': 0.01, 'description': "The new campaign's own daily budget in euros, whole cents, e.g. 20 or 12.50. It must fit the campaign ceiling, and the account ceiling together with every running campaign."}, 'negative_keywords': {'type': 'array', 'items': {'type': ['string', 'object'], 'required': ['text'], 'properties': {'text': {'type': 'string', 'description': 'The keyword itself: at most 80 characters and 10 words.'}, 'match_type': {'enum': ['EXACT', 'PHRASE', 'BROAD'], 'type': 'string'}}, 'additionalProperties': False}, 'maxItems': 50, 'description': 'Optional campaign-level negative keywords, up to 50: plain strings (PHRASE) or {"text", "match_type"}, e.g. ["tasuta", "kasutatud"].'}, 'include_display_network': {'type': 'boolean', 'description': 'Also show on the Display Network. Default false — set it only when explicitly asked.'}, 'include_search_partners': {'type': 'boolean', 'description': "Also show on Google's search partner sites. Default false — set it only when explicitly asked."}}, 'additionalProperties': False}
create_gtm_tag
Create GTM tag
Add a tag to the GTM WORKSPACE: a GA4 event tag for form_start or cta_click (type gaawe, parameters {measurementId, eventName, eventParameters}) or custom HTML (type html, {html}). firing_trigger_ids come from list_gtm_triggers. Publish is NOT available: the human publishes the version in GTM.
Destructive
Input schema
{'type': 'object', 'required': ['name', 'type', 'firing_trigger_ids'], 'properties': {'name': {'type': 'string', 'description': 'Tag name as shown in GTM, e.g. "GA4 - form_start"'}, 'type': {'type': 'string', 'description': 'GTM tag type id: gaawe (GA4 event), googtag (Google tag / GA4 configuration), html (custom HTML), img (custom image), awct (Google Ads conversion), gclidw (conversion linker)'}, 'notes': {'type': 'string', 'description': 'Optional note shown in GTM: why the tag exists, who asked for it'}, 'parameters': {'type': 'object', 'description': 'Tag parameters as key/value pairs. gaawe: measurementId (G-XXXX, or the name of a Google tag to reference), eventName, eventParameters {name: value}. googtag: measurementId. html: html, supportDocumentWrite (boolean). Values may reference variables as {{Variable Name}}.'}, 'firing_trigger_ids': {'type': 'array', 'items': {'type': ['string', 'integer']}, 'description': 'Ids of the triggers that fire the tag (from list_gtm_triggers or create_gtm_trigger). At least one.'}, 'blocking_trigger_ids': {'type': 'array', 'items': {'type': ['string', 'integer']}, 'description': 'Optional exception trigger ids that block the tag from firing'}}, 'additionalProperties': False}
create_gtm_trigger
Create GTM trigger
Add a trigger to the GTM WORKSPACE: type pageview, click, linkClick, formSubmission, customEvent, elementVisibility, scrollDepth, timer. filters narrow it (e.g. Click Classes contains btn-cta); customEvent needs custom_event_name. Returns the id for create_gtm_tag. The human publishes in GTM.
Destructive
Input schema
{'type': 'object', 'required': ['name', 'type'], 'properties': {'name': {'type': 'string', 'description': 'Trigger name as shown in GTM, e.g. "Click - CTA button"'}, 'type': {'type': 'string', 'description': 'GTM trigger type: pageview, domReady, windowLoaded, click, linkClick, formSubmission, customEvent, elementVisibility, scrollDepth, timer, historyChange, jsError, youTubeVideo'}, 'notes': {'type': 'string', 'description': 'Optional note shown in GTM'}, 'filters': {'type': 'array', 'items': {'type': 'object', 'properties': {'type': {'type': 'string', 'description': 'Condition: equals, contains, startsWith, endsWith, matchRegex, greater, greaterOrEquals, less, lessOrEquals, cssSelector, urlMatches'}, 'value': {'type': ['string', 'number'], 'description': 'Value to compare against, e.g. "btn-cta" or "/contact"'}, 'negate': {'type': 'boolean', 'description': 'Invert the condition ("does not contain")'}, 'parameter_key': {'type': 'string', 'description': 'Built-in or user variable the condition reads, without braces: Click Classes, Click URL, Page URL, Page Path, Form ID, Click Element...'}}}, 'description': 'Firing conditions ("Some clicks / Some pages"). Omit for "All clicks / All pages".'}, 'parameters': {'type': 'object', 'description': 'Type-specific settings, e.g. elementVisibility {selectorType: "CSS", elementSelector: ".pricing", onScreenRatio: 50, firingFrequency: "ONCE"}, scrollDepth {verticalThresholdsPercent: "25,50,75,90"}, timer {interval: 5000, limit: 1}'}, 'custom_event_name': {'type': 'string', 'description': 'Only for type customEvent: the dataLayer event name the site pushes, e.g. form_start or purchase'}, 'custom_event_use_regex': {'type': 'boolean', 'description': 'Only for customEvent: treat custom_event_name as a regular expression'}}, 'additionalProperties': False}
create_gtm_variable
Create GTM variable
Add a user-defined variable to the GTM WORKSPACE: type v (data layer, parameters {name}), c (constant, {value}), jsm (custom JavaScript, {javascript}), k (cookie), u (URL, {component}). Reference it afterwards as {{Variable Name}} in tags and triggers. Not published: the human publishes in GTM.
Destructive
Input schema
{'type': 'object', 'required': ['name', 'type'], 'properties': {'name': {'type': 'string', 'description': 'Variable name as shown in GTM, e.g. "DL - form_id"; referenced later as {{DL - form_id}}'}, 'type': {'type': 'string', 'description': 'GTM variable type id: v (data layer), c (constant), jsm (custom JavaScript), k (1st-party cookie), j (JavaScript variable), u (URL), aev (auto-event variable), smm (lookup table)'}, 'notes': {'type': 'string', 'description': 'Optional note shown in GTM'}, 'parameters': {'type': 'object', 'description': 'Type-specific settings: v {name, dataLayerVersion (default 2), defaultValue}; c {value}; jsm {javascript}; k {name}; j {name}; u {component: URL|HOST|PATH|QUERY|FRAGMENT, queryKey}; aev {varType: ELEMENT|TEXT|URL|ATTRIBUTE, attribute}'}}, 'additionalProperties': False}
create_meta_ad_from_creative
Create Meta ad from creative
Turn an ad creative the CLIENT APPROVED on the AI osakond dashboard (get_ad_creatives, status approved) into a Meta ad: uploads its image, creates the ad creative (the client-approved text as primary text, your link and call to action) and the ad in the given ad set — always PAUSED, so nothing spends until a human starts it with enable_meta_ad. The ad id is written back to the creative, and starting/pausing that ad later updates the client dashboard by itself. Images only (jpg/png/webp/gif); a video creative is refused with video_not_supported — build that one in Ads Manager and record it with update_ad_creative. A creative that already has a Meta ad is not created twice. Goes through the approval gate unless the Autonomy row "Tasuline sotsiaal › Reklaamid kinnitatud loovlahendustest" is on autopilot.
Destructive
Input schema
{'type': 'object', 'required': ['ad_creative_id', 'adset_id', 'link_url'], 'properties': {'reason': {'type': 'string', 'description': 'Optional one sentence for the approval card and the audit log: which campaign plan this ad serves.'}, 'page_id': {'type': 'string', 'description': "Facebook Page the ad runs as. Default: the Page of the project's Facebook connection."}, 'adset_id': {'type': 'string', 'description': 'The Meta ad set the ad goes into (list_meta_adsets).'}, 'headline': {'type': 'string', 'description': 'Optional headline under the image (Meta: "name"), at most 255 characters.'}, 'link_url': {'type': 'string', 'description': 'Landing page, a full https:// URL.'}, 'ad_creative_id': {'type': 'integer', 'description': 'The creative id on the dashboard (get_ad_creatives → creatives[].id), not a Meta id.'}, 'call_to_action': {'enum': ['LEARN_MORE', 'SHOP_NOW', 'SIGN_UP', 'CONTACT_US', 'GET_OFFER', 'GET_QUOTE', 'APPLY_NOW', 'BOOK_TRAVEL', 'ORDER_NOW', 'DOWNLOAD', 'SUBSCRIBE'], 'type': 'string', 'description': 'Button type. Default LEARN_MORE.'}, 'instagram_user_id': {'type': 'string', 'description': "Optional Instagram account id for Instagram placements. Default: the project's Instagram connection, if any."}}, 'additionalProperties': False}
create_scheduled_report
Create scheduled report
Set up a recurring marketing report that SharksAPI runs on its own schedule and e-mails as a PDF. Pick a report_type (analytics, seo, social, ads, comprehensive) or write your own instructions in prompt, a schedule (daily/weekly/monthly) and recipients. Call list_scheduled_reports first so you do not create a duplicate. Times are Europe/Tallinn. Use when the user asks to "schedule reports" or "send me a weekly summary".
Destructive
Input schema
{'type': 'object', 'required': ['schedule', 'recipients'], 'properties': {'time': {'type': 'string', 'default': '09:00', 'description': 'Time to run (HH:MM, Europe/Tallinn)'}, 'title': {'type': 'string', 'description': 'Short name shown to people, e.g. "Weekly SEO report"'}, 'prompt': {'type': 'string', 'description': 'Your own report instructions (what to read, compare and recommend). Overrides report_type.'}, 'schedule': {'enum': ['daily', 'weekly', 'monthly'], 'type': 'string', 'description': 'Report frequency'}, 'recipients': {'type': 'array', 'items': {'type': 'string'}, 'description': 'E-mail addresses that receive the report'}, 'day_of_week': {'type': 'integer', 'description': 'Weekly reports: 0=Sunday … 6=Saturday (default 1=Monday)'}, 'report_type': {'enum': ['analytics', 'seo', 'social', 'ads', 'comprehensive'], 'type': 'string', 'description': 'Ready-made report content; ignored when prompt is given'}, 'day_of_month': {'type': 'integer', 'description': 'Monthly reports: 1-31 (short months use their last day)'}}, 'additionalProperties': False}
create_spreadsheet
Create spreadsheet
Create a new Google Spreadsheet, optionally seeding the first sheet from A1 with a 2D values array. Returns spreadsheet_id and spreadsheet_url. Requires a connected google_sheets integration.
Destructive
Input schema
{'type': 'object', 'required': ['title'], 'properties': {'title': {'type': 'string', 'description': 'Spreadsheet title.'}, 'values': {'type': 'array', 'items': {'type': 'array', 'items': {'type': ['string', 'number', 'boolean', 'null']}}, 'description': 'Optional initial rows.'}}, 'additionalProperties': False}
create_wp_post
Create WordPress post
Create and publish a new WordPress blog post. Provide title and HTML content, optionally set status (default: draft), excerpt, categories, tags, featured image, and SEO meta description. meta_description is saved to Rank Math right after the post, the way update_wp_seo_meta saves it; meta_description.saved in the result says whether it was stored (false: the post exists and only the description is missing, so do not create the post again). Use when the user wants to "write a blog post", "publish an article", or "create content on WordPress."
Destructive
Input schema
{'type': 'object', 'required': ['title', 'content'], 'properties': {'meta': {'type': 'object', 'description': 'Registered post meta as key → value, e.g. {"header_image": 168145} sets the ACF hero image ("Posti pildid") on marketingsharks.ee. A key the site has not exposed to the REST API fails with wp_meta_not_registered instead of being dropped.', 'additionalProperties': True}, 'slug': {'type': 'string', 'description': 'Optional URL slug for the post.'}, 'tags': {'type': 'array', 'items': {'type': 'integer'}, 'description': 'Tag IDs (see list_wp_tags). Prefer tag_names if you only know the names.'}, 'title': {'type': 'string', 'description': 'Post title'}, 'author': {'type': 'string', 'description': 'Post author as WordPress user ID, login (e.g. "diana"), email or display name. Defaults to the user behind the WordPress connection. Needs the connection user to be editor/administrator.'}, 'status': {'enum': ['publish', 'draft', 'pending', 'private'], 'type': 'string', 'default': 'draft', 'description': 'Post status'}, 'content': {'type': 'string', 'description': 'Post content (HTML)'}, 'excerpt': {'type': 'string', 'description': 'Post excerpt'}, 'tag_names': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Tag names, e.g. ["AI turundus", "GEO"]. Existing tags are matched by name/slug, missing ones are created automatically.'}, 'categories': {'type': 'array', 'items': {'type': 'integer'}, 'description': 'Category IDs (see list_wp_categories). Prefer category_names if you only know the names.'}, 'category_names': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Category names or slugs, e.g. ["SEO", "Turundus"]. Resolved to IDs; an unknown category fails the call (categories are never auto-created).'}, 'featured_media': {'type': 'integer', 'description': 'Featured image ID'}, 'meta_description': {'type': 'string', 'description': 'SEO meta description shown in Google (max ~155 chars). Stored in Rank Math (rank_math_description) once the post is created; check meta_description.saved in the result.'}}, 'additionalProperties': False}
create_wp_redirect
Create WordPress redirect
Create a 301 (or 302) redirect. Use when consolidating duplicate pages, retiring an old URL, or after changing a slug. "from" is a site-relative path with a leading slash; "to" may be relative or absolute. The platform detects the site's redirect backend itself: the Redirection plugin (Tools → Redirection) when installed, else Rank Math's Redirections module — the result names which one ("backend") and how to verify. Redirection: an existing rule for the same source is updated in place. Rank Math only: every redirect hangs on a post, so the platform attaches it to the post still at "from", else the destination page — pass object_id only when neither exists. The old URL must answer with the redirect status before you record the task as done.
Destructive
Input schema
{'type': 'object', 'required': ['from', 'to'], 'properties': {'to': {'type': 'string', 'description': 'Destination path or URL.'}, 'from': {'type': 'string', 'description': 'Old path, e.g. "/vana-leht/" (an absolute URL on the same site is accepted).'}, 'type': {'type': 'integer', 'description': '301 permanent (default) or 302 temporary.'}, 'object_id': {'type': 'integer', 'description': 'Optional, Rank Math backend only (ignored with the Redirection plugin). WordPress post/page ID to attach the redirect to when neither "from" nor "to" is a post or page on this site (e.g. both URLs are archives). Usually omit.'}}, 'additionalProperties': False}
create_wp_tag
Create WordPress tag
Create a WordPress tag by name. Idempotent: if a tag with that name/slug already exists, its id is returned with created:false. Usually you do not need this — create_wp_post / update_wp_post accept tag_names and create missing tags themselves.
Input schema
{'type': 'object', 'required': ['name'], 'properties': {'name': {'type': 'string', 'description': 'Tag name as it should appear on the site, e.g. "AI turundus".'}}, 'additionalProperties': False}
delegate_to_agents
Delegate to agents
TOP-DOWN delegation: the Turundusjuht (manager) pushes work to one or MORE teammate agents in a single call. Each assignment becomes a strategy card on that agent's own Command Center, stamped "Turundusjuhilt" (assigned_by=manager) so the agent knows it came from the boss — and it rolls back up to the manager's rollup automatically. Use when the user gives the manager a campaign/initiative that needs specific agents to act (e.g. new campaign → paid ads agent + copywriter agent). The manager decides ordering: use depends_on (which agent_keys must deliver first) and conditions (free-text extra requirements, e.g. "käivita alles pärast tekstide valmimist; eelarve €500"). Dependencies are informational discipline for the agents — the manager is the orchestrator.
Input schema
{'type': 'object', 'required': ['manager_token', 'assignments'], 'properties': {'assignments': {'type': 'array', 'items': {'type': 'object', 'required': ['agent_key', 'title'], 'properties': {'mode': {'enum': ['human_controlled', 'ai_controlled'], 'type': 'string', 'description': 'Default ai_controlled.'}, 'tasks': {'type': 'array', 'items': {'type': ['object', 'string']}, 'description': 'Subtasks for this agent. Items: {title, description?, label?} — or plain strings (a string becomes the task title).'}, 'title': {'type': 'string', 'description': 'Card title, e.g. "Uue kampaania käivitamine — xxx leht".'}, 'pillar': {'type': 'string', 'description': 'Marketing-plan pillar key (defaults to the pillar that owns this agent).'}, 'severity': {'enum': ['critical', 'high', 'medium', 'low'], 'type': 'string'}, 'strategy': {'type': 'string', 'description': 'Markdown brief/rationale shown under "View strategy".'}, 'agent_key': {'type': 'string', 'description': 'Teammate agent key (e.g. "paid", "copy", "seo") — must match a child dashboard\'s agent key under this manager.'}, 'conditions': {'type': 'string', 'description': "Manager's extra conditions/constraints in free text (budget, timing, approvals). Shown on the card."}, 'depends_on': {'type': 'array', 'items': {'type': 'string'}, 'description': 'agent_keys whose deliverables must come FIRST (e.g. paid depends_on ["copy"]). Shown on the card so the agent waits.'}}}, 'description': "One entry per target agent. Each becomes a strategy card on that agent's dashboard."}, 'manager_token': {'type': 'string', 'description': 'Public token of the manager (Turundusjuht) dashboard doing the delegating.'}}, 'additionalProperties': False}
delete_dashboard
Delete dashboard
Permanently delete a dashboard by its public token. This also deletes all widgets and cached data. Only agents from the owning project can delete.
Destructive
Input schema
{'type': 'object', 'required': ['token'], 'properties': {'token': {'type': 'string'}}, 'additionalProperties': False}
delete_drive_file
Delete drive file
Permanently delete a Drive file or folder by id. This cannot be undone. Requires a connected google_drive integration.
Destructive
Input schema
{'type': 'object', 'required': ['file_id'], 'properties': {'file_id': {'type': 'string', 'description': 'Drive file or folder id to delete.'}}, 'additionalProperties': False}
delete_google_review_reply
Delete Google review reply
Remove the business owner's reply from one Google review (DELETE …/reviews/{review_id}/reply); the review itself stays. A review without a reply is reported as changed=false with no API write and no approval card.
Destructive
Input schema
{'type': 'object', 'required': ['review_id'], 'properties': {'review_id': {'type': 'string', 'description': 'review_id from get_google_business_reviews.'}}, 'additionalProperties': False}
delete_gtm_tag
Delete GTM tag
Delete a tag from the GTM WORKSPACE by tag_id (from list_gtm_tags). Prefer update_gtm_tag with paused: true when the tag might be needed again. The deletion only reaches the live site once the human publishes the workspace in the GTM UI; there is no publish tool.
Destructive
Input schema
{'type': 'object', 'required': ['tag_id'], 'properties': {'tag_id': {'type': ['string', 'integer'], 'description': 'Tag id from list_gtm_tags'}}, 'additionalProperties': False}
delete_strategy_task
Delete strategy task
Delete a task from a strategy card. Identify the task by task_id (DB id) OR task_number (1-indexed order from get_strategy_status). task_id takes precedence if both are supplied. Use when a task is no longer relevant (e.g. the underlying condition changed) or was created in error. Does NOT enforce task_mode — any agent with access to the dashboard project can delete.
Destructive
Input schema
{'type': 'object', 'required': ['token', 'widget_id'], 'properties': {'token': {'type': 'string', 'description': 'Dashboard public_token'}, 'task_id': {'type': 'integer', 'description': 'Task ID within the strategy card. Either task_id or task_number is required. task_id wins if both supplied.'}, 'widget_id': {'type': 'integer', 'description': 'Strategy card widget ID'}, 'task_number': {'type': 'integer', 'description': 'Alternative to task_id: 1-indexed order of the task within the strategy card (as shown in get_strategy_status output).'}}, 'additionalProperties': False}
diagnose_connections
Diagnose connections
Run Connection Doctor for this project. Classifies missing configuration, expired authorization, temporary provider failures, and healthy connections without exposing credentials. Set live=true for bounded read-only provider checks.
Read only
Input schema
{'type': 'object', 'properties': {'live': {'type': 'boolean', 'default': False, 'description': 'Run a bounded read-only provider check when supported.'}, 'service': {'type': 'string', 'description': 'Optional service ID. Omit to diagnose every project connection.'}}, 'additionalProperties': False}
disconnect_service
Disconnect service
Disconnect an integrated service and remove its stored credentials. This is irreversible — the service will need to be reconnected with fresh credentials. Use when asked to "disconnect Slack", "remove the GA4 integration", or "unlink WordPress."
Destructive
Input schema
{'type': 'object', 'required': ['service'], 'properties': {'service': {'type': 'string', 'description': 'Service ID to disconnect'}}, 'additionalProperties': False}
domain_keywords
Domain keywords
Organic keywords a domain currently ranks for on Google, via DataForSEO Labs. Returns keyword, current position, monthly search volume, estimated traffic, CPC, and landing page URL. Use this for competitor audits ("what is competitor.ee ranking for?"), content gap analysis, and finding the highest-traffic pages of any domain. For your own ranking changes over time, prefer get_seoshark_keywords which tracks trends.
Read only
Input schema
{'type': 'object', 'required': ['target'], 'properties': {'limit': {'type': 'integer', 'default': 50, 'description': 'Max keywords to return (1–1000)'}, 'target': {'type': 'string', 'description': 'Domain to inspect (e.g. example.ee — no protocol)'}, 'language_code': {'type': 'string', 'default': 'et', 'description': 'Language code (et, en, ru, fi, ...)'}, 'location_code': {'type': 'integer', 'default': 2233, 'description': 'DataForSEO location code (2233 = Estonia)'}}, 'additionalProperties': False}
enable_google_ads_campaign
Enable Google ads campaign
Start one Google Ads campaign serving again (campaigns:mutate, update mask "status" = ENABLED). This starts spending real money, so it waits for a human click in the Postkast — the channel-level Autonomy autopilot does not cover it and neither does a trusted first-party agent token. Only a human putting this very Autonomy row (Google Ads › "Kampaaniate käivitamine") on Autopilot lets it run without a click, and the ceilings below hold even then. It is refused outright (no approval card) until a human has set the daily ceilings on the Autonomy page, when the campaign budget or the account total would go over them, or when the account is not in EUR. The answer carries the campaign daily budget read just before the change; if the budget moved between the approval and your repeat call, the approval is voided (budget_changed_since_approval) and you ask again. A campaign that is already enabled is reported as success with changed=false and no API write. campaign_id comes from list_google_ads_campaigns.
Destructive
Input schema
{'type': 'object', 'required': ['campaign_id'], 'properties': {'reason': {'type': 'string', 'description': 'Optional one sentence for the approval card and the audit log: why this campaign should start spending again.'}, 'campaign_id': {'type': 'string', 'description': 'Campaign id from list_google_ads_campaigns, e.g. "20713245160" (digits only, not the resource name)'}}, 'additionalProperties': False}
enable_meta_ad
Enable Meta ad
Start one Meta ad delivering again (POST /{id} status=ACTIVE). This can start spending real money, so it waits for a human click in the Postkast — the channel-level autopilot does not cover it and neither does a trusted first-party agent token. Only a human putting this very Autonomy row (Meta › "Käivitamine") on Autopilot lets it run without a click, and the ceilings below hold even then. It is refused outright (no approval card) until a human has set the daily ceilings on the Autonomy page, when the budget that would spend or the account total would go over them, or when the ad account is not in EUR. If the budget moved between the approval and your repeat call, the approval is voided (budget_changed_since_approval) and you ask again. Already active → success with changed=false. ad_id comes from list_meta_ads. An ad made from a client-approved creative (create_meta_ad_from_creative) shows up as running on the client dashboard once it is started.
Destructive
Input schema
{'type': 'object', 'required': ['ad_id'], 'properties': {'ad_id': {'type': 'string', 'description': 'Meta ad id from list_meta_ads (digits).'}, 'reason': {'type': 'string', 'description': 'Optional one sentence for the approval card and the audit log: why this ad should start spending again.'}}, 'additionalProperties': False}
enable_meta_adset
Enable Meta adset
Start one Meta ad set delivering again (POST /{id} status=ACTIVE). This can start spending real money, so it waits for a human click in the Postkast — the channel-level autopilot does not cover it and neither does a trusted first-party agent token. Only a human putting this very Autonomy row (Meta › "Käivitamine") on Autopilot lets it run without a click, and the ceilings below hold even then. It is refused outright (no approval card) until a human has set the daily ceilings on the Autonomy page, when the budget that would spend or the account total would go over them, or when the ad account is not in EUR. If the budget moved between the approval and your repeat call, the approval is voided (budget_changed_since_approval) and you ask again. Already active → success with changed=false. adset_id comes from list_meta_adsets.
Destructive
Input schema
{'type': 'object', 'required': ['adset_id'], 'properties': {'reason': {'type': 'string', 'description': 'Optional one sentence for the approval card and the audit log: why this ad set should start spending again.'}, 'adset_id': {'type': 'string', 'description': 'Meta ad set id from list_meta_adsets (digits).'}}, 'additionalProperties': False}
enable_meta_campaign
Enable Meta campaign
Start one Meta campaign delivering again (POST /{id} status=ACTIVE). This can start spending real money, so it waits for a human click in the Postkast — the channel-level autopilot does not cover it and neither does a trusted first-party agent token. Only a human putting this very Autonomy row (Meta › "Käivitamine") on Autopilot lets it run without a click, and the ceilings below hold even then. It is refused outright (no approval card) until a human has set the daily ceilings on the Autonomy page, when the budget that would spend or the account total would go over them, or when the ad account is not in EUR. If the budget moved between the approval and your repeat call, the approval is voided (budget_changed_since_approval) and you ask again. Already active → success with changed=false. campaign_id comes from list_meta_campaigns.
Destructive
Input schema
{'type': 'object', 'required': ['campaign_id'], 'properties': {'reason': {'type': 'string', 'description': 'Optional one sentence for the approval card and the audit log: why this campaign should start spending again.'}, 'campaign_id': {'type': 'string', 'description': 'Meta campaign id from list_meta_campaigns (digits).'}}, 'additionalProperties': False}
fetch
Fetch
Fetch details for a SharksAPI.AI search result by id. Use ids returned from the search tool, such as tool:get_ga4 or doc:overview.
Read only Destructive
Input schema
{'type': 'object', 'required': ['id'], 'properties': {'id': {'type': 'string', 'description': 'Result id returned by search.'}}, 'additionalProperties': False}
Output schema
{'type': 'object', 'required': ['id', 'title', 'text', 'url'], 'properties': {'id': {'type': 'string'}, 'url': {'type': 'string'}, 'text': {'type': 'string'}, 'title': {'type': 'string'}, 'metadata': {'type': 'object', 'additionalProperties': True}}, 'additionalProperties': False}
fill_brand_sections
Fill brand sections
Fill AI osakond brand guide sections from the client's brand book: sections {logo: {rules}, colors: {colors: [{role c1..c4, hex, name, use}]}, fonts: {heading, body}, tone: {address, scales {t1,t2,t3 1–5}, words_use[], words_avoid[], example_yes, example_no}, bank: {photo_style}, no: {restrictions, legal}, icons (v2 pages only): {style: line|filled|duotone, use}}. They are marked "Agent täitis · vaata üle" and do NOT open the gate until the client saves them; a section the client already saved is never overwritten.
Input schema
{'type': 'object', 'required': ['sections'], 'properties': {'token': {'type': 'string', 'description': 'Dashboard public_token. Optional — defaults to your own dashboard.'}, 'sections': {'type': 'object'}}, 'additionalProperties': False}
first_value_status
First value status
Show this project's activation milestones: approved agent, connected data source, first useful non-setup run, and public dashboard. Returns progress, time-to-first-value, the next action, and a suggested prompt without credentials or task results.
Read only
Input schema
{'type': 'object', 'properties': {}}
generate_image
Generate image
Generate an on-brand image with Google Gemini into the project's photo bank: a JPEG sized exactly for aspect_ratio (4:5 → 1080×1350, 1:1 → 1080×1080, 3:4 → 1080×1440, 9:16 → 1080×1920, 16:9 → 1920×1080) with a permanent public url for media_urls, a 7-day signed_url and an asset_id. The brand guide's colours, photo style and restrictions are added to your prompt, reference_image_ids (from list_creative_assets) go to the model as visual references, and brand_overlay=true puts the client's real logo in the corner its logo rules name, inside the platform safe zone, in the variant made for the background under it. Refused while the AI osakond brand guide is incomplete or when a reference shows people without consent; keep personal data out of the prompt and pass ai_generated=true wherever a publishing tool offers it.
Input schema
{'type': 'object', 'required': ['prompt', 'purpose'], 'properties': {'tags': {'type': 'array', 'items': {'type': 'string'}, 'maxItems': 10, 'description': 'Photo-bank tags for finding the image later, e.g. ["kevadkampaania", "köök"].'}, 'prompt': {'type': 'string', 'description': 'What the image shows: subject, setting, composition, light, mood (any language, max 4000 characters). No personal data — names, e-mails, phone numbers.'}, 'purpose': {'enum': ['social_post', 'ad', 'blog'], 'type': 'string', 'description': 'Where it will be used; sets the default aspect_ratio (social_post and ad → 4:5, blog → 16:9).'}, 'aspect_ratio': {'enum': ['1:1', '4:5', '3:4', '9:16', '16:9'], 'type': 'string', 'description': '4:5 = Instagram/Facebook feed, 9:16 = story or reel, 1:1 = square, 3:4 = tall feed post, 16:9 = blog header or link preview. Defaults from purpose.'}, 'brand_overlay': {'type': 'boolean', 'default': False, 'description': "Composite the client's logo from the brand guide: corner from its logo rules, margin inside the safe zone, light or dark variant by the background."}, 'logo_position': {'enum': ['top_left', 'top_right', 'bottom_left', 'bottom_right'], 'type': 'string', 'description': "Override the logo corner when the brand guide's rules do not fit this format (only with brand_overlay)."}, 'reference_image_ids': {'type': 'array', 'items': {'type': 'integer'}, 'maxItems': 3, 'description': "Up to 3 photo-bank ids (list_creative_assets) sent as visual references, e.g. the client's product or premises. Images flagged do_not_publish are refused."}}, 'additionalProperties': False}
get_activecampaign_automations
Get ActiveCampaign automations
Get marketing automations from ActiveCampaign with name, status (active/inactive), trigger type, and contact count. Use for reviewing automation workflows.
Read only
Input schema
{'type': 'object', 'properties': {'limit': {'type': 'integer', 'default': 20, 'description': 'Number of automations to return'}}, 'additionalProperties': False}
get_activecampaign_campaigns
Get ActiveCampaign campaigns
Get email marketing campaigns from ActiveCampaign with name, type, send date, open rate, and click rate. Use for email campaign performance review.
Read only
Input schema
{'type': 'object', 'properties': {'limit': {'type': 'integer', 'default': 20, 'description': 'Number of campaigns to return'}}, 'additionalProperties': False}
get_activecampaign_contacts
Get ActiveCampaign contacts
Get contacts from ActiveCampaign CRM/email marketing platform with email, name, tags, lists, and engagement score. Filter by email address to find a specific contact.
Read only
Input schema
{'type': 'object', 'properties': {'email': {'type': 'string', 'description': 'Filter by email address'}, 'limit': {'type': 'integer', 'default': 20, 'description': 'Number of contacts to return'}}, 'additionalProperties': False}
get_activecampaign_deals
Get ActiveCampaign deals
Get deals from ActiveCampaign CRM pipeline with value, stage, contact, and owner. Filter by pipeline stage to focus on specific deal phases.
Read only
Input schema
{'type': 'object', 'properties': {'limit': {'type': 'integer', 'default': 20, 'description': 'Number of deals to return'}, 'stage': {'type': 'string', 'description': 'Filter by pipeline stage'}}, 'additionalProperties': False}
get_ad_creatives
Get ad creatives
Meta ad creatives on the AI osakond Meta Ads tab and what the client decided on them. Each has id, title, status (needs_approval | new_version = waiting for the client; approved; running; revising; pause_requested; paused; resume_requested; rejected), text, change_note (the client's wish), text_pending_sync, external_ad_id. to_do lists what YOU must now do in Meta. Do it with the Meta write tools where they reach: approved → create_meta_ad_from_creative (makes a PAUSED ad from an image creative and records external_ad_id) then enable_meta_ad (the manager approves the start); pause_requested → pause_meta_ad; resume_requested → enable_meta_ad — starting or pausing through those tools updates the creative here by itself. What they cannot do (video creatives, the client's new text on a running ad = text_pending_sync, a connection without ads_management) you do in Ads Manager and confirm with update_ad_creative; revising ones get a new version via submit_ad_creative.
Read only
Input schema
{'type': 'object', 'properties': {'token': {'type': 'string', 'description': 'Dashboard public_token. Optional — defaults to your own dashboard.'}}, 'additionalProperties': False}
get_analytics_summary
Get analytics summary
Get a dashboard overview of all connected marketing platforms (GA4, Search Console, Facebook, LinkedIn, Twitter, Google Ads, Meta Ads) with their connection status, property IDs, and configuration. Use this first to understand which analytics sources are available before fetching specific data.
Read only
Input schema
{'type': 'object', 'properties': {}}
get_bing_backlinks
Get Bing backlinks
Free URL-level backlinks for the client's own site from Bing Webmaster Tools. Without url: the site's pages ranked by the number of inbound links Bing counted (paged). With url: the external pages linking to that URL, each with its anchor text. Use for link reclamation (linked pages that now 404 → check_url_status), link audits and "who links to us". Only the connected site — for other domains use backlinks_summary (DataForSEO).
Read only
Input schema
{'type': 'object', 'properties': {'url': {'type': 'string', 'description': 'Optional. One URL of the connected site to list its linking pages + anchors.'}, 'page': {'type': 'integer', 'minimum': 0, 'description': 'Result page, 0-based (default 0).'}}, 'additionalProperties': False}
get_bing_crawl_stats
Get Bing crawl stats
Get Bingbot crawl + index statistics for the connected site: pages crawled, crawl errors, indexed page count. Use for technical SEO health checks.
Read only
Input schema
{'type': 'object', 'properties': {}}
get_bing_top_pages
Get Bing top pages
Get best-performing pages in Bing search ranked by clicks. Returns URL, clicks, impressions, CTR, and average position for each page.
Read only
Input schema
{'type': 'object', 'required': ['start_date', 'end_date'], 'properties': {'limit': {'type': 'integer', 'default': 10}, 'end_date': {'type': 'string', 'format': 'date'}, 'start_date': {'type': 'string', 'format': 'date', 'description': 'Start date (YYYY-MM-DD). Omit both dates to get the last 28 days; the response carries the dates actually used, so report the period from those rather than assuming.'}}, 'additionalProperties': False}
get_bing_top_queries
Get Bing top queries
Get the top Bing search queries that bring visitors to the website. Returns keyword, clicks, impressions, CTR, and average position. Use to answer "what keywords do we rank for in Bing?"
Read only
Input schema
{'type': 'object', 'required': ['start_date', 'end_date'], 'properties': {'limit': {'type': 'integer', 'default': 10}, 'end_date': {'type': 'string', 'format': 'date'}, 'start_date': {'type': 'string', 'format': 'date', 'description': 'Start date (YYYY-MM-DD). Omit both dates to get the last 28 days; the response carries the dates actually used, so report the period from those rather than assuming.'}}, 'additionalProperties': False}
get_bing_url_info
Get Bing URL info
What Bing knows about up to 20 URLs of the connected Bing Webmaster site: HTTP status Bing saw, discovery date, last crawl date, document size, and the number of anchors (inbound links) Bing counted. Free; complements inspect_gsc_url for Bing/Copilot visibility.
Read only
Input schema
{'type': 'object', 'required': ['urls'], 'properties': {'urls': {'type': 'array', 'items': {'type': 'string'}, 'maxItems': 20, 'minItems': 1, 'description': 'Full URLs of the connected site.'}}, 'additionalProperties': False}
get_bing_webmaster
Get Bing webmaster
Fetch Bing organic search performance from Bing Webmaster Tools for a date range. Returns daily clicks, impressions, CTR, and average position in Bing search results. Complements Google Search Console with Microsoft/Bing search data.
Read only
Input schema
{'type': 'object', 'required': ['start_date', 'end_date'], 'properties': {'end_date': {'type': 'string', 'format': 'date'}, 'start_date': {'type': 'string', 'format': 'date', 'description': 'Start date (YYYY-MM-DD). Omit both dates to get the last 28 days; the response carries the dates actually used, so report the period from those rather than assuming.'}}, 'additionalProperties': False}
get_bluesky_feed
Get Bluesky feed
Get recent posts from a Bluesky account feed. Returns post text, timestamps, like/repost/reply counts, and embedded media. Defaults to the connected account.
Read only
Input schema
{'type': 'object', 'properties': {'limit': {'type': 'integer', 'default': 20, 'description': 'Number of posts to return'}, 'handle': {'type': 'string', 'description': 'Bluesky handle to get feed for. Defaults to connected account.'}}, 'additionalProperties': False}
get_bluesky_followers
Get Bluesky followers
List followers of a Bluesky account with display name, handle, bio, and follower count. Defaults to the connected account.
Read only
Input schema
{'type': 'object', 'properties': {'limit': {'type': 'integer', 'default': 20, 'description': 'Number of followers to return'}, 'handle': {'type': 'string', 'description': 'Bluesky handle. Defaults to connected account.'}}, 'additionalProperties': False}
get_bluesky_notifications
Get Bluesky notifications
Get recent Bluesky notifications: likes, reposts, follows, mentions, and replies. Returns notification type, author, timestamp, and related post text.
Read only
Input schema
{'type': 'object', 'properties': {'limit': {'type': 'integer', 'default': 20, 'description': 'Number of notifications to return'}}, 'additionalProperties': False}
get_bluesky_profile
Get Bluesky profile
Get a Bluesky (AT Protocol) user profile with display name, bio, follower/following counts, and post count. Defaults to the connected account handle.
Read only
Input schema
{'type': 'object', 'properties': {'handle': {'type': 'string', 'description': 'Bluesky handle (e.g., user.bsky.social). Defaults to connected account.'}}, 'additionalProperties': False}
get_brand_guide
Get brand guide
The AI osakond brand guide the client fills in: logo rules, colours (HEX), fonts, tone (sina/teie, scales, words to use and avoid, example sentences), photo style, restrictions and mandatory texts, liked examples, plus logo / icon / image-bank / font files. On a v2 page there is also an `icons` part (the icon set, its style line|filled|duotone and where icons are used): use only icons from `icons` and only in that style, never draw your own. brand_ready is the gate: while it is false you make NO images, videos, carousels or ad creatives (texts, SEO, search ads and the plan go on) — say "Ootab brändijuhist" and name missing_sections. Use an image-bank file only when usable=true (no people, or consent, and not a manufacturer picture without the right to advertise: usage_rights own | maker_ok | maker_no). If a brand book was uploaded and the logo, colours, fonts and tone sections are empty, read it and call fill_brand_sections.
Read only
Input schema
{'type': 'object', 'properties': {'token': {'type': 'string', 'description': 'Dashboard public_token. Optional — defaults to your own dashboard.'}}, 'additionalProperties': False}
get_campaign_stats
Get campaign stats
Get detailed performance statistics for a specific email campaign by ID. Returns total recipients, sent count, failed count, and pending count. Use for campaign performance review or answering "how did our email campaign perform?" or "what are the stats for campaign X?"
Read only
Input schema
{'type': 'object', 'required': ['campaign_id'], 'properties': {'campaign_id': {'type': 'integer', 'description': 'Email campaign ID'}}, 'additionalProperties': False}
get_clarity
Get Clarity
Fetch Microsoft Clarity session insights — sessions, dead clicks, rage clicks, scroll depth, JS errors, quickback clicks, engaged sessions. Clarity API only supports the last 1, 2, or 3 days (no historical range). Optionally break down by up to 3 dimensions: Browser, Device, OS, Country, URL, Source, Medium, Campaign, Channel, NewVsReturning. Use to answer "where do users get frustrated?" or "what are our UX dead spots?"
Read only
Input schema
{'type': 'object', 'properties': {'dimensions': {'type': 'array', 'items': {'type': 'string'}, 'maxItems': 3, 'description': 'Optional breakdown dimensions (up to 3): Browser, Device, OS, Country, URL, Source, Medium, Campaign, Channel, NewVsReturning'}, 'num_of_days': {'enum': [1, 2, 3], 'type': 'integer', 'default': 3, 'description': 'Number of days to analyze (1, 2, or 3 — Clarity API limit)'}}, 'additionalProperties': False}
get_client_messages
Get client messages
Messages the client wrote on their dashboard: under a "Sinult on vaja" item (thread = the strategy task you parked with needs_human / needs_access — the client answering your ask, possibly with a file) or in the dashboard-wide "Kirjuta agendile" thread (questions, ideas, feedback). Returns each thread with the task (id, title, your ask) and the messages in order; unread_only=true (default) returns only what you have not read yet and marks it read. Attachments are listed with a download URL that needs the dashboard cookie — ask the human to forward the file if you cannot fetch it. Read this at the start of every run; answer with reply_to_client.
Read only
Input schema
{'type': 'object', 'properties': {'limit': {'type': 'integer', 'default': 50, 'description': 'Max messages (newest threads first).'}, 'token': {'type': 'string', 'description': 'Dashboard public_token. Omit for your own dashboard.'}, 'unread_only': {'type': 'boolean', 'default': True}}, 'additionalProperties': False}
get_client_requests
Get client requests
The client's events and requests on the AI osakond dashboard ("Sinu sündmused ja soovid"): what is happening, when, channels (empty = you choose), extra budget, notes, attachments and the step it is on (sent → agent_working → in_plan → needs_client_approval | needs_growth_lead → done). Plan content 3 weeks before an event; a request with extra budget waits for the growth lead.
Read only
Input schema
{'type': 'object', 'properties': {'token': {'type': 'string', 'description': 'Dashboard public_token. Optional — defaults to your own dashboard.'}, 'open_only': {'type': 'boolean', 'description': 'Only requests that are not done (default true).'}}, 'additionalProperties': False}
get_connection_status
Get connection status
Check the current connection status and health of a specific integrated service. Returns service status, connection timestamp, and any metadata or configuration details. Use to verify a service is working before querying it, or answering "is GA4 connected?", "check Slack connection", or "why isn't WordPress working?"
Read only
Input schema
{'type': 'object', 'required': ['service'], 'properties': {'service': {'type': 'string', 'description': 'Service ID (e.g., slack, ga4, github, stripe)'}}, 'additionalProperties': False}
get_credit_status
Get credit status
Check current credit balance for this project. The monthly limit is only the recurring free allowance, not a hard usage cap. Purchased or admin-granted credits remain usable after the free allowance is exhausted. Returns total spendable credits and a status based on that total. Use this to check if the project has enough credits before performing multiple operations, or to inform the user about their credit status.
Read only
Input schema
{'type': 'object', 'properties': {}}
get_dashboard
Get dashboard
Fetch a dashboard's configuration by its public token. Returns the dashboard metadata, widget list, and public URL — but not the live data (data is fetched on view). Use this to inspect what you previously built.
Read only
Input schema
{'type': 'object', 'required': ['token'], 'properties': {'token': {'type': 'string', 'description': 'The public_token returned when the dashboard was created'}}, 'additionalProperties': False}
get_dashboard_access_link
Get dashboard access link
Get a short-lived signed URL that opens a password-protected dashboard of THIS project in a browser WITHOUT typing the password — for a browser session the agent drives itself (screen recording for a demo video, visual QA, a live walkthrough). Opening the URL sets the same unlock cookie a human gets after the password form (valid 24h; a manager unlock also opens its agent dashboards) and redirects to /{token}/index.html — keep the same browser context for the whole session. The link expires after ttl_minutes (default 15, max 60), works only for dashboards in your project and leaves the password in place. Treat it like the password: never paste it into posts, memory, tickets or a recording. To READ dashboard data use read_dashboard instead — this tool is only for when the real rendered page is needed.
Read only
Input schema
{'type': 'object', 'required': ['token'], 'properties': {'token': {'type': 'string', 'description': 'Dashboard public_token (agent or manager dashboard, same project as your auth).'}, 'ttl_minutes': {'type': 'integer', 'default': 15, 'description': 'How long the link itself stays openable (1–60). The unlock it grants lasts 24h regardless.'}}, 'additionalProperties': False}
get_data_manager_request_status
Get data manager request status
Processing status of one Data Manager upload (request_id returned by upload_offline_conversions): per destination the request status, record counts, errors and warnings with their reasons, and the user-data match rate range. Google processes uploads asynchronously — check a few minutes later, and again the next day in get_offline_conversion_upload_status.
Read only
Input schema
{'type': 'object', 'required': ['request_id'], 'properties': {'request_id': {'type': 'string'}}, 'additionalProperties': False}
get_department_plan
Get department plan
Read the living marketing plan of an AI osakond dashboard: the current snapshot (title, goal, KPIs with monthly history, pillars, calendar, milestones, budget, initiatives, rules, risks, decisions), the version history (who changed what and why) and plan documents waiting for your proposal. Every agent of the department works to this plan — read it at the start of a run and after "plan.version_created". Where every block of the client page gets its data and what is yours to write: get_seo_dashboard → data_map, or https://sharksapi.ai/docs/ai-osakond-andmed.md.
Read only
Input schema
{'type': 'object', 'properties': {'token': {'type': 'string', 'description': 'Dashboard public_token. Optional — defaults to your own dashboard.'}, 'include_snapshot_schema': {'type': 'boolean', 'description': 'Also return the snapshot shape (default false).'}}, 'additionalProperties': False}
get_department_plan_document
Get department plan document
Read a plan document the client or growth lead uploaded on the AI osakond dashboard (id from get_department_plan.pending_documents). Returns the text of PDF, Word (.docx), text and Markdown files. Compare it with the current plan, then call propose_plan_update.
Read only
Input schema
{'type': 'object', 'required': ['document_id'], 'properties': {'token': {'type': 'string', 'description': 'Dashboard public_token. Optional — defaults to your own dashboard.'}, 'document_id': {'type': 'integer'}}, 'additionalProperties': False}
get_doc
Get doc
Read a Google Doc by id. Returns title and plain-text content. Requires a connected google_docs integration.
Read only
Input schema
{'type': 'object', 'required': ['document_id'], 'properties': {'document_id': {'type': 'string', 'description': 'Google Doc id (from the URL).'}}, 'additionalProperties': False}
get_drive_file_content
Get drive file content
Download and return the text content of a Google Drive file. Google Docs are exported as plain text, Google Sheets as CSV (with parsed structured_data), Google Slides as text. Regular files (PDF, TXT, etc.) are downloaded as-is. Returns file_name, mime_type, content, structured_data, size, and web_view_link.
Read only
Input schema
{'type': 'object', 'required': ['file_id'], 'properties': {'file_id': {'type': 'string', 'description': 'Drive file id (from list_drive_files or search_drive).'}, 'mime_type': {'type': 'string', 'description': 'Optional override of the export mime type.'}}, 'additionalProperties': False}
get_email_campaigns
Get email campaigns
List email marketing campaigns with their name, status, and creation date. Use to get an overview of all campaigns or when the user asks "what email campaigns do we have?" or "show me our marketing emails."
Read only
Input schema
{'type': 'object', 'properties': {'limit': {'type': 'integer', 'default': 20}}, 'additionalProperties': False}
get_emails
Get emails
Retrieve a list of emails from the connected email account. Returns sender, recipient, subject, date, seen state, and body preview. Filter by mailbox folder, date range, sender, subject, unread state, and limit results. Use for reviewing email history or answering "what emails have we sent?" or "show recent email activity."
Read only
Input schema
{'type': 'object', 'properties': {'from': {'type': 'string', 'description': 'Only include messages from this email address.'}, 'limit': {'type': 'integer', 'default': 50}, 'folder': {'type': 'string', 'description': 'Mailbox folder to read. Accepts inbox, sent/Sent, sentitems/Sent Items, drafts, archive, junk/spam, deleted/trash.'}, 'status': {'enum': ['sent', 'scheduled', 'draft', 'failed'], 'type': 'string', 'description': 'Legacy alias for folder where possible: sent maps to the sent mailbox, draft maps to drafts. scheduled/failed are not mailbox folders.'}, 'end_date': {'type': 'string', 'description': 'Only include emails on or before this date (YYYY-MM-DD).'}, 'start_date': {'type': 'string', 'description': 'Only include emails on or after this date (YYYY-MM-DD).'}, 'unread_only': {'type': 'boolean', 'description': 'Only include unread messages.'}, 'subject_contains': {'type': 'string', 'description': 'Only include messages whose subject contains this text.'}}, 'additionalProperties': False}
get_facebook
Get Facebook
Fetch Facebook Page performance metrics for a date range. Returns page reach, post engagement (likes, comments, shares), follower count and growth, and page views. Use this for social media reporting or answering "how is our Facebook page performing?"
Read only
Input schema
{'type': 'object', 'required': ['start_date', 'end_date'], 'properties': {'end_date': {'type': 'string', 'format': 'date'}, 'aggregate': {'type': 'boolean', 'default': False}, 'start_date': {'type': 'string', 'format': 'date', 'description': 'Start date (YYYY-MM-DD). Omit both dates to get the last 28 days; the response carries the dates actually used, so report the period from those rather than assuming.'}}, 'additionalProperties': False}
get_facebook_posts
Get Facebook posts
List Facebook Page posts published in a date range with reactions, likes, comments and shares. Pass metrics to return only the named numeric fields per post (e.g. ["likes","comments","shares"]) so dashboard charts plot only those; omit it to get every metric.
Read only
Input schema
{'type': 'object', 'required': ['start_date', 'end_date'], 'properties': {'limit': {'type': 'integer', 'default': 50}, 'metrics': {'type': 'array', 'items': {'enum': ['views', 'reactions', 'likes', 'comments', 'shares'], 'type': 'string'}, 'description': 'Optional subset of per-post metrics to return: views, reactions, likes, comments, shares. Omit for all.'}, 'end_date': {'type': 'string', 'format': 'date'}, 'start_date': {'type': 'string', 'format': 'date', 'description': 'Start date (YYYY-MM-DD). Omit both dates to get the last 28 days; the response carries the dates actually used, so report the period from those rather than assuming.'}}, 'additionalProperties': False}
get_ga4
Get GA4
Fetch website traffic data from Google Analytics 4 for a date range. Returns daily or aggregated metrics: total users, new users, sessions, pageviews, bounce rate, average session duration, and engagement rate. Use aggregate=true for a single summary row (faster). Ideal for answering "how much traffic did we get?" or "what are our website stats?" For metric_card dashboard widgets pass metric=sessions|users|pageviews|bounce_rate|avg_session_duration|engagement_rate to get a single aggregated value for that field.
Read only
Input schema
{'type': 'object', 'required': ['start_date', 'end_date'], 'properties': {'host': {'type': 'string', 'description': 'Optional. Limit to one hostname of the property (GA4 hostName), e.g. "kookjakodu.fi" — for properties that measure several domains. "www." is matched too.'}, 'metric': {'type': 'string', 'description': 'Optional. When set, return only this metric field. Use for metric_card widgets. Valid values: sessions, users, pageviews, bounce_rate, avg_session_duration, engagement_rate'}, 'country': {'type': 'string', 'description': 'Optional. Limit to visitors from one country — GA4 country name, e.g. "Estonia", "Finland".'}, 'end_date': {'type': 'string', 'format': 'date', 'description': 'End date (YYYY-MM-DD)'}, 'aggregate': {'type': 'boolean', 'default': False, 'description': 'Return single aggregated row'}, 'start_date': {'type': 'string', 'format': 'date', 'description': 'Start date (YYYY-MM-DD)'}}, 'additionalProperties': False}
get_ga4_channels
Get GA4 channels
Break down website traffic by acquisition channel from GA4: sessions, users, pageviews, bounce rate, avg session duration, key_events (total conversions) and conversion_rate (key events / sessions, fraction 0–1) per channel — Organic Search, Direct, Social, Referral, Paid Search, Cross-network, Email, Display. Pass key_events=["generate_lead","click_to_call"] to add one column per named key event (find the names with get_ga4_events key_events_only=true). Use this to answer "where does our traffic come from?" or "which channel actually converts?"
Read only
Input schema
{'type': 'object', 'required': ['start_date', 'end_date'], 'properties': {'host': {'type': 'string', 'description': 'Optional. Limit to one hostname of the property (GA4 hostName), e.g. "kookjakodu.fi" — for properties that measure several domains. "www." is matched too.'}, 'country': {'type': 'string', 'description': 'Optional. Limit to visitors from one country — GA4 country name, e.g. "Estonia", "Finland".'}, 'end_date': {'type': 'string', 'format': 'date'}, 'breakdown': {'enum': ['channel', 'social_sources'], 'type': 'string', 'description': 'channel (default): one row per channel group. social_sources: Organic Social sessions and key events per day and platform (facebook, instagram, tiktok, linkedin, youtube, other) — website visits from organic posts.'}, 'key_events': {'type': 'array', 'items': {'type': 'string'}, 'description': 'GA4 key-event names to add as per-channel columns, e.g. ["generate_lead", "click_to_call", "kirjuta_meile"]. Total key_events is always included.'}, 'start_date': {'type': 'string', 'format': 'date', 'description': 'Start date (YYYY-MM-DD). Omit both dates to get the last 28 days; the response carries the dates actually used, so report the period from those rather than assuming.'}}, 'additionalProperties': False}
get_ga4_ecommerce
Get GA4 ecommerce
What an online shop sold, from GA4 e-commerce events, for a date range. breakdown=totals (default): sessions, purchases, revenue, add_to_carts, checkouts, aov (average order value) and conversion_rate (purchases / sessions, fraction 0–1). daily: the same per day, for trend charts. channels: purchases, revenue and sessions per GA4 channel group (Organic Search, Paid Search, Paid Social, Organic Social, Direct …) — which channel sells, last click. products: top products by revenue (item, purchased, revenue, viewed, added_to_cart). Revenue is in the property currency as the shop reports it (usually with VAT, without shipping). Zeros everywhere on a shop almost always mean the purchase event is not being sent to GA4 — say that, do not report "no sales". The e-commerce client pages (business_model=ecommerce) read orders and revenue from here.
Read only
Input schema
{'type': 'object', 'required': ['start_date', 'end_date'], 'properties': {'host': {'type': 'string', 'description': 'Optional. Limit to one hostname of the property (GA4 hostName), for properties that measure several shops.'}, 'limit': {'type': 'integer', 'description': 'products only: how many (default 10, max 50)'}, 'country': {'type': 'string', 'description': 'Optional. Limit to buyers from one country — GA4 country name, e.g. "Estonia".'}, 'end_date': {'type': 'string', 'format': 'date', 'description': 'End date (YYYY-MM-DD)'}, 'breakdown': {'enum': ['totals', 'daily', 'channels', 'products'], 'type': 'string', 'description': 'totals (default) · daily · channels · products'}, 'start_date': {'type': 'string', 'format': 'date', 'description': 'Start date (YYYY-MM-DD)'}}, 'additionalProperties': False}
get_ga4_events
Get GA4 events
Get all GA4 events with their counts and user numbers for a date range. Returns event_name, event_count, users. Shows what actions visitors take on the site (page_view, click, scroll, form_submit, purchase, etc). Use limit to control how many events. Set key_events_only=true to see only conversion/key events.
Read only
Input schema
{'type': 'object', 'required': ['start_date', 'end_date'], 'properties': {'host': {'type': 'string', 'description': 'Optional. Limit to one hostname of the property (GA4 hostName), e.g. "kookjakodu.fi" — for properties that measure several domains. "www." is matched too.'}, 'limit': {'type': 'integer', 'default': 20}, 'country': {'type': 'string', 'description': 'Optional. Limit to visitors from one country — GA4 country name, e.g. "Estonia", "Finland".'}, 'end_date': {'type': 'string', 'format': 'date'}, 'start_date': {'type': 'string', 'format': 'date', 'description': 'Start date (YYYY-MM-DD). Omit both dates to get the last 28 days; the response carries the dates actually used, so report the period from those rather than assuming.'}, 'key_events_only': {'type': 'boolean', 'default': False, 'description': 'Only show key events (conversions)'}}, 'additionalProperties': False}
get_ga4_landing_pages
Get GA4 landing pages
Compatibility alias for page-level GA4 traffic. Returns the same page title/path, pageviews and sessions fields as get_ga4_pages; use get_gsc_top_pages when you specifically need organic-search landing pages from Search Console.
Read only
Input schema
{'type': 'object', 'required': ['start_date', 'end_date'], 'properties': {'limit': {'type': 'integer', 'default': 10}, 'end_date': {'type': 'string', 'format': 'date'}, 'start_date': {'type': 'string', 'format': 'date', 'description': 'Start date (YYYY-MM-DD). Omit both dates to get the last 28 days; the response carries the dates actually used.'}}, 'additionalProperties': False}
get_ga4_new_vs_returning
Get GA4 new vs returning
Break down website visitors into new vs returning users from GA4. Returns sessions, users, engagement rate, and average session duration for each group. Use to answer "do we have a loyal audience?" or "what percentage of visitors come back?" Target: ~60-70% new, 30-40% returning.
Read only
Input schema
{'type': 'object', 'required': ['start_date', 'end_date'], 'properties': {'end_date': {'type': 'string', 'format': 'date'}, 'start_date': {'type': 'string', 'format': 'date', 'description': 'Start date (YYYY-MM-DD). Omit both dates to get the last 28 days; the response carries the dates actually used, so report the period from those rather than assuming.'}}, 'additionalProperties': False}
get_ga4_pages
Get GA4 pages
Get the top website pages from GA4 ranked by pageviews, with page title, path, pageviews and sessions. Use this for "top pages", "which pages got traffic?", or when a dashboard needs page-level GA4 rows.
Read only
Input schema
{'type': 'object', 'required': ['start_date', 'end_date'], 'properties': {'limit': {'type': 'integer', 'default': 10}, 'end_date': {'type': 'string', 'format': 'date'}, 'start_date': {'type': 'string', 'format': 'date', 'description': 'Start date (YYYY-MM-DD). Omit both dates to get the last 28 days; the response carries the dates actually used.'}}, 'additionalProperties': False}
get_gbp_review_link
Get gbp review link
Get the Google review link of the connected Google Business Profile location — the page where a customer writes a review (metadata.newReviewUri, or the writereview?placeid= link built from the place id), with the business name and Maps link. Use it in review requests, receipts or QR codes; send_review_request uses it by default.
Read only
Input schema
{'type': 'object', 'properties': {}}
get_google_ads
Get Google ads
Fetch Google Ads campaign performance data for a date range. Returns impressions, clicks, CTR, average CPC, total cost, conversions, and cost per conversion for each campaign. Optionally filter by campaign_id. Use for paid search reporting or answering "how are our Google Ads performing?" or "what is our ad spend ROI?"
Read only
Input schema
{'type': 'object', 'required': ['start_date', 'end_date'], 'properties': {'end_date': {'type': 'string', 'format': 'date', 'description': 'End date (YYYY-MM-DD, today, yesterday, or NdaysAgo).'}, 'breakdown': {'enum': ['campaign', 'daily', 'search_terms', 'conversion_actions', 'changes'], 'type': 'string', 'description': 'campaign (default): one row per campaign for the whole range. daily: one row per day for the whole account (date, impressions, clicks, cost/spend, conversions) — for trend charts. search_terms: the search terms that brought conversions (term, conversions, cost, clicks, cpa). conversion_actions: conversions per conversion action (form, call, …). changes: the account change history, last 30 days max (at, resource, operation, fields, campaign, ad_group, by = user email, client = UI/API, new_status, negative, keyword).'}, 'start_date': {'type': 'string', 'format': 'date', 'description': 'Start date (YYYY-MM-DD, today, yesterday, or NdaysAgo such as 30daysAgo). Omit both dates to get the last 28 days.'}, 'campaign_id': {'type': 'string', 'description': 'Specific campaign ID (optional)'}}, 'additionalProperties': False}
get_google_ads_ai_max_report
Get Google ads AI max report
AI Max for Search in one read: per Search campaign whether AI Max is on, text customization / final-URL expansion automation, text guidelines (term exclusions, messaging restrictions); spend, conversions and CPA split by match source (your keywords vs AI Max broad vs keywordless); and the query × generated headline × landing page combinations AI Max actually served. Use before deciding to keep, restrict or stop AI Max, and to find headlines or URLs that break the brand rules.
Read only
Input schema
{'type': 'object', 'properties': {'limit': {'type': 'integer', 'maximum': 500, 'minimum': 1, 'description': 'Max combination rows (default 100).'}, 'end_date': {'type': 'string', 'description': 'YYYY-MM-DD. Default: yesterday.'}, 'start_date': {'type': 'string', 'description': 'YYYY-MM-DD. Default: 30 days before end_date.'}, 'campaign_id': {'type': 'string', 'description': 'Only this campaign.'}}, 'additionalProperties': False}
get_google_ads_gaql_report
Get Google ads GAQL report
Read-only escape hatch: run one Google Ads Query Language SELECT against the connected account and get the rows. Only these resources are allowed: campaign, ad_group, ad_group_ad, ad_group_criterion, campaign_criterion, keyword_view, search_term_view, campaign_search_term_view, ai_max_search_term_ad_combination_view, final_url_expansion_asset_view, performance_max_placement_view, asset_group, asset_group_asset, asset_group_top_combination_view, ad_group_ad_asset_view, shopping_performance_view, geographic_view, user_location_view, landing_page_view, expanded_landing_page_view, age_range_view, gender_view, conversion_action, customer, shared_set, shared_criterion, campaign_shared_set, customer_negative_criterion, change_event, recommendation, bidding_strategy, campaign_budget, offline_conversion_upload_conversion_action_summary, offline_conversion_upload_client_summary, product_group_view, asset, label, campaign_asset, ad_group_asset, customer_asset. LIMIT is capped at 1000. Use when a dedicated tool does not have the field you need (impression share, hour/device/geo segments, change_event, recommendations, asset performance). Writes are impossible through this tool.
Read only
Input schema
{'type': 'object', 'required': ['query'], 'properties': {'query': {'type': 'string', 'description': 'e.g. SELECT campaign.name, metrics.search_budget_lost_impression_share FROM campaign WHERE segments.date DURING LAST_30_DAYS'}}, 'additionalProperties': False}
get_google_ads_pmax_report
Get Google ads PMax report
Performance Max transparency: per PMax campaign the cost / conversions / value split by channel (Search, Shopping via product data, YouTube, Display, Discover, Gmail, Maps, Search partners — segments.ad_network_type), asset groups with ad strength and results, top placements (impressions only — Google gives no cost per placement), and PMax search terms with a brand vs non-brand share when brand_terms are given. Use to see where PMax actually spends and whether it lives off brand searches.
Read only
Input schema
{'type': 'object', 'properties': {'end_date': {'type': 'string', 'description': 'YYYY-MM-DD. Default: yesterday.'}, 'start_date': {'type': 'string', 'description': 'YYYY-MM-DD. Default: 30 days before end_date.'}, 'brand_terms': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Brand spellings, e.g. ["firmus","firmus elekter"], to measure brand share of PMax search terms.'}, 'campaign_id': {'type': 'string', 'description': 'Only this PMax campaign.'}}, 'additionalProperties': False}
get_google_ads_search_terms
Get Google ads search terms
The actual search queries the Google Ads account paid for, with cost, clicks, conversions, value and CPA per query — Search (search_term_view) and, with include_pmax, Performance Max (campaign_search_term_view). Each Search row also carries match_source (ADVERTISER_PROVIDED_KEYWORD, AI_MAX_KEYWORDLESS, AI_MAX_BROAD_MATCH, PERFORMANCE_MAX…) and status (ADDED / EXCLUDED / NONE). Also returns an n-gram summary (1–3 words) of spend without conversions, so wasted themes are visible. Use it for the weekly search-term pass before add_google_ads_negative_keywords / add_google_ads_shared_negatives / add_google_ads_keywords.
Read only
Input schema
{'type': 'object', 'properties': {'limit': {'type': 'integer', 'maximum': 1000, 'minimum': 1, 'description': 'Max rows, by cost (default 200).'}, 'end_date': {'type': 'string', 'description': 'YYYY-MM-DD. Default: yesterday.'}, 'start_date': {'type': 'string', 'description': 'YYYY-MM-DD. Default: 30 days before end_date.'}, 'campaign_id': {'type': 'string', 'description': 'Only this campaign.'}, 'include_pmax': {'type': 'boolean', 'description': 'Also Performance Max search terms (default true).'}, 'min_cost_eur': {'type': 'number', 'description': 'Only queries that cost at least this much (default 0).'}, 'only_without_conversions': {'type': 'boolean', 'description': 'Only queries with 0 conversions.'}}, 'additionalProperties': False}
get_google_alerts
Get Google alerts
Retrieve Google Alerts mentions showing where your brand or tracked keywords appeared on the web. Returns source URL, title, date, auto-detected sentiment (positive/negative/neutral), and category (News, Blog, Social Media, etc). Filter by sentiment, category, date range, or unread status. Use refresh=true to fetch latest alerts from RSS. Ideal for brand reputation monitoring or PR tracking.
Read only
Input schema
{'type': 'object', 'properties': {'days': {'type': 'integer', 'description': 'Only show alerts from last N days'}, 'limit': {'type': 'integer', 'default': 20, 'description': 'Number of alerts to return'}, 'refresh': {'type': 'boolean', 'default': False, 'description': 'Fetch fresh alerts from RSS before returning'}, 'category': {'type': 'string', 'description': 'Filter by category (News, Blog, Social Media, etc)'}, 'sentiment': {'enum': ['positive', 'negative', 'neutral'], 'type': 'string', 'description': 'Filter by sentiment'}, 'unread_only': {'type': 'boolean', 'default': False, 'description': 'Only show unread alerts'}}, 'additionalProperties': False}
get_google_business_insights
Get Google business insights
Fetch Google Business Profile performance insights for a date range. Returns Maps views, Search views, website clicks, phone calls, direction requests. Use to answer "how visible are we on Google Maps?" or "how many people found us via Google Business?" breakdown=daily gives the same numbers day by day ({rows: [{date, views_search, views_maps, views, website, calls, directions, actions}], data_until}); Google fills the last 2–4 days later, data_until is the last day with numbers. breakdown=search_keywords gives the searches that showed the profile, counted per calendar month (the months of start_date..end_date; a month that has not ended has no data yet).
Read only
Input schema
{'type': 'object', 'required': ['start_date', 'end_date'], 'properties': {'limit': {'type': 'integer', 'maximum': 500, 'minimum': 1, 'description': 'Optional, search_keywords only: how many terms, most impressions first (default 50).'}, 'end_date': {'type': 'string', 'format': 'date'}, 'breakdown': {'enum': ['total', 'daily', 'search_keywords'], 'type': 'string', 'description': 'Optional. total (default): one sum per metric. daily: one row per day. search_keywords: {months, keywords: [{term, impressions, fewer_than}]} — Google hides small counts, such a term has impressions null and fewer_than (e.g. 15).'}, 'start_date': {'type': 'string', 'format': 'date', 'description': 'Start date (YYYY-MM-DD). Omit both dates to get the last 28 days; the response carries the dates actually used, so report the period from those rather than assuming.'}}, 'additionalProperties': False}
get_google_business_local_seo
Get Google business local SEO
Combined Google Business Profile report: location info, visibility (Maps + Search views), actions (website clicks, calls, directions), and reviews (count, average rating, 5 most recent). A single-call overview for local SEO health.
Read only
Input schema
{'type': 'object', 'required': ['start_date', 'end_date'], 'properties': {'end_date': {'type': 'string', 'format': 'date'}, 'start_date': {'type': 'string', 'format': 'date', 'description': 'Start date (YYYY-MM-DD). Omit both dates to get the last 28 days; the response carries the dates actually used, so report the period from those rather than assuming.'}}, 'additionalProperties': False}
get_google_business_reviews
Get Google business reviews
Fetch Google Business Profile reviews — rating, reviewer name, comment text, reply status. Returns the most recent reviews. Use to answer "what do customers say about us?" or "what is our Google rating?" 90% of customers check reviews before buying. with_summary=true answers {average_rating, total_review_count, answered, unanswered, read, complete, reviews} — Google's own average and count, and how many of the reviews read carry the owner's reply.
Read only
Input schema
{'type': 'object', 'properties': {'limit': {'type': 'integer', 'maximum': 500, 'minimum': 1, 'description': 'Optional, with with_summary only: how many reviews to read, newest first (default 50, max 500). answered/unanswered count these; complete=true means every review was read.'}, 'with_summary': {'type': 'boolean', 'description': 'Optional. true: answer an object with the rating summary and the reply count next to the reviews (newest first). Default false: the plain list of the latest reviews.'}}, 'additionalProperties': False}
get_gsc_brand_queries
Get GSC brand queries
Filter Google Search Console queries by brand name and compute brand click share. Returns brand clicks, brand impressions, total clicks, total impressions, brand_click_share_pct (%), and the top individual brand queries. Use to answer "what share of our organic traffic comes from people searching our brand name?" Pass brand_keyword for the exact brand term; if omitted, the project name is used.
Read only
Input schema
{'type': 'object', 'required': ['start_date', 'end_date'], 'properties': {'limit': {'type': 'integer', 'default': 20, 'description': 'Max brand queries to return'}, 'country': {'type': 'string', 'description': 'Optional ISO-3166-1 alpha-3 country code, e.g. "est", "fin", to compute the brand share in one search market.'}, 'end_date': {'type': 'string', 'format': 'date'}, 'site_url': {'type': 'string', 'description': 'Optional. Another Search Console property of the SAME client instead of the connected one. Only properties an admin listed for this project are accepted.'}, 'start_date': {'type': 'string', 'format': 'date', 'description': 'Start date (YYYY-MM-DD). Omit both dates to get the last 28 days; the response carries the dates actually used, so report the period from those rather than assuming.'}, 'brand_keyword': {'type': 'string', 'description': 'Brand name to filter queries by (case-insensitive contains match)'}}, 'additionalProperties': False}
get_gsc_keyword_positions
Get GSC keyword positions
Daily Google ranking position of a fixed set of search terms from Search Console — the data source for a "SEO positsioonid" rank-trend chart. Pass keywords (exact search terms, e.g. ["soojuspump","maaküte"]); when omitted the tracked keyword list from the connected SeoShark project is used (top_n of them), and as a last resort the top queries by clicks. Returns one row per day: {date, "<keyword>": position|null, ...} — null = no impressions that day (a gap, not rank 0). Position is the GSC daily average for the EXACT term (case-insensitive), so it is stable and comparable month to month. Use for chart_line widgets with display_config.y_axis.reverse=true; pass summary=true for a table of current positions (last 7 days vs previous 7). Note GSC data lags ~2 days. Filter by country (alpha-3, e.g. "est") to see one market.
Read only
Input schema
{'type': 'object', 'properties': {'days': {'type': 'integer', 'default': 30, 'description': 'Lookback window in days (used when start_date/end_date are omitted).'}, 'page': {'type': 'string', 'description': 'Only count rankings of pages whose URL contains this substring.'}, 'top_n': {'type': 'integer', 'default': 6, 'description': 'How many tracked keywords to auto-select when keywords is omitted (best current SeoShark position first).'}, 'country': {'type': 'string', 'description': 'ISO-3166-1 alpha-3 country code, e.g. "est", "fin".'}, 'summary': {'type': 'boolean', 'default': False, 'description': 'Return one row per keyword instead of daily rows: {keyword, position (impression-weighted avg of the last 7 reported days), previous_position (the 7 days before), change (+ = improved), clicks_7d, impressions_7d, days_seen_7d}. Use for a "hetkeseis" table widget next to the rank-trend chart.'}, 'end_date': {'type': 'string', 'format': 'date'}, 'keywords': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Exact search terms to track (max 20). Omit to use the SeoShark tracked keyword list.'}, 'site_url': {'type': 'string', 'description': 'Optional. Another Search Console property of the SAME client (e.g. "sc-domain:kookjakodu.fi") instead of the connected one. Only properties an admin listed for this project (dashboard Seaded → Domeenid) are accepted.'}, 'start_date': {'type': 'string', 'format': 'date', 'description': 'Start date (YYYY-MM-DD). Omit both dates to get the last 30 days.'}, 'with_impressions': {'type': 'boolean', 'default': False, 'description': 'Daily rows only: add "_impressions": {"<keyword>": n} to each day, so an average over several days can be weighted by impressions the way Search Console averages a period (a day with one search must not count as much as a day with forty). Leave it off for chart_line widgets — they draw every key as a line.'}}, 'additionalProperties': False}
get_gsc_top_pages
Get GSC top pages
Get the best-performing website pages in Google search ranked by clicks. Returns URL, clicks, impressions, CTR, and average position for each page. Use this to find "which pages bring the most organic traffic?" or "what are our strongest landing pages?"
Read only
Input schema
{'type': 'object', 'required': ['start_date', 'end_date'], 'properties': {'limit': {'type': 'integer', 'default': 10}, 'query': {'type': 'string', 'description': 'Optional search-query substring filter. Use this when you need pages that ranked for a specific term.'}, 'country': {'type': 'string', 'description': 'Optional ISO-3166-1 alpha-3 country code, e.g. "est", "fin", to limit pages to one search market.'}, 'end_date': {'type': 'string', 'format': 'date'}, 'site_url': {'type': 'string', 'description': 'Optional. Another Search Console property of the SAME client (e.g. "sc-domain:kookjakodu.fi") instead of the connected one. Only properties an admin listed for this project (dashboard Seaded → Domeenid) are accepted.'}, 'start_date': {'type': 'string', 'format': 'date', 'description': 'Start date (YYYY-MM-DD). Omit both dates to get the last 28 days; the response carries the dates actually used, so report the period from those rather than assuming.'}}, 'additionalProperties': False}
get_gsc_top_queries
Get GSC top queries
Get the top Google search queries that bring visitors to the website. Returns keyword, clicks, impressions, CTR, and average position. Use this to answer "what keywords do we rank for?" or "which search terms drive traffic?" Essential for SEO keyword strategy. Filter by country (ISO-3166 alpha-3, e.g. "fin" for Finland, "est" for Estonia) to see per-market keywords, and/or by page (substring, e.g. "/fi/") to scope to one section.
Read only
Input schema
{'type': 'object', 'required': ['start_date', 'end_date'], 'properties': {'page': {'type': 'string', 'description': 'Only queries for pages whose URL contains this substring, e.g. "/fi/".'}, 'limit': {'type': 'integer', 'default': 10}, 'country': {'type': 'string', 'description': 'ISO-3166-1 alpha-3 country code, e.g. "fin", "est", "swe", "nor".'}, 'end_date': {'type': 'string', 'format': 'date'}, 'site_url': {'type': 'string', 'description': 'Optional. Another Search Console property of the SAME client (e.g. "sc-domain:kookjakodu.fi") instead of the connected one. Only properties an admin listed for this project (dashboard Seaded → Domeenid) are accepted.'}, 'start_date': {'type': 'string', 'format': 'date', 'description': 'Start date (YYYY-MM-DD). Omit both dates to get the last 28 days; the response carries the dates actually used, so report the period from those rather than assuming.'}}, 'additionalProperties': False}
get_gtm_container
Get GTM container
Overview of the connected Google Tag Manager container: name, GTM-XXXX public id, active workspace, counts of tags/triggers/variables (also tags by type and paused tags) and the currently published live version. Start here before adding or editing tags.
Read only
Input schema
{'type': 'object', 'properties': {}}
get_instagram
Get Instagram
Fetch Instagram Business account performance metrics for a date range. Returns reach, impressions, profile views, website clicks and follower count. Use this for Instagram reporting or answering "how is our Instagram performing?"
Read only
Input schema
{'type': 'object', 'required': ['start_date', 'end_date'], 'properties': {'end_date': {'type': 'string', 'format': 'date'}, 'start_date': {'type': 'string', 'format': 'date', 'description': 'Start date (YYYY-MM-DD). Omit both dates to get the last 28 days; the response carries the dates actually used, so report the period from those rather than assuming.'}}, 'additionalProperties': False}
get_instagram_posts
Get Instagram posts
List Instagram Business posts published in a date range with media type, likes and comments. Pass metrics to return only the named numeric fields per post (e.g. ["likes","comments","shares","saves"]) so dashboard charts plot only those; omit it to get every metric.
Read only
Input schema
{'type': 'object', 'required': ['start_date', 'end_date'], 'properties': {'limit': {'type': 'integer', 'default': 50}, 'metrics': {'type': 'array', 'items': {'enum': ['views', 'reach', 'total_interactions', 'likes', 'comments', 'shares', 'saves'], 'type': 'string'}, 'description': 'Optional subset of per-post metrics to return: views, reach, total_interactions, likes, comments, shares, saves. Omit for all.'}, 'end_date': {'type': 'string', 'format': 'date'}, 'start_date': {'type': 'string', 'format': 'date', 'description': 'Start date (YYYY-MM-DD). Omit both dates to get the last 28 days; the response carries the dates actually used, so report the period from those rather than assuming.'}}, 'additionalProperties': False}
get_jotform_forms
Get Jotform forms
Get online forms from Jotform with form title, creation date, submission count, and status. Use to see what forms are collecting data.
Read only
Input schema
{'type': 'object', 'properties': {'limit': {'type': 'integer', 'default': 20, 'description': 'Number of forms to return'}}, 'additionalProperties': False}
get_jotform_submissions
Get Jotform submissions
Get submitted responses for a specific Jotform form. Returns all field values, submission date, and respondent info. Requires form_id from get_jotform_forms.
Read only
Input schema
{'type': 'object', 'required': ['form_id'], 'properties': {'limit': {'type': 'integer', 'default': 20, 'description': 'Number of submissions to return'}, 'form_id': {'type': 'string', 'description': 'Form ID to get submissions for'}}, 'additionalProperties': False}
get_linkedin
Get LinkedIn
Fetch LinkedIn Company Page analytics for a date range. Returns post impressions, engagement metrics (reactions, comments, shares), follower count and demographics. Use this for B2B social media reporting or answering "how is our LinkedIn performing?"
Read only
Input schema
{'type': 'object', 'required': ['start_date', 'end_date'], 'properties': {'end_date': {'type': 'string', 'format': 'date'}, 'start_date': {'type': 'string', 'format': 'date', 'description': 'Start date (YYYY-MM-DD). Omit both dates to get the last 28 days; the response carries the dates actually used, so report the period from those rather than assuming.'}}, 'additionalProperties': False}
get_linkedin_posts
Get LinkedIn posts
List LinkedIn Company Page posts published in a date range, one row per post with impressions, unique impressions, clicks, reactions, comments, reposts and engagement rate (organic + sponsored combined, via the Pages Data Portability API). Newest first; each row carries the post text, media type and permalink. Use for "which LinkedIn posts performed best", per-post reporting, or a table/chart_bar dashboard widget. Pass metrics to return only the named numeric fields (e.g. ["impressions","reactions"]). get_linkedin gives the page-level totals instead.
Read only
Input schema
{'type': 'object', 'required': ['start_date', 'end_date'], 'properties': {'limit': {'type': 'integer', 'default': 50, 'description': 'Max posts to inspect (1-100). Each post costs one analytics call, so keep it modest.'}, 'metrics': {'type': 'array', 'items': {'enum': ['impressions', 'unique_impressions', 'clicks', 'reactions', 'comments', 'reposts', 'engagement_rate'], 'type': 'string'}, 'description': 'Optional subset of per-post metrics to return: impressions, unique_impressions, clicks, reactions, comments, reposts, engagement_rate. Omit for all.'}, 'end_date': {'type': 'string', 'format': 'date'}, 'start_date': {'type': 'string', 'format': 'date', 'description': 'Start date (YYYY-MM-DD). Omit both dates to get the last 28 days; the response carries the dates actually used, so report the period from those rather than assuming.'}}, 'additionalProperties': False}
get_merchant_products
Get merchant products
Products of the connected Google Merchant Center account as Google processed them: offer id, title, price, availability, brand, GTIN, link, and per product the status per destination (approved / pending / disapproved countries) and every item-level issue (code, severity, attribute, description, resolution). With only_issues the list is limited to products that have issues, and issue_summary counts products per issue code. Use it to find why products do not serve in Shopping / Performance Max / free listings.
Read only
Input schema
{'type': 'object', 'properties': {'limit': {'type': 'integer', 'maximum': 500, 'minimum': 1, 'description': 'Product rows to return (default 100).'}, 'severity': {'enum': ['DISAPPROVED', 'DEMOTED', 'NOT_IMPACTED', 'ANY'], 'type': 'string', 'description': 'Only issues of this severity (default ANY).'}, 'only_issues': {'type': 'boolean', 'description': 'Only products with at least one issue (default true).'}, 'max_products': {'type': 'integer', 'maximum': 5000, 'minimum': 1, 'description': 'Products to scan (default 1000).'}}, 'additionalProperties': False}
get_meta_ad_creatives
Get Meta ad creatives
What each Meta ad actually shows and whether Meta accepts it: primary text, headline, CTA, link, image hash / video id, format (single image, video, carousel, dynamic/flexible), the Facebook post id and Instagram media id behind the ad, effective_status, and review problems (issues_info, ad_review_feedback with the policy reason). Also groups ads into concept clusters (same image/video, or near-identical text) with spend share, so near-duplicates that Meta's Andromeda retrieval treats as one ad are visible. Use before briefing new creative, for creative diversity and for repairing disapproved ads.
Read only
Input schema
{'type': 'object', 'properties': {'limit': {'type': 'integer', 'maximum': 500, 'minimum': 1, 'description': 'Max ads (default 200).'}, 'status': {'enum': ['active', 'with_issues', 'all'], 'type': 'string', 'description': 'active = ACTIVE; with_issues = DISAPPROVED / WITH_ISSUES / PENDING_REVIEW; all = also paused (default active).'}, 'adset_id': {'type': 'string'}, 'spend_days': {'type': 'integer', 'maximum': 90, 'minimum': 1, 'description': 'Spend window for the spend share (default 28).'}, 'campaign_id': {'type': 'string'}}, 'additionalProperties': False}
get_meta_ad_insights
Get Meta ad insights
Meta Ads performance at ad, ad set or campaign level, over time (daily, weekly or whole period) and optionally broken down by age, gender, country, region, placement (publisher_platform, platform_position) or device. Per row: spend, impressions, reach, frequency, link CTR, CPM, results and cost per result for the chosen action (lead, purchase, complete_registration…), video hook rate (3-second views ÷ impressions) and hold rate (ThruPlay ÷ 3-second views), and Meta's quality / engagement / conversion rankings. With level=ad and time_increment=7 every ad also gets a fatigue verdict (fatigued / watch / healthy / too_little_data) from frequency rising while CTR and cost per result worsen. Use for creative fatigue, placement and segment analysis, value-rule evidence and weekly reviews; get_meta_ads stays the account-level summary.
Read only
Input schema
{'type': 'object', 'properties': {'level': {'enum': ['ad', 'adset', 'campaign'], 'type': 'string', 'description': 'Default ad.'}, 'limit': {'type': 'integer', 'maximum': 2000, 'minimum': 1, 'description': 'Max rows (default 500).'}, 'adset_id': {'type': 'string'}, 'end_date': {'type': 'string', 'description': 'YYYY-MM-DD. Default: yesterday.'}, 'breakdowns': {'type': 'array', 'items': {'enum': ['age', 'gender', 'country', 'region', 'publisher_platform', 'platform_position', 'device_platform', 'impression_device'], 'type': 'string'}, 'description': 'Max 2. Placement: ["publisher_platform","platform_position"].'}, 'start_date': {'type': 'string', 'description': 'YYYY-MM-DD. Default: 28 days before end_date.'}, 'active_only': {'type': 'boolean', 'description': 'Only ads/ad sets/campaigns delivering now (default false).'}, 'campaign_id': {'type': 'string'}, 'result_action': {'type': 'string', 'description': 'Action type counted as the result, e.g. lead, purchase, offsite_conversion.fb_pixel_lead, onsite_conversion.lead_grouped, complete_registration, link_click. Default: lead, else purchase, else link_click.'}, 'time_increment': {'enum': ['1', '7', 'all_days'], 'type': 'string', 'description': '1 = daily, 7 = weekly, all_days = one row per object (default 7).'}, 'target_cost_per_result': {'type': 'number', 'description': 'Target CPA in account currency: fatigue is judged only for ads that spent at least 2× this in the period.'}}, 'additionalProperties': False}
get_meta_ads
Get Meta ads
Fetch Meta Ads (Facebook & Instagram) campaign performance for a date range. Returns spend, impressions, reach, clicks, CTR, CPC, conversions, cost per result, and ROAS for each campaign. Use for paid social reporting or answering "how are our Facebook/Instagram ads performing?" or "what is our Meta Ads ROAS?"
Read only
Input schema
{'type': 'object', 'required': ['start_date', 'end_date'], 'properties': {'end_date': {'type': 'string', 'format': 'date', 'description': 'End date (YYYY-MM-DD, today, yesterday, or NdaysAgo).'}, 'breakdown': {'enum': ['campaign', 'daily', 'ads', 'conversion_actions', 'changes'], 'type': 'string', 'description': 'campaign (default): one row per campaign for the whole range (with effective_status, updated_time). daily: one row per day for the whole account (date, impressions, clicks, cost/spend, conversions, leads) — for trend charts. ads: the ads that brought leads (ad, campaign, leads, spend, cpl). conversion_actions: lead-type actions with counts (also 0) + the account pixels with last_fired. changes: the account activity log (at, type, label, object, by).'}, 'start_date': {'type': 'string', 'format': 'date', 'description': 'Start date (YYYY-MM-DD, today, yesterday, or NdaysAgo such as 30daysAgo). Omit both dates to get the last 28 days.'}}, 'additionalProperties': False}
get_meta_signal_health
Get Meta signal health
Health of the Meta pixels / datasets of the connected ad account: last fired, event volume per event over the period, browser (pixel) vs server (Conversions API) volume per event, share of events carrying customer information and which match keys arrive (fbp/fbc cookies, email, phone, external_id), Event Match Quality and coverage from the Dataset Quality API when Meta has enough volume to score, and which pixel/event each ad set optimises for. Ends with findings (no server events, optimisation event with too little volume to leave learning, no customer info, stale pixel). Use before scaling, when results drop while spend is flat, and after site/GTM/consent changes.
Read only
Input schema
{'type': 'object', 'properties': {'days': {'type': 'integer', 'maximum': 28, 'minimum': 1, 'description': 'Look-back (default 7).'}, 'pixel_id': {'type': 'string', 'description': 'Only this pixel/dataset (default: all of the ad account).'}}, 'additionalProperties': False}
get_my_tasks
Get my tasks
For a channel agent: your open work in one call — unfinished tasks on your strategy cards and your channel's planned activities, plus your pillar of the plan and whether the client approved it. Call it at the start of every run.
Read only
Input schema
{'type': 'object', 'properties': {}}
get_offline_conversion_upload_status
Get offline conversion upload status
Health of offline / CRM conversion imports as Google reports it: per conversion action the upload status, successful / pending / total events and alerts (e.g. unmatched GCLIDs, clicks too old), plus the import actions and whether each is primary for bidding. With request_id (from upload_offline_conversions) also the Data Manager processing status of that upload.
Read only
Input schema
{'type': 'object', 'properties': {'request_id': {'type': 'string', 'description': 'Optional Data Manager request id.'}}, 'additionalProperties': False}
get_onboarding_status
Get onboarding status
START HERE after registering. The onboarding checklist for this project, in order: interview your person (exact questions to ask), connect their data sources, give the client their own sign-in, first useful result, an audit and plan the client approves, and a first recurring report. Each step says if it is done and what to do next. Works the same in any AI client; call it again after each step.
Read only
Input schema
{'type': 'object', 'properties': {}}
get_plan_document
Get plan document
Read the team's full marketing-plan DOCUMENT (markdown) — the living plan text shown and edited on the /plan page and downloadable as PDF. Returns the markdown, when it was last updated, when subagent tasks were last synced to it, and dirty=true when the document changed after the last sync (meaning the manager must re-align subagent tasks). Structured plan data (KPIs, pillars) lives in set_marketing_plan; this is the narrative document.
Read only
Input schema
{'type': 'object', 'properties': {'manager_token': {'type': 'string', 'description': "Manager dashboard token (optional; defaults to the project's manager dashboard)."}}, 'additionalProperties': False}
get_posthog_events
Get PostHog events
Get tracked events from PostHog product analytics with event name, timestamp, user, and properties. Filter by specific event name for targeted analysis.
Read only
Input schema
{'type': 'object', 'properties': {'event': {'type': 'string', 'description': 'Filter by event name'}, 'limit': {'type': 'integer', 'default': 20, 'description': 'Number of events to return'}}, 'additionalProperties': False}
get_posthog_feature_flags
Get PostHog feature flags
Get feature flags from PostHog with name, key, active status, rollout percentage, and targeting filters. Use for feature management review.
Read only
Input schema
{'type': 'object', 'properties': {'limit': {'type': 'integer', 'default': 20, 'description': 'Number of feature flags to return'}, 'active': {'type': 'boolean', 'description': 'Filter by active status'}}, 'additionalProperties': False}
get_posthog_insights
Get PostHog insights
Get saved insights (charts, funnels, retention reports) from PostHog with name, type, filters, and last computed results.
Read only
Input schema
{'type': 'object', 'properties': {'limit': {'type': 'integer', 'default': 20, 'description': 'Number of insights to return'}}, 'additionalProperties': False}
get_posthog_persons
Get PostHog persons
Get user profiles from PostHog product analytics with properties, first/last seen dates, and event count. Search by name, email, or distinct ID.
Read only
Input schema
{'type': 'object', 'properties': {'limit': {'type': 'integer', 'default': 20, 'description': 'Number of persons to return'}, 'search': {'type': 'string', 'description': 'Search query for persons'}}, 'additionalProperties': False}
get_purchase_url
Get purchase URL
Generate a Stripe payment URL where the user can buy more credits. Returns a direct checkout link that opens in a browser. Use when credits are low or exhausted, or when the user asks to buy/purchase/top-up credits. The URL is valid for a single purchase.
Read only
Input schema
{'type': 'object', 'properties': {'package': {'enum': ['starter', 'business', 'enterprise'], 'type': 'string', 'description': 'Credit package: starter (1,000 credits / €20), business (3,000 / €50), enterprise (10,000 / €100). Default: starter.'}}, 'additionalProperties': False}
get_resend_domains
Get resend domains
Get configured sending domains from Resend. Returns domain name, verification status, DNS records, and creation date. Use for domain management or answering "what domains are set up in Resend?", "is our domain verified?", or "check email sending domain status."
Read only
Input schema
{'type': 'object', 'properties': {'limit': {'type': 'integer', 'default': 20, 'description': 'Number of domains to return'}}, 'additionalProperties': False}
get_resend_emails
Get resend emails
Get sent transactional emails from Resend email delivery platform. Returns email subject, recipients, status, sent date, and delivery info. Use for email delivery monitoring or answering "what emails were sent via Resend?", "check email delivery status", or "show recent sent emails."
Read only
Input schema
{'type': 'object', 'properties': {'limit': {'type': 'integer', 'default': 20, 'description': 'Number of emails to return'}}, 'additionalProperties': False}
get_search_console
Get search console
Fetch Google organic search performance data from Search Console. Returns daily clicks, impressions, click-through rate (CTR), and average position in Google search results. Use aggregate=true for totals. Ideal for answering "how do we perform in Google search?" or "is our SEO improving?" For metric_card dashboard widgets pass metric=clicks|impressions|ctr|position to get a single aggregated value for that field.
Read only
Input schema
{'type': 'object', 'required': ['start_date', 'end_date'], 'properties': {'page': {'type': 'string', 'description': 'Optional. Limit the daily totals to pages whose URL contains this text, e.g. "/fi/" for a section. Not a breakdown — for rows per URL use get_gsc_top_pages.'}, 'limit': {'type': 'integer', 'description': 'NOT supported here — this tool returns daily totals. Use get_gsc_top_queries / get_gsc_top_pages with limit for ranked breakdown rows.'}, 'metric': {'type': 'string', 'description': 'Optional. When set, return only this metric field. Use for metric_card widgets. Valid values: clicks, impressions, ctr, position'}, 'country': {'type': 'string', 'description': 'Optional. Limit the daily totals to one market — ISO-3166-1 alpha-3, e.g. "est", "fin".'}, 'end_date': {'type': 'string', 'format': 'date', 'description': 'End date (YYYY-MM-DD, today, yesterday, or NdaysAgo).'}, 'site_url': {'type': 'string', 'description': 'Optional. Another Search Console property of the SAME client (e.g. "sc-domain:kookjakodu.fi") instead of the connected one. Only properties an admin listed for this project (dashboard Seaded → Domeenid) are accepted.'}, 'aggregate': {'type': 'boolean', 'default': False}, 'row_limit': {'type': 'integer', 'description': 'NOT supported here — use get_gsc_top_queries / get_gsc_top_pages with `limit`.'}, 'dimensions': {'type': 'array', 'items': {'type': 'string'}, 'description': 'NOT supported here — this tool returns daily totals. For a breakdown by search term use get_gsc_top_queries, by URL use get_gsc_top_pages.'}, 'page_exact': {'type': 'string', 'description': 'Optional. Limit the daily totals to ONE URL exactly as Search Console reports it, e.g. "https://www.example.ee/hinnad/". Use this for a single page — `page` with the home page URL would match the whole site.'}, 'start_date': {'type': 'string', 'format': 'date', 'description': 'Start date (YYYY-MM-DD, today, yesterday, or NdaysAgo such as 30daysAgo). Omit both dates to get the last 28 days; the response carries the dates actually used, so report the period from those rather than assuming.'}}, 'additionalProperties': False}
get_seo_dashboard
Get SEO dashboard
Read the SEO / AI osakond client view of an agent dashboard: which sections you have written and when, what the platform reads itself (Search Console, GA4, Google Ads, Meta Ads, Facebook, Instagram, TikTok, LinkedIn, PageSpeed — cached 3 h, re-warmed hourly, fully re-read every night), the open "Sinult on vaja" items, unread client messages, the schema of every section, and data_map: every block's source, the sections that are YOURS with cadence and status (missing / stale / ok), your tool actions, the last nightly refresh. Call this before update_seo_dashboard. Full guide: https://sharksapi.ai/docs/ai-osakond-andmed. Token optional — defaults to your own dashboard.
Read only
Input schema
{'type': 'object', 'properties': {'token': {'type': 'string', 'description': 'Dashboard public_token. Omit for your own dashboard.'}, 'domain': {'type': 'string', 'description': 'Optional domain context from the dashboard. The read returns all configured domains; use update_seo_dashboard domain=<host> when writing a domain-specific section.'}, 'market': {'type': 'string', 'description': 'Optional market context from the dashboard, e.g. "est" or "fin". The read returns all markets; use update_seo_dashboard market=<code> when writing a market-specific section.'}, 'include_schema': {'type': 'boolean', 'default': True, 'description': 'Include the section schema/guidance (set false for a compact status read).'}}, 'additionalProperties': False}
get_seoshark
Get SEOShark
Comprehensive SEO snapshot from sharks.pw/seo: project info, keyword list with positions, backlinks overview + toxic backlinks, content overview + technical SEO. One call returns everything needed for a quick SEO health check. Use for "how is our SEO?" or weekly SEO summaries.
Read only
Input schema
{'type': 'object', 'properties': {}}
get_seoshark_backlinks
Get SEOShark backlinks
Backlink list from sharks.pw/seo with referring domain, anchor text, and dofollow/nofollow type. Filter by all|dofollow|nofollow|toxic. Use for link-building reviews and toxic-link audits.
Read only
Input schema
{'type': 'object', 'properties': {'type': {'enum': ['all', 'dofollow', 'nofollow', 'toxic'], 'type': 'string', 'default': 'all'}, 'limit': {'type': 'integer', 'default': 100}, 'domain': {'type': 'string', 'description': 'Optional safety check. This tool can only read the domain attached to the connected SeoShark project; for arbitrary domains use backlinks_summary(target=domain).'}}, 'additionalProperties': False}
get_seoshark_content
Get SEOShark content
Content overview + technical SEO + word cloud from sharks.pw/seo. Returns total pages crawled, word count, common terms, and technical issues (missing titles, broken links, slow pages). Use for "what content do we have?" or technical SEO audits.
Read only
Input schema
{'type': 'object', 'properties': {'word_cloud_limit': {'type': 'integer', 'default': 50, 'description': 'Top N terms in the word cloud'}}, 'additionalProperties': False}
get_seoshark_keyword_history
Get SEOShark keyword history
Position history for a single keyword from sharks.pw/seo — daily/weekly position snapshots over time. Use for "how did keyword X trend?" or to detect ranking improvements/regressions.
Read only
Input schema
{'type': 'object', 'required': ['keyword'], 'properties': {'limit': {'type': 'integer', 'description': 'Ignored compatibility field. Keyword history returns the full available history for the keyword.'}, 'keyword': {'type': 'string', 'description': 'Keyword to look up history for'}}, 'additionalProperties': False}
get_seoshark_keywords
Get SEOShark keywords
Tracked keyword positions from sharks.pw/seo. Returns keyword, current Google position, optional search-volume/difficulty depending on what the project tracks. Use for "what keywords do we rank for?" or to feed weekly SEO reports.
Read only
Input schema
{'type': 'object', 'properties': {'limit': {'type': 'integer', 'default': 50, 'description': 'Max keywords to return'}, 'country': {'type': 'string', 'description': 'Select which SeoShark project by country (e.g. "EE", "FI") when the project has more than one. Defaults to the first.'}, 'keyword': {'type': 'string', 'description': 'Filter to a single keyword (optional)'}}, 'additionalProperties': False}
get_seoshark_keywords_history
Get SEOShark keywords history
Multi-keyword position history pivoted as time-series rows for chart_line widgets. Returns one row per date with one numeric column per keyword (lower number = better Google position). If keywords[] is empty, picks the top N currently best-ranking keywords. RULE: the keyword-positions trend must ALWAYS be rendered as a `chart_line` widget with display_config.y_axis.reverse=true (so #1 sits at the top) — on every dashboard, for every client. NEVER render this trend as a text_markdown Unicode sparkline; text_markdown is allowed only for separate narrative commentary beside the chart.
Read only
Input schema
{'type': 'object', 'properties': {'days': {'type': 'integer', 'default': 30, 'description': 'Lookback window in days'}, 'top_n': {'type': 'integer', 'default': 5, 'description': 'How many top-ranking keywords to plot when keywords[] is empty'}, 'country': {'type': 'string', 'description': 'When the project has more than one SeoShark project (e.g. "EE" and "FI"), select which by country code. Defaults to the first connection.'}, 'keywords': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Specific keywords to plot. Leave empty to auto-pick top_n.'}}, 'additionalProperties': False}
get_social_comments
Get social comments
Read the actual comments (text, author, time, like count, hidden state) on a Facebook page post or Instagram media via the Meta Graph API. Works on any post of the connected page/account — pass the provider post id (from get_facebook_posts, get_instagram_posts, or a published social_post's provider_post_id). If you only have a SharksAPI social_post_id, pass that and the platform infers channel + provider_post_id. Instagram returns replies inline; for Facebook pass a comment_id as post_id to read that thread's replies. Use this instead of browser automation for community management.
Read only
Input schema
{'type': 'object', 'properties': {'after': {'type': 'string', 'description': "Pagination cursor from a previous call's next_after."}, 'limit': {'type': 'integer', 'maximum': 50, 'minimum': 1, 'description': 'Comments per page, default 25.'}, 'channel': {'enum': ['facebook', 'instagram', 'tiktok', 'linkedin'], 'type': 'string'}, 'post_id': {'type': 'string', 'description': "Provider post/media id. Facebook also accepts a comment id here to list that comment's replies."}, 'social_post_id': {'type': 'integer', 'minimum': 1, 'description': 'Optional SharksAPI social post id; used to infer channel and provider_post_id for a published post.'}}, 'additionalProperties': False}
get_social_engagement_chart
Get social engagement chart
Chart-ready per-post engagement across Facebook and Instagram for a date range. Combines get_facebook_posts and get_instagram_posts, computes engagement per post (FB: reactions + comments + shares; IG: total interactions), sorts descending and returns {labels, datasets} for a chart_bar dashboard widget — one colored dataset per channel so FB and IG are visually distinct. Use as the source of a "engagement per post" dashboard widget; the dashboard date filter passes start_date/end_date straight through.
Read only
Input schema
{'type': 'object', 'properties': {'limit': {'type': 'integer', 'default': 20, 'description': 'Max posts (bars) in the chart across both channels (default 20, max 40).'}, 'end_date': {'type': 'string', 'description': 'End date (YYYY-MM-DD or today). Defaults to today.'}, 'start_date': {'type': 'string', 'description': 'Start date (YYYY-MM-DD or daysAgo:N). Defaults to 28 days ago.'}}, 'additionalProperties': False}
get_social_mentions
Get social mentions
Aggregates brand mentions across Reddit, YouTube, LinkedIn, Facebook, and Bluesky into a single normalized feed. Each mention includes platform, author, content (truncated to 500 chars), url, posted_at, and sentiment (positive/negative/neutral via keyword heuristic). Reddit + YouTube always run via system credentials; LinkedIn/Facebook/Bluesky run only when the project has a connected account of that type. Sources fail per-source — one broken source returns an entry in errors[] but the rest still return. Use this for "where is my brand mentioned online?" or "what are people saying about us this week?". Replaces deprecated search_web_mentions.
Read only
Input schema
{'type': 'object', 'required': ['query'], 'properties': {'days': {'type': 'integer', 'default': 30, 'description': 'Look-back window in days (1-365)'}, 'limit': {'type': 'integer', 'default': 20, 'description': 'Max results per source (1-100)'}, 'query': {'type': 'string', 'description': 'Brand name, hashtag, or keyword to search (e.g. "IST International School" or "ist.ee")'}, 'refresh': {'type': 'boolean', 'default': False, 'description': 'Bypass all per-source caches for this call'}}, 'additionalProperties': False}
get_social_post
Get social post
Get one project-scoped social publishing record and its approval status. Does not publish or mutate it. Failed rows carry last_error_code + last_error_message (Meta's own error text, e.g. "(#200) Requires pages_manage_posts") so you can tell a permission problem from a provider outage without asking a human.
Read only
Input schema
{'type': 'object', 'required': ['social_post_id'], 'properties': {'social_post_id': {'type': 'integer', 'minimum': 1}}, 'additionalProperties': False}
get_strategy_status
Get strategy status
Get the current status of a strategy card — title, mode, and all tasks with their completion state. Use this before creating a new strategy to see what was done previously, or to monitor progress of an AI-controlled strategy. Each task has an `is_skipped` flag and an `actionable` flag: tasks with is_skipped=true were deactivated by a human and MUST NOT be executed or completed by an agent — skip them. progress_pct counts skipped tasks as resolved (alongside completed).
Read only
Input schema
{'type': 'object', 'required': ['token'], 'properties': {'token': {'type': 'string', 'description': 'Dashboard public_token'}, 'task_id': {'type': 'integer', 'description': 'Optional compatibility lookup: when you only know a task id, the platform infers the owning strategy card and returns that card status.'}, 'task_ids': {'type': 'array', 'items': {'type': 'integer'}, 'description': 'Optional compatibility lookup for copied task lists. The first valid task id is used to infer the strategy card.'}, 'widget_id': {'type': 'integer', 'description': 'Strategy card widget ID. Optional when the dashboard has exactly one strategy card; otherwise the error returns the available card ids.'}}, 'additionalProperties': False}
get_team_capabilities
Get team capabilities
Orientation for planning: what marketing-agent roles you can use on THIS project, what each does, which SharksAPI data sources are LIVE (connected) vs missing, and the recommended skills per role. Works even before any dashboard/team exists — call it FIRST when turning a planning brief into an annual plan, then set_marketing_plan + create_dashboard + delegate_to_agents + add_plan_activity to distribute the work. Returns whether a manager dashboard already exists. Measure only anonymous data — never applicant PII.
Read only
Input schema
{'type': 'object', 'properties': {}}
get_team_overview
Get team overview
Read the rolled-up state of a Turundusjuht (manager) Command Center: every subagent's status (ok/attention/critical) and progress, the Top-5 most pressing topics across the team, and marketing-plan pillar coverage. Pass the MANAGER dashboard token. The returned agents[] include each subagent's child_token — use those tokens with add_strategy_card so each agent fills its own area. This is how the manager agent sees the whole team on one dash.
Read only
Input schema
{'type': 'object', 'required': ['token'], 'properties': {'token': {'type': 'string', 'description': 'Manager dashboard public_token (the one whose layout_config.dashboard_role = manager).'}}, 'additionalProperties': False}
get_team_skill
Get team skill
Fetch the full markdown of a team skill so you can read it, install it (save as .claude/skills/{slug}/SKILL.md), or combine several versions into a better one. Defaults to the canonical version, else the latest.
Read only
Input schema
{'type': 'object', 'required': ['slug'], 'properties': {'slug': {'type': 'string'}, 'version': {'type': 'integer', 'description': 'Optional specific version. Omit for canonical/latest.'}}, 'additionalProperties': False}
get_tiktok
Get TikTok
Fetch TikTok account overview via the Display API: display name, verified flag, follower/following counts, total likes and video count, plus profile link. Works after the owner authorizes TikTok via OAuth (Login Kit). Use for social media reporting or answering "how is our TikTok account doing?"
Read only
Input schema
{'type': 'object', 'properties': {}}
get_tiktok_creator_info
Get TikTok creator info
Read the connected TikTok creator's posting settings BEFORE composing a post: which privacy levels the account may use (privacy_level_options — PUBLIC_TO_EVERYONE appears only once the app has passed TikTok's content-posting audit AND the account is public), whether the creator has disabled comments/duets/stitches (those cannot be re-enabled per post), the max video duration, and the creator nickname/avatar. Call this first, build the post from its answers, then call post_tiktok_video. Also the quickest way to check whether public posting is unlocked yet: posting_unlocked=true.
Read only
Input schema
{'type': 'object', 'properties': {}}
get_tiktok_post_status
Get TikTok post status
Check the processing state of a TikTok video posted with post_tiktok_video. Returns status (PROCESSING_DOWNLOAD → PUBLISH_COMPLETE or FAILED) plus the fail_reason when TikTok rejected the video. Poll every ~30s until terminal.
Read only
Input schema
{'type': 'object', 'required': ['publish_id'], 'properties': {'publish_id': {'type': 'string', 'description': 'The publish_id returned by post_tiktok_video.'}}, 'additionalProperties': False}
get_tiktok_videos
Get TikTok videos
List the connected TikTok account's own videos with engagement stats: views, likes, comments, shares, title, share URL and post time. Optional max_count (default 20). Use to find top-performing TikTok content or build a posting report.
Read only
Input schema
{'type': 'object', 'properties': {'end_date': {'type': 'string', 'format': 'date', 'description': 'Ignored. TikTok Display API video listing is newest-first; filter returned videos client-side by create_time if you need a date window.'}, 'max_count': {'type': 'integer', 'description': 'How many videos to return (default 20, newest first)'}, 'start_date': {'type': 'string', 'format': 'date', 'description': 'Ignored. TikTok Display API video listing is newest-first; filter returned videos client-side by create_time if you need a date window.'}}, 'additionalProperties': False}
get_twitter
Get Twitter
Fetch Twitter/X account analytics for a date range. Returns tweet count, impressions, engagement rate, retweets, likes, replies, and profile visits. Use for social media reporting or answering "how are our tweets performing?"
Read only
Input schema
{'type': 'object', 'required': ['start_date', 'end_date'], 'properties': {'end_date': {'type': 'string', 'format': 'date'}, 'start_date': {'type': 'string', 'format': 'date', 'description': 'Start date (YYYY-MM-DD). Omit both dates to get the last 28 days; the response carries the dates actually used, so report the period from those rather than assuming.'}}, 'additionalProperties': False}
get_upcoming_events
Get upcoming events
Get the next N upcoming Google Calendar events, ordered by start time, starting from now. Returns event id, title, description, start, end, location, attendees, and html_link. Use for daily briefings or answering "what do I have coming up?" or "what is my next meeting?"
Read only
Input schema
{'type': 'object', 'properties': {'max_results': {'type': 'integer', 'default': 10}}, 'additionalProperties': False}
get_usage_summary
Get usage summary
Get credit usage statistics: daily usage breakdown, top tools by usage count, and usage by bot type. Use to analyze spending patterns or report on API consumption.
Read only
Input schema
{'type': 'object', 'properties': {'days': {'type': 'integer', 'description': 'Number of days to look back (default: 30, max: 90)'}}, 'additionalProperties': False}
get_wp_page
Get WordPress page
Fetch one WordPress page in full (title, content, excerpt, slug, status, link) by page_id. `content` is the whole page, never a preview. `content_format` says which form it is: "raw" is the stored source with its Gutenberg block markup, exactly what update_wp_page expects back; "rendered" is the full rendered HTML, returned when WordPress refuses the edit context (the connection user may not edit this page). excerpt_format and title_format work the same way. Read it before rewriting so you keep the parts you are not changing, then send the whole edited content back.
Read only
Input schema
{'type': 'object', 'required': ['page_id'], 'properties': {'page_id': {'type': 'integer'}}, 'additionalProperties': False}
get_wp_post
Get WordPress post
Retrieve a single WordPress post in full: title, content, excerpt, categories, tags, featured image, author, publication date, slug and link, plus `meta` (post meta the site exposes over REST, e.g. header_image) and `acf` (ACF fields when the field group is shown in REST). `content` is the whole post, never a preview. `content_format` says which form it is: "raw" is the stored source with its Gutenberg block markup, exactly what update_wp_post expects back; "rendered" is the full rendered HTML, returned when WordPress refuses the edit context (the connection user may not edit this post). `excerpt` (excerpt_format raw, or text = plain text of the rendered excerpt) and `title` (title_format raw or rendered) follow the same rule. A key you wrote with update_wp_post meta is missing here only if the site has not registered it. Use when you need the complete post content for editing, SEO analysis, or content review.
Read only
Input schema
{'type': 'object', 'required': ['post_id'], 'properties': {'post_id': {'type': 'integer', 'description': 'WordPress post ID'}}, 'additionalProperties': False}
get_wp_seo_meta
Get WordPress SEO Meta
Read the current Rank Math SEO fields for a post or page, drafts included: SEO title, meta description, focus keyword, canonical, and the share image as stored (og_image, og_image_id, the values update_wp_seo_meta writes) and as rendered on the public page (og_image_rendered + width/height). Published posts are read from the rendered page; drafts from post meta. Fields listed in `unreadable` are hidden by the site, so null there does not mean empty. Use before rewriting a title so you know the current length and wording, and after update_wp_seo_meta to verify it.
Read only
Input schema
{'type': 'object', 'required': ['object_id'], 'properties': {'type': {'type': 'string', 'description': 'posts (default) or pages.'}, 'object_id': {'type': 'integer', 'description': 'Post or page ID.'}}, 'additionalProperties': False}
hide_social_comment
Hide social comment
Hide (or unhide) a comment on the project's Facebook page or Instagram business account — for spam and abuse moderation. Hiding is reversible and the commenter still sees their own comment; deletion is deliberately not offered. Requires pages_manage_engagement (Facebook) / instagram_manage_comments (Instagram). External write: goes through the human approval gate unless the social channel is on autopilot.
Destructive
Input schema
{'type': 'object', 'required': ['channel', 'comment_id'], 'properties': {'hide': {'type': 'boolean', 'description': 'Default true. Pass false to unhide a previously hidden comment.'}, 'channel': {'enum': ['facebook', 'instagram', 'tiktok', 'linkedin'], 'type': 'string'}, 'comment_id': {'type': 'string', 'description': 'The comment to hide or unhide, from get_social_comments.'}}, 'additionalProperties': False}
inspect_gsc_url
Inspect GSC URL
Google's own index verdict for up to 20 URLs of the connected Search Console property (URL Inspection API): verdict (PASS/NEUTRAL/FAIL), coverage state ("Submitted and indexed", "Crawled - currently not indexed", "Discovered - currently not indexed", "Excluded by noindex", "Duplicate, Google chose different canonical"…), indexing and robots.txt state, page fetch state, last crawl time, Googlebot type, user-declared vs Google-selected canonical, the sitemaps and referring URLs Google knows, plus mobile-usability and rich-result verdicts. Use it instead of inferring indexing from zero impressions. Quota: 2,000 inspections per property per day — inspect tier-1 URLs, not the whole site.
Read only
Input schema
{'type': 'object', 'required': ['urls'], 'properties': {'url': {'type': 'string', 'description': 'Compatibility alias for one URL; the platform converts it to urls[].'}, 'urls': {'type': 'array', 'items': {'type': 'string'}, 'maxItems': 20, 'minItems': 1, 'description': 'Full URLs inside the property, e.g. ["https://example.ee/teenused/"].'}, 'site_url': {'type': 'string', 'description': 'Optional. Another Search Console property of the SAME client that an admin enabled for this project.'}, 'language_code': {'type': 'string', 'description': 'Language for the human-readable issue messages (default "en").'}}, 'additionalProperties': False}
inspect_runs
Inspect runs
Inspect failed and stalled A2A tool runs for this project. Returns sanitized root-cause categories and recommended actions without task inputs, raw results, credentials, callback URLs, IPs, or automatic replay. Pass task_id for one run.
Read only
Input schema
{'type': 'object', 'properties': {'days': {'type': 'integer', 'default': 7, 'maximum': 30, 'minimum': 1}, 'limit': {'type': 'integer', 'default': 50, 'maximum': 100, 'minimum': 1}, 'task_id': {'type': 'string', 'description': 'Optional exact A2A task ID for one project-scoped run.'}}, 'additionalProperties': False}
invalidate_dashboard_cache
Invalidate dashboard cache
Clear all cached widget data for a dashboard, forcing the next view to refetch live data. Use when you know the underlying integration data just changed and want viewers to see the latest values immediately.
Input schema
{'type': 'object', 'required': ['token'], 'properties': {'token': {'type': 'string'}}, 'additionalProperties': False}
invite_client_person
Invite client person
Give your client (the business owner or a colleague of theirs) their own sign-in to this project's dashboards: SharksAPI e-mails them a one-time link, no password. Signed-in owners can approve work and take the money decisions on the dashboard; on a dashboard where the client decides, only they can. Use it once the first dashboard exists, with the e-mail the person gave you. Calling it again for the same e-mail just sends a fresh link.
Input schema
{'type': 'object', 'required': ['email'], 'properties': {'name': {'type': 'string', 'description': 'Their name (optional, used in the greeting)'}, 'role': {'enum': ['owner', 'member'], 'type': 'string', 'description': 'owner (default) may take money decisions; member may approve other work'}, 'email': {'type': 'string', 'description': "The person's e-mail address"}, 'landing': {'enum': ['index.html', 'inbox', 'plan', 'connections'], 'type': 'string', 'description': 'Dashboard page the link opens (default index.html)'}}, 'additionalProperties': False}
invite_teammate
Invite teammate
Share full access to THIS project with another person's Claude Cowork — fully A2A, no web page. Creates a team invite and returns an invite_token + a ready recipient_instruction. The recipient's OWN agent accepts by POSTing {invite_token, name} to /api/v1/a2a/accept-invite, which provisions a claude_cowork agent scoped to the SAME project and returns its client_id + client_secret + mcp_url. They can then command the same team — Turundusjuht, SEO agent, etc. (delegate_to_agents, read_dashboard, set_marketing_plan, all of it). ALSO does credential recovery: if the email already belongs to a teammate who lost their secret, accepting REFRESHES it (client_id + connections stay; response sets recovery:true). Pass the recipient_instruction (or invite_token) to the colleague. A web fallback (invite_url) also exists.
Input schema
{'type': 'object', 'required': ['email'], 'properties': {'name': {'type': 'string', 'description': 'Optional display name for the teammate.'}, 'email': {'type': 'string', 'format': 'email', 'description': "The teammate's email — also the owner_email of the agent that will be created for them."}, 'scopes': {'type': 'array', 'items': {'enum': ['marketing:read', 'marketing:write', 'sales:read', 'sales:write', 'office:read', 'office:write'], 'type': 'string'}, 'description': 'Access scopes to grant. Defaults to FULL access (all six) — the same level the inviter has.'}, 'expires_days': {'type': 'integer', 'default': 7, 'description': 'Days the invite link stays valid (1-30). Default 7.'}}, 'additionalProperties': False}
keyword_planner_ideas
Keyword planner ideas
Get keyword ideas from Google Keyword Planner using seed keywords and/or a URL. Returns keyword suggestions with monthly search volume, competition level (LOW/MEDIUM/HIGH), and CPC bid estimates. The gold standard for keyword research backed by actual Google Ads data. Requires a Google Ads connection with Keyword Planner access. Supports language and location targeting.
Read only
Input schema
{'type': 'object', 'required': [], 'properties': {'url': {'type': 'string', 'description': 'Optional seed URL — Google will extract keywords from this page'}, 'keywords': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Seed keywords to generate ideas from (e.g. ["digital marketing", "SEO"])'}, 'language': {'type': 'string', 'description': 'Language criterion ID (e.g. "1000" for English, "1043" for Estonian). Default: "1000"'}, 'location': {'type': 'string', 'description': 'Location criterion ID (e.g. "2233" for Estonia, "2840" for USA). Default: "2233"'}}, 'additionalProperties': False}
keyword_planner_volumes
Keyword planner volumes
Get historical search volumes for specific keywords from Google Keyword Planner. Returns monthly search volume trends, competition index, and CPC estimates for each keyword. Use this when you already have a keyword list and need volume data to prioritize. Requires a Google Ads connection with Keyword Planner access.
Read only
Input schema
{'type': 'object', 'required': ['keywords'], 'properties': {'keywords': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Keywords to get search volumes for (e.g. ["SEO audit", "keyword research tool"])'}}, 'additionalProperties': False}
keyword_search_volume
Keyword search volume
Google Ads search volume, CPC (EUR/USD), and competition level for a batch of keywords. Returns per-keyword monthly search volume, competition index (0–100), keyword difficulty, and average CPC. Use this for keyword research before writing content, ad group planning, prioritising content calendars, or answering "how much traffic could rank X bring us?". Pair with search_serp_google for the full "can we rank?" check.
Read only
Input schema
{'type': 'object', 'required': ['keywords'], 'properties': {'keywords': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Keywords to look up (batch supported, typically up to ~1000)'}, 'language_code': {'type': 'string', 'default': 'et', 'description': 'Language code (et, en, ru, fi, ...)'}, 'location_code': {'type': 'integer', 'default': 2233, 'description': 'DataForSEO location code (2233 = Estonia)'}}, 'additionalProperties': False}
link_to_manager
Link to manager
Attach an existing standalone agent dashboard under a manager dashboard as a team member (or detach it). Use this when an agent built its own dashboard first and now joins a team. Both dashboards must be in the same project. Sets parent + agent_key so the dashboard appears in the manager rollup and shows the shared plan context.
Input schema
{'type': 'object', 'required': ['token'], 'properties': {'token': {'type': 'string', 'description': 'Public token of the agent dashboard to link.'}, 'agent_key': {'type': 'string', 'description': 'Stable slug for this agent in the team (e.g. "seo"). Should match a manager plan pillar\'s agent_keys.'}, 'agent_icon': {'type': 'string'}, 'agent_name': {'type': 'string'}, 'agent_accent': {'type': 'string'}, 'manager_token': {'type': ['string', 'null'], 'description': 'Public token of the manager dashboard to attach under. Pass null to DETACH and make this a standalone dashboard again.'}}, 'additionalProperties': False}
list_agent_runs
List agent runs
The channel agents' server runs: each agent's schedule and next run, its latest runs (status, tool calls, what it did, errors) and the writes still waiting for a person's approval.
Read only
Input schema
{'type': 'object', 'properties': {'limit': {'type': 'integer', 'maximum': 20, 'minimum': 1, 'description': 'Runs per agent; default 5'}, 'channel': {'type': 'string', 'description': 'Only this channel'}}, 'additionalProperties': False}
list_calendars
List calendars
List all Google Calendars the user has access to. Returns calendar id, summary, description, primary flag, and access role. Use to discover which calendar to query, or to answer "which calendars do I have?" Returns the primary calendar plus any shared or subscribed calendars.
Read only
Input schema
{'type': 'object', 'properties': {}}
list_change_impacts
List change impacts
What your team's changes did to the numbers. Every measurable change an agent makes (update_wp_seo_meta title/description, page content, schema, redirects, a published new page, Google Ads / Meta Ads edits) is recorded by the platform, which reads its effect 14 and 28 days later against the same number of days before: for pages Google Search Console clicks, impressions, CTR and position of that URL (with the whole site's change beside it, so a seasonal swing is not credited to the change); for ads CTR, conversions and cost per conversion. Each row gives a ready highlight (metric + metric_label) for update_seo_dashboard section "highlights" ("Mida agent tegi") — use it instead of computing before/after yourself, and never write "tehtud" as the metric. Rows still being measured say when the next reading is due. Use it for monthly results, reports, and to learn which kinds of change work for this client.
Read only
Input schema
{'type': 'object', 'properties': {'days': {'type': 'integer', 'maximum': 365, 'minimum': 1, 'description': 'Changes made in the last N days (default 90).'}, 'limit': {'type': 'integer', 'maximum': 100, 'minimum': 1, 'description': 'Max rows, newest first (default 30).'}, 'target': {'type': 'string', 'description': 'Only changes whose page URL, title or campaign contains this text.'}, 'channel': {'enum': ['seo', 'google_ads', 'meta_ads'], 'type': 'string', 'description': 'Only this channel.'}, 'measured_only': {'type': 'boolean', 'description': 'Only changes with at least one reading (default false).'}}, 'additionalProperties': False}
list_client_people
List client people
List the client's people who can sign in to this project's dashboards (e-mail, role, when they last signed in).
Read only
Input schema
{'type': 'object', 'properties': {}}
list_connections
List connections
List all currently connected services for this project. Returns each connection's service type, status (connected/disconnected/error), connection date, last sync time, and whether it needs configuration. Use for connection health overview or answering "what services are connected?", "show our integrations", or "which connections have issues?"
Read only
Input schema
{'type': 'object', 'properties': {}}
list_creative_assets
List creative assets
List the project's photo bank, newest first: images made by generate_image, the brand guide's image bank and photos the client attached to dashboard messages — each with id, source, a 7-day signed_url, created_at and taken_at (camera date), size, tags and the has_people / consent flags. publish says what you may do with it: ok, do_not_publish (identifiable people without consent — never publish it or use it as a reference) or check_people (a client photo nobody has checked — look before you publish). Also shows your request_client_photos asks and how many photos each has received.
Read only
Input schema
{'type': 'object', 'properties': {'tag': {'type': 'string', 'description': 'Only images with this tag.'}, 'limit': {'type': 'integer', 'default': 50, 'description': 'Max images (1–200).'}, 'since': {'type': 'string', 'description': "YYYY-MM-DD: only images taken (camera date) or added on or after this date — use it to leave out last year's photos."}, 'source': {'enum': ['generated', 'brand', 'client_upload'], 'type': 'string', 'description': 'Only images from this source.'}, 'publishable_only': {'type': 'boolean', 'default': False, 'description': 'Leave out do_not_publish images.'}}, 'additionalProperties': False}
list_drafts
List drafts
List content drafts for this project, newest/most-urgent first. Filter by status (pending, changes_requested, approved, scheduled, rejected, published) — omit to get the open queue (pending + changes_requested).
Read only
Input schema
{'type': 'object', 'properties': {'type': {'enum': ['social_post', 'web_text', 'newsletter', 'blog', 'ad_text', 'event_text', 'campaign_message', 'seo_change'], 'type': 'string', 'description': 'Optional content type filter, e.g. blog, social_post, newsletter.'}, 'limit': {'type': 'integer', 'description': 'Max rows (default 25).'}, 'status': {'type': 'string', 'description': 'Filter by a single status, or "open" for the review queue.'}, 'draft_id': {'type': 'integer', 'description': 'Optional shortcut: when supplied, this inspects that one draft (same result as review_draft with action=inspect).'}}, 'additionalProperties': False}
list_drive_files
List drive files
List files in a Google Drive folder (or root if folder_id omitted). Returns file id, name, mime type, size, modified time, and web view link. Use for browsing folders, finding documents, or answering "what files are in my Drive?"
Read only
Input schema
{'type': 'object', 'properties': {'limit': {'type': 'integer', 'default': 50}, 'folder_id': {'type': 'string', 'description': 'Drive folder id. Omit to list root-level files.'}}, 'additionalProperties': False}
list_drive_folders
List drive folders
List subfolders inside a Google Drive folder (or root if parent_id omitted). Returns folder id, name, and modified time. Use to navigate a folder hierarchy or answer "what folders do I have in Drive?"
Read only
Input schema
{'type': 'object', 'properties': {'parent_id': {'type': 'string', 'description': 'Parent folder id. Omit to list root-level folders.'}}, 'additionalProperties': False}
list_events
List events
List Google Calendar events between two dates (RFC3339 date-times). Returns event id, title, description, start, end, location, attendees (with RSVP status), and html_link. Use for calendar review, meeting prep, or answering "what events do I have this week/month?" Date tokens "today", "yesterday", "NdaysAgo" are supported.
Read only
Input schema
{'type': 'object', 'required': ['start_date', 'end_date'], 'properties': {'end_date': {'type': 'string', 'description': 'End date/time (RFC3339) or token.'}, 'start_date': {'type': 'string', 'description': 'Start date/time (RFC3339, e.g. "2026-04-21T00:00:00Z") or token ("today", "yesterday", "7daysAgo").'}, 'max_results': {'type': 'integer', 'default': 50}}, 'additionalProperties': False}
list_gbp_posts
List gbp posts
List the posts (updates, events, offers) on the connected Google Business Profile: post_id, topic_type, state (LIVE, PROCESSING, REJECTED…), summary, call to action, event/offer dates, photos and the public search_url. Call it before create_gbp_post so you do not repeat a recent update, and afterwards to see whether the post went live.
Read only
Input schema
{'type': 'object', 'properties': {'page_size': {'type': 'integer', 'description': 'Posts per page, 1-100 (default 20).'}, 'page_token': {'type': 'string', 'description': 'next_page_token from the previous page.'}}, 'additionalProperties': False}
list_google_ads_ads
List Google ads ads
List the responsive search ads (RSA) of the connected Google Ads account with what update_google_ads_rsa needs: ad_id, the ad group and campaign it sits in, its status, the headlines and descriptions with their pinned positions, the display paths (path1, path2), the final URLs, the ad strength and the policy approval status. Filter by campaign_id or ad_group_id (ids from list_google_ads_campaigns / this list). Read-only — call it before changing ad texts so you edit what is really live.
Read only
Input schema
{'type': 'object', 'properties': {'status': {'enum': ['ENABLED', 'PAUSED', 'ALL'], 'type': 'string', 'description': 'Filter by ad status. Default ALL (removed ads are always left out).'}, 'ad_group_id': {'type': 'string', 'description': 'Only the ads of this ad group (digits).'}, 'campaign_id': {'type': 'string', 'description': 'Only the ads of this campaign (digits, from list_google_ads_campaigns).'}}, 'additionalProperties': False}
list_google_ads_campaigns
List Google ads campaigns
List the campaigns in the connected Google Ads account with the fields the write tools need: id, name, status (ENABLED / PAUSED), channel type (SEARCH, PERFORMANCE_MAX…), resource_name, the campaign budget resource_name, whether that budget is shared, and the daily budget in euros. get_google_ads returns performance metrics; this one returns the ids and the current state, so call it before pause_google_ads_campaign, enable_google_ads_campaign, set_google_ads_campaign_budget, set_google_ads_ad_schedule or add_google_ads_negative_keywords and to check what a campaign_not_found error is talking about.
Read only
Input schema
{'type': 'object', 'properties': {'status': {'enum': ['ENABLED', 'PAUSED', 'ALL'], 'type': 'string', 'description': 'Filter by campaign status. Default ALL (removed campaigns are always left out).'}}, 'additionalProperties': False}
list_google_ads_conversion_actions
List Google ads conversion actions
List the conversion actions of the connected Google Ads account (read-only): id, name, type, category, status, counting type, whether it is primary for bidding, default value, and for website actions the conversion_id and conversion_label a GTM "awct" tag needs. Call it before create_google_ads_conversion_action (reuse an action instead of duplicating it) and before choosing maximize_conversions bidding for a new campaign.
Read only
Input schema
{'type': 'object', 'properties': {'status': {'enum': ['ENABLED', 'HIDDEN', 'ALL'], 'type': 'string', 'description': 'Filter by status. Default ALL (removed actions are always left out).'}}, 'additionalProperties': False}
list_google_ads_negative_lists
List Google ads negative lists
Negative-keyword lists (shared sets) of the account with their keywords and the campaigns each is attached to, plus which enabled Search and Performance Max campaigns have NO list attached. PMax does not inherit Search negatives — use this to find the gap before add_google_ads_shared_negatives.
Read only
Input schema
{'type': 'object', 'properties': {'include_keywords': {'type': 'boolean', 'description': 'List the keywords of each list (default true).'}}, 'additionalProperties': False}
list_gsc_sitemaps
List GSC sitemaps
The sitemaps submitted in Search Console for the connected property: path, type, last submitted and last downloaded by Google, pending/processing flag, errors and warnings count, and submitted URL counts per content type. Use to spot a sitemap Google stopped reading or one full of errors.
Read only
Input schema
{'type': 'object', 'properties': {'site_url': {'type': 'string', 'description': 'Optional. Another Search Console property of the SAME client that an admin enabled for this project.'}}, 'additionalProperties': False}
list_gtm_tags
List GTM tags
List the tags in the GTM workspace: id, name, type (gaawe = GA4 event, googtag = Google tag, html = custom HTML), firing_trigger_ids, paused flag and condensed parameters. Optional search filters by name substring. Check here whether a tag already exists before creating one.
Read only
Input schema
{'type': 'object', 'properties': {'search': {'type': 'string', 'description': 'Case-insensitive substring to match against tag names, e.g. "form" or "GA4"'}}, 'additionalProperties': False}
list_gtm_triggers
List GTM triggers
List the triggers in the GTM workspace: id, name, type (pageview, click, linkClick, formSubmission, customEvent, elementVisibility, scrollDepth, timer...) and the condensed firing conditions {type, parameter_key, value}. Use the ids as firing_trigger_ids when creating or updating tags.
Read only
Input schema
{'type': 'object', 'properties': {}}
list_gtm_variables
List GTM variables
List the user-defined variables in the GTM workspace: id, name, type (v = data layer variable, c = constant, jsm = custom JavaScript, k = 1st-party cookie, u = URL, aev = auto-event variable) and their parameters. Reference one in tags and trigger conditions as {{Variable Name}}.
Read only
Input schema
{'type': 'object', 'properties': {}}
list_integrations
List integrations
Browse the catalog of marketing integrations (analytics, search, advertising, social, SEO, CMS, e-mail marketing, reviews, forms, Google Workspace) with authentication type (api_key, oauth), required credentials, category and setup instructions. Filter by category or auth type. Use to discover what can be connected, e.g. "what integrations are available?" or "which services support API key auth?".
Read only
Input schema
{'type': 'object', 'properties': {'category': {'type': 'string', 'description': 'Filter by category: seo, analytics, advertising, social, email, email_marketing, marketing_automation, cms, development, forms, office, reviews'}, 'auth_type': {'enum': ['api_key', 'oauth', 'webhook'], 'type': 'string', 'description': 'Filter by authentication type'}}, 'additionalProperties': False}
list_merchant_data_sources
List merchant data sources
Data sources of the Merchant Center account: primary feeds (file, API, Merchant Center UI, autofeed) and supplemental ones, with ids, input type, feed label and language. Shows whether the SharksAPI supplemental source exists and which primary sources use it.
Read only
Input schema
{'type': 'object', 'properties': {}}
list_meta_ads
List Meta ads
List the ads of the connected Meta ad account — of one ad set, one campaign, or all — with id, name, adset_id, campaign_id, status, effective_status (e.g. PENDING_REVIEW, DISAPPROVED, ADSET_PAUSED) and the creative (headline, text, image). Use it to find the ad_id for pause_meta_ad / enable_meta_ad and to check an ad the dashboard links to. Read-only.
Read only
Input schema
{'type': 'object', 'properties': {'status': {'enum': ['ACTIVE', 'PAUSED', 'ALL'], 'type': 'string', 'description': 'Filter by the status you set (ACTIVE / PAUSED). Default ALL; deleted and archived objects are always left out.'}, 'adset_id': {'type': 'string', 'description': 'Only the ads of this ad set.'}, 'campaign_id': {'type': 'string', 'description': 'Only the ads of this campaign.'}}, 'additionalProperties': False}
list_meta_adsets
List Meta adsets
List the ad sets of the connected Meta ad account — all of them, or those of one campaign — with id, name, campaign_id, status, effective_status, optimization goal and the ad set budget (daily_budget_eur, or a lifetime budget with what remains). An ad set under an Advantage campaign budget has no budget of its own (budget_level "campaign"): change that one with set_meta_campaign_budget. Read-only.
Read only
Input schema
{'type': 'object', 'properties': {'status': {'enum': ['ACTIVE', 'PAUSED', 'ALL'], 'type': 'string', 'description': 'Filter by the status you set (ACTIVE / PAUSED). Default ALL; deleted and archived objects are always left out.'}, 'campaign_id': {'type': 'string', 'description': 'Only the ad sets of this campaign (id from list_meta_campaigns).'}}, 'additionalProperties': False}
list_meta_campaigns
List Meta campaigns
List the campaigns of the connected Meta ad account with what the Meta write tools need: id, name, status (what you set: ACTIVE / PAUSED), effective_status (what actually delivers), objective, and where the budget lives — budget_level "campaign" (Advantage campaign budget, daily_budget_eur on the campaign) or "adset" (each ad set has its own). get_meta_ads returns performance; this returns ids and state, so call it before pausing, starting or re-budgeting anything.
Read only
Input schema
{'type': 'object', 'properties': {'status': {'enum': ['ACTIVE', 'PAUSED', 'ALL'], 'type': 'string', 'description': 'Filter by the status you set (ACTIVE / PAUSED). Default ALL; deleted and archived objects are always left out.'}}, 'additionalProperties': False}
list_plan_activities
List plan activities
List marketing plan activities for this project (the Annual/Monthly calendar data), ordered by date. Optionally filter by month (1-12) or status. If an activity is linked with task_ref, its status/attention are derived from that strategy task.
Read only
Input schema
{'type': 'object', 'properties': {'limit': {'type': 'integer', 'description': 'Maximum rows to return (default all, cap 100).'}, 'month': {'type': 'integer', 'description': 'Only activities in this month (1-12).'}, 'status': {'type': 'string', 'description': 'planned | in_progress | done.'}, 'channel': {'type': 'string', 'description': 'Only activities of this channel / agent_key (e.g. seo, paid, content).'}}, 'additionalProperties': False}
list_scheduled_reports
List scheduled reports
List this project's recurring reports: title, schedule, recipients, whether it is on, last and next run, and the start of the last result (an "ERROR: …" result means the last run failed). Call before create_scheduled_report to avoid duplicates.
Read only
Input schema
{'type': 'object', 'properties': {}}
list_site_file_backups
List site file backups
List the recent file changes made on the client website through write_site_file / restore_site_file, newest first: path, when, note, whether the change was rolled back. Optional path filter.
Read only
Input schema
{'type': 'object', 'properties': {'path': {'type': 'string'}, 'limit': {'type': 'integer', 'default': 20}}, 'additionalProperties': False}
list_site_files
List site files
List a folder of the client website over its SFTP connection, e.g. the active theme (wp-content/themes/<theme>/). Omit path to start at wp-content/themes/. Use to find the template, stylesheet or functions.php to change before read_site_file. Only files under wp-content/themes/ or wp-content/mu-plugins/ of the WordPress root (php, css, js, json, html, txt, svg, xml, max 512 KB). wp-config.php, .htaccess, uploads and plugins are out of reach by design.
Read only
Input schema
{'type': 'object', 'properties': {'path': {'type': 'string', 'description': 'Folder relative to the WordPress root, e.g. "wp-content/themes/" or "wp-content/themes/sharks/inc/". Defaults to "wp-content/themes/".'}}, 'additionalProperties': False}
list_social_posts
List social posts
List approval-first social publishing records for this project. Does not expose credentials or provider tokens.
Read only
Input schema
{'type': 'object', 'properties': {'page': {'type': 'integer', 'minimum': 1, 'description': 'Optional 1-based page number. Use with limit for pagination.'}, 'limit': {'type': 'integer', 'maximum': 100, 'minimum': 1}, 'status': {'enum': ['pending_approval', 'approved', 'scheduled', 'queued', 'publishing', 'published', 'failed', 'cancelled', 'awaiting_manual'], 'type': 'string'}, 'channel': {'enum': ['facebook', 'instagram', 'tiktok', 'linkedin'], 'type': 'string'}, 'group_key': {'type': 'string', 'description': 'Only the variants submitted with this group_key.'}}, 'additionalProperties': False}
list_team_skills
List team skills
List the project's shared team skills visible to you — every slug with its channel, versions, who contributed each, and which version is canonical (the manager's pick). Channel agents see global skills + their own channel's; orchestrators see all. Your memory_bootstrap already carries a compact index of these — use this tool for the full picture.
Read only
Input schema
{'type': 'object', 'properties': {'slug': {'type': 'string', 'description': 'Optional — restrict to one skill slug.'}}, 'additionalProperties': False}
list_wp_categories
List WordPress categories
List the WordPress categories (id, name, slug, post count) so you can pick category IDs/names for create_wp_post / update_wp_post. Categories are never created by the agent — ask the site owner if one is missing.
Read only
Input schema
{'type': 'object', 'properties': {}}
list_wp_pages
List WordPress pages
List WordPress PAGES (service/landing pages, not blog posts) with id, title, slug, link, status and modified. content and excerpt are 150-character plain-text previews, not the page: use get_wp_page for the full content. Use before editing a service page so you have the right page_id. Filter with search (title/content substring) or status (publish|draft|any).
Read only
Input schema
{'type': 'object', 'properties': {'search': {'type': 'string', 'description': 'Substring to match in title/content, e.g. "kodulehe".'}, 'status': {'enum': ['publish', 'draft', 'pending', 'private', 'any'], 'type': 'string', 'description': 'publish (default), draft, pending, private, any.'}, 'per_page': {'type': 'integer', 'description': 'Max rows (default 20, cap 100).'}}, 'additionalProperties': False}
list_wp_posts
List WordPress posts
List WordPress blog posts with filtering and sorting. Returns id, title, status, date, modified, slug, link, categories and tags per post. content and excerpt are 150-character plain-text previews, not the post: use get_wp_post for the full content. Filter by status (publish/draft/pending), search by keyword, and sort by date, title, or modification date. Use for content audits, finding specific posts, or answering "what blog posts do we have?" or "show me recent drafts."
Read only
Input schema
{'type': 'object', 'properties': {'page': {'type': 'integer', 'default': 1}, 'after': {'type': 'string', 'description': 'Alias for start_date. Accepts YYYY-MM-DD or a WordPress REST after timestamp.'}, 'order': {'enum': ['asc', 'desc'], 'type': 'string', 'default': 'desc'}, 'before': {'type': 'string', 'description': 'Alias for end_date. Accepts YYYY-MM-DD or a WordPress REST before timestamp.'}, 'search': {'type': 'string', 'description': 'Search term'}, 'status': {'enum': ['publish', 'draft', 'pending', 'private', 'any'], 'type': 'string', 'default': 'publish', 'description': 'Post status filter'}, 'orderby': {'enum': ['date', 'title', 'modified'], 'type': 'string', 'default': 'date'}, 'end_date': {'type': 'string', 'description': 'Include posts published on or before this date (YYYY-MM-DD)'}, 'per_page': {'type': 'integer', 'default': 10, 'description': 'Posts per page'}, 'start_date': {'type': 'string', 'description': 'Include posts published on or after this date (YYYY-MM-DD)'}}, 'additionalProperties': False}
list_wp_tags
List WordPress tags
List the WordPress tags (id, name, slug, post count). Use before tagging a post so you reuse existing tags instead of creating near-duplicates.
Read only
Input schema
{'type': 'object', 'properties': {}}
manage_strategy_card
Manage strategy card
Manager control over a teammate's strategy card (the items behind the Turundusjuht Top-5). The Top-5 is a live rollup — you don't edit it directly, you act on the underlying card and the Top-5 updates automatically. Identify the card by its dashboard token + widget_id (both come from get_team_overview: top_issues[].child_token + top_issues[].widget_id, or agents[].child_token). Actions: "close" (finish the card: it moves to the Command Center "Tehtud" stack and keeps its tasks — use this for last week's card when a new weekly card starts), "reopen", "delete" (remove the card entirely — refused when it has completed tasks unless force=true), "pause"/"resume" (a paused card drops out of the Top-5 and critical counts until resumed), "set_severity" (re-prioritise in the Top-5), "reassign" (move the whole card — title, strategy, tasks and their done-state — to another teammate agent, stamped Turundusjuhilt), "update_strategy" (replace the markdown shown in View strategy).
Input schema
{'type': 'object', 'required': ['token', 'widget_id', 'action'], 'properties': {'force': {'type': 'boolean', 'default': False, 'description': 'Only with action=delete: delete even though the card has completed tasks. Requires an explicit user instruction.'}, 'token': {'type': 'string', 'description': "public_token of the dashboard the card lives on (the agent's dashboard — top_issues[].child_token)."}, 'action': {'enum': ['close', 'reopen', 'delete', 'pause', 'resume', 'set_severity', 'reassign', 'update_strategy'], 'type': 'string', 'description': 'What to do with the card. Weekly routine: when you start a new week\'s card, "close" the previous one (it moves to the Tehtud stack with its history) — never "delete" it. "delete" is refused for cards with completed tasks unless force=true.'}, 'severity': {'enum': ['critical', 'high', 'medium', 'low'], 'type': 'string', 'description': 'Required for action=set_severity.'}, 'strategy': {'type': 'string', 'description': 'Required for action=update_strategy — replacement markdown for the card detail.'}, 'widget_id': {'type': 'integer', 'description': 'Strategy card widget id (top_issues[].widget_id).'}, 'to_agent_key': {'type': 'string', 'description': 'Required for action=reassign — the teammate agent key to move the card to (e.g. "copy", "paid"). Must be another agent under the same manager.'}}, 'additionalProperties': False}
mark_plan_tasks_synced
Mark plan tasks synced
Manager-only bookkeeping: declare that subagent tasks are now re-aligned with the current marketing-plan document. Clears the "tasks not synced" flag on the dashboard and archives the team-memory reminder. Call this AFTER actually updating the affected agents' tasks (delegate_to_agents / update_strategy_task / add_plan_activity) — never before.
Destructive
Input schema
{'type': 'object', 'properties': {'manager_token': {'type': 'string', 'description': "Manager dashboard token (optional; defaults to the project's manager dashboard)."}}, 'additionalProperties': False}
memory_archive
Memory archive
Archive a memory entry (same write permissions as memory_update). Archived entries stay searchable but leave the bootstrap package.
Input schema
{'type': 'object', 'required': ['id'], 'properties': {'id': {'type': 'string'}}, 'additionalProperties': False}
memory_bootstrap
Memory bootstrap
Call FIRST at session start (if no context was handed to you in the A2A task payload): returns the composed working context for this workspace within a ~2500-token budget — all global constraints (incl. the autonomy setting) and facts, your channel's open task_state entries, the latest decisions/results and lessons. Orchestrator may pass role to compose the package for a channel agent before delegating (attach it to the A2A task payload).
Read only
Input schema
{'type': 'object', 'properties': {'role': {'type': 'string', 'description': 'Orchestrator only: compose for this channel role (e.g. seo, google_ads) to attach to a delegated task.'}, 'token': {'type': 'string', 'description': 'Ignored. Your role and scope come from the token you authenticate with; no dashboard token is needed here.'}, 'agent_key': {'type': 'string', 'description': 'Ignored. Your agent/channel identity comes from the token you authenticate with; use role only when an orchestrator composes context for another role.'}, 'project_id': {'type': 'integer', 'description': 'Ignored. Project scope comes from the authenticated token, not from a caller-supplied id.'}}, 'additionalProperties': False}
memory_get
Memory get
Read one memory entry by id if it is visible to your role. Use this when memory_bootstrap or memory_search gives you an entry id and you need the full current record.
Read only
Input schema
{'type': 'object', 'required': ['id'], 'properties': {'id': {'type': 'string'}}, 'additionalProperties': False}
memory_review
Memory review
Orchestrator only: list duplicates, expired and stale-hot entries so the turundusjuht can consolidate (merge with supersedes_id, archive, re-pin). Run this in the weekly manager loop.
Input schema
{'type': 'object', 'properties': {}}
memory_search
Memory search
Full-text search over every memory entry you may read, INCLUDING the archive. Use when bootstrap notes there are more entries, or you need history on a specific keyword/campaign/decision.
Read only
Input schema
{'type': 'object', 'required': ['query'], 'properties': {'type': {'enum': ['fact', 'decision', 'result', 'lesson', 'task_state', 'constraint'], 'type': 'string', 'description': 'Optional type filter.'}, 'limit': {'type': 'integer', 'description': 'Optional result cap. Default 25, maximum 25.'}, 'query': {'type': 'string'}, 'scope': {'type': 'string', 'description': 'Optional scope filter.'}}, 'additionalProperties': False}
memory_update
Memory update
Amend an existing memory entry you are allowed to write (title/content/status/pinned/expires_at/task_id). Prefer this over a duplicate write; use memory_write with supersedes_id when the old entry should be replaced wholesale.
Input schema
{'type': 'object', 'required': ['id'], 'properties': {'id': {'type': 'string'}, 'title': {'type': 'string'}, 'pinned': {'type': 'boolean'}, 'status': {'enum': ['hot', 'active', 'archived'], 'type': 'string'}, 'content': {'type': 'string'}, 'task_id': {'type': 'integer'}, 'expires_at': {'type': 'string'}}, 'additionalProperties': False}
memory_write
Memory write
Write-through memory: record every important decision, result, lesson, fact or task_state IMMEDIATELY while working (not in a batch at session end — an interrupted session must not lose memory). Style: short, factual, dated, measurable — an entry, not an essay. Types: fact (client standing data), constraint (orchestrator/human only — bans, budgets, autonomy), decision (+why), result (measured), lesson, task_state (what was done, what is next; link task_id). Channel agents write their own channel:<role> and private scopes, PLUS scope global for shared knowledge types fact|decision|lesson — use global for general rules every agent must see; task_state/result stay in your channel, and you can amend or supersede only global entries you created yourself. Duplicates get a supersede suggestion instead of a second copy.
Input schema
{'type': 'object', 'required': ['scope', 'type', 'content'], 'properties': {'date': {'type': 'string', 'format': 'date', 'description': 'Optional event date (YYYY-MM-DD). If content does not already start with a date, the platform prefixes this date before saving.'}, 'type': {'enum': ['fact', 'decision', 'result', 'lesson', 'task_state', 'constraint'], 'type': 'string'}, 'scope': {'type': 'string', 'description': 'global | channel:<slug> | private:<agent_id>'}, 'title': {'type': 'string', 'description': 'Short, searchable. If omitted, a short title is inferred from content.'}, 'pinned': {'type': 'boolean', 'description': 'Keep hot — exempt from consolidation demotion.'}, 'content': {'type': 'string', 'description': 'Markdown. Dated + measurable, e.g. "2026-07-09: valisime 5 fookusmärksõna, sest GSC näitas pos 8–15; siht TOP5 60 päevaga". Content over ~1000 chars is split into multiple bounded entries.'}, 'task_id': {'type': 'integer', 'description': 'Command-center task this task_state belongs to (dashboard strategy task id).'}, 'expires_at': {'type': 'string', 'description': 'ISO datetime for temporary facts.'}, 'supersedes_id': {'type': 'string', 'description': 'Replace this older entry (it gets archived).'}, 'source_session': {'type': 'string', 'description': 'Session identifier for traceability.'}}, 'additionalProperties': False}
monitor_keyword_serp
Monitor keyword SERP
Check current Google search results (SERP) for specific keywords. Returns top-ranking URLs, titles, and snippets for each keyword. Configurable by location (default: Estonia), language (default: et), and device type. Use for tracking "where do we rank for keyword X?" or "who ranks #1 for this term?" or competitive SERP analysis.
Destructive
Input schema
{'type': 'object', 'required': ['keywords'], 'properties': {'device': {'enum': ['desktop', 'mobile'], 'type': 'string', 'default': 'desktop'}, 'domain': {'type': 'string', 'description': 'Optional target domain to locate in the SERP; defaults to the project Search Console domain.'}, 'country': {'type': 'string', 'description': 'Alias for location. ISO country codes such as ee/est are accepted and normalized before the SERP check.'}, 'keywords': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Keywords to monitor'}, 'language': {'type': 'string', 'default': 'et', 'description': 'Search language'}, 'location': {'type': 'string', 'default': 'Estonia', 'description': 'Search location'}}, 'additionalProperties': False}
monthly_marketing_report
Monthly marketing report
Generate a comprehensive monthly marketing report in a single call. Automatically gathers data from all connected marketing sources: GA4 website traffic and channel breakdown, Google Search Console top queries and top pages, social media metrics (Facebook, LinkedIn, Twitter — whichever are connected), and Google/Meta ad campaign performance. Returns a structured report with sections for each data source, including which sources were available and which were not connected. Covers the specified month or defaults to last 30 days. Use when asked "give me this month's marketing report", "how did we do last month?", "monthly overview", or "marketing summary."
Read only
Input schema
{'type': 'object', 'properties': {'end_date': {'type': 'string', 'description': 'Report end date (YYYY-MM-DD). Defaults to yesterday.'}, 'top_limit': {'type': 'integer', 'default': 10, 'description': 'Number of top queries/pages to include (default: 10)'}, 'start_date': {'type': 'string', 'description': 'Report start date (YYYY-MM-DD). Defaults to 30 days ago.'}}, 'additionalProperties': False}
pause_google_ads_campaign
Pause Google ads campaign
Stop one Google Ads campaign from serving (campaigns:mutate, update mask "status" = PAUSED). Pausing only ever stops spend, so the Autonomy row "Reklaam › Kampaaniate peatamine" may run it without asking; on the default approve level it waits for a click in the Postkast, where the card names the campaign. A campaign that is already paused is reported as success with changed=false, no API write and no approval card. campaign_id comes from list_google_ads_campaigns. To start a campaign again use enable_google_ads_campaign — that one always needs a human.
Destructive
Input schema
{'type': 'object', 'required': ['campaign_id'], 'properties': {'reason': {'type': 'string', 'description': 'Optional one sentence for the approval card and the audit log: why this campaign is being paused.'}, 'campaign_id': {'type': 'string', 'description': 'Campaign id from list_google_ads_campaigns, e.g. "20713245160" (digits only, not the resource name)'}}, 'additionalProperties': False}
pause_meta_ad
Pause Meta ad
Stop one Meta ad from delivering (POST /{id} status=PAUSED). Pausing only ever stops spend, so the Autonomy row "Tasuline sotsiaal › peatamine" may run it without asking; on the default approve level it waits for a click in the Postkast, where the card names the ad. Already paused → success with changed=false, no write and no card. The ad must belong to the connected ad account. ad_id comes from list_meta_ads. To start it again use enable_meta_ad — that one always needs a human.
Destructive
Input schema
{'type': 'object', 'required': ['ad_id'], 'properties': {'ad_id': {'type': 'string', 'description': 'Meta ad id from list_meta_ads (digits).'}, 'reason': {'type': 'string', 'description': 'Optional one sentence for the approval card and the audit log: why this ad is being paused.'}}, 'additionalProperties': False}
pause_meta_adset
Pause Meta adset
Stop one Meta ad set from delivering (POST /{id} status=PAUSED). Pausing only ever stops spend, so the Autonomy row "Tasuline sotsiaal › peatamine" may run it without asking; on the default approve level it waits for a click in the Postkast, where the card names the ad set. Already paused → success with changed=false, no write and no card. The ad set must belong to the connected ad account. adset_id comes from list_meta_adsets. To start it again use enable_meta_adset — that one always needs a human.
Destructive
Input schema
{'type': 'object', 'required': ['adset_id'], 'properties': {'reason': {'type': 'string', 'description': 'Optional one sentence for the approval card and the audit log: why this ad set is being paused.'}, 'adset_id': {'type': 'string', 'description': 'Meta ad set id from list_meta_adsets (digits).'}}, 'additionalProperties': False}
pause_meta_campaign
Pause Meta campaign
Stop one Meta campaign from delivering (POST /{id} status=PAUSED). Pausing only ever stops spend, so the Autonomy row "Tasuline sotsiaal › peatamine" may run it without asking; on the default approve level it waits for a click in the Postkast, where the card names the campaign. Already paused → success with changed=false, no write and no card. The campaign must belong to the connected ad account. campaign_id comes from list_meta_campaigns. To start it again use enable_meta_campaign — that one always needs a human.
Destructive
Input schema
{'type': 'object', 'required': ['campaign_id'], 'properties': {'reason': {'type': 'string', 'description': 'Optional one sentence for the approval card and the audit log: why this campaign is being paused.'}, 'campaign_id': {'type': 'string', 'description': 'Meta campaign id from list_meta_campaigns (digits).'}}, 'additionalProperties': False}
post_tiktok_video
Post TikTok video
Publish a video to the connected TikTok account (Content Posting API Direct Post). Requires the connection to be authorized with the video.publish scope — if you get a scope_not_authorized error, the owner must re-authorize TikTok. Pass a public video_url TikTok pulls from (the domain must be verified in the TikTok developer portal). privacy_level defaults to SELF_ONLY (private); PUBLIC_TO_EVERYONE works only after TikTok's content-posting audit AND if the creator allows it — call with the caption drafted via the normal draft-approval flow first. Returns a publish_id; poll get_tiktok_post_status until PUBLISH_COMPLETE.
Destructive
Input schema
{'type': 'object', 'required': ['video_url', 'title'], 'properties': {'title': {'type': 'string', 'description': 'Caption/title, max 2200 chars, may contain #hashtags and @mentions.'}, 'is_aigc': {'type': 'boolean', 'description': 'Mark the video as AI-generated content (TikTok shows the AI-generated label). Set true for any video produced with AI tools.'}, 'video_url': {'type': 'string', 'description': 'Public HTTPS URL of the video file (mp4). Domain must be verified for the TikTok app.'}, 'disable_duet': {'type': 'boolean', 'description': 'Disallow duets.'}, 'privacy_level': {'enum': ['SELF_ONLY', 'MUTUAL_FOLLOW_FRIENDS', 'FOLLOWER_OF_CREATOR', 'PUBLIC_TO_EVERYONE'], 'type': 'string', 'description': "Default SELF_ONLY. Must be one of the creator's allowed options (checked automatically)."}, 'disable_stitch': {'type': 'boolean', 'description': 'Disallow stitches.'}, 'disable_comment': {'type': 'boolean', 'description': 'Turn off comments on this post.'}, 'brand_content_toggle': {'type': 'boolean', 'description': 'Commercial content disclosure: true when the video is a PAID partnership promoting a third-party business (TikTok adds the "Paid partnership" label).'}, 'brand_organic_toggle': {'type': 'boolean', 'description': "Commercial content disclosure: true when the video promotes the creator's OWN business/products (most company-account posts)."}, 'video_cover_timestamp_ms': {'type': 'integer', 'description': 'Frame (ms) to use as the cover image.'}}, 'additionalProperties': False}
promote_skill
Promote skill
MANAGER ONLY. Mark one version of a skill as the team CANONICAL ("the best") — this is what list_team_skills highlights and what new agents install. To combine the best of several contributions: read them with get_team_skill, synthesize a merged version, contribute_skill it, then promote_skill that new version. Demotes the previous canonical.
Input schema
{'type': 'object', 'required': ['slug', 'version'], 'properties': {'slug': {'type': 'string'}, 'version': {'type': 'integer'}}, 'additionalProperties': False}
propose_plan_input
Propose plan input
Bottom-up: a teammate agent proposes an input/suggestion into the manager's shared marketing plan (e.g. SEO agent proposes a content priority). Appears in the manager Command Center under "Agentide sisendid plaani" for the manager to accept or decline. Status starts as "proposed".
Input schema
{'type': 'object', 'required': ['title'], 'properties': {'body': {'type': 'string', 'description': 'Optional detail / rationale.'}, 'title': {'type': 'string', 'description': 'Short title of the proposal.'}, 'agent_key': {'type': 'string', 'description': 'Optional. The proposing agent\'s key (e.g. "seo"); inferred from your linked agent dashboard when possible.'}, 'pillar_key': {'type': 'string', 'description': 'Optional pillar this input relates to.'}, 'manager_token': {'type': 'string', 'description': 'Optional. Public token of the manager dashboard whose plan to add the input to; inferred from your linked agent dashboard when possible.'}}, 'additionalProperties': False}
propose_plan_update
Propose plan update
Propose a new version of the AI osakond marketing plan — the whole snapshot as it should be — with the changes in plain words (diffs: ["Meta eelarve 800 € → 1 000 € kuus", …]). The growth lead reviews it in the Postkast (/inbox) or on the plan tab and applies it; only then it becomes a version. Tie it to the uploaded document it comes from (document_id), or leave document_id out for a proposal of your own (e.g. the first plan after the kick-off meeting). The snapshot shape: get_department_plan(include_snapshot_schema=true).
Input schema
{'type': 'object', 'required': ['snapshot', 'diffs'], 'properties': {'note': {'type': 'string', 'description': 'One or two sentences for the growth lead: what the document changes and what you left out.'}, 'diffs': {'type': 'array', 'items': {'type': 'string'}, 'description': 'What changes, one line each, "before → after".'}, 'token': {'type': 'string', 'description': 'Dashboard public_token. Optional — defaults to your own dashboard.'}, 'snapshot': {'type': 'object', 'description': 'The full plan as it should be after the change.'}, 'document_id': {'type': 'integer', 'description': 'The uploaded plan document this proposal answers.'}}, 'additionalProperties': False}
read_dashboard
Read dashboard
Read a FULL dashboard — layout AND live widget data — in one call. Use this instead of opening the public URL in a browser: it returns every widget's current values (metric cards, chart series, tables, markdown, strategy cards with task ids/status), the shared marketing-plan context for team agents, and the manager rollup when the token is a manager dashboard. Integration widgets are fetched server-side with the same caching as the public page. Returns compact JSON ordered by widget position. Combine with update_strategy_task / delegate_to_agents to act on what you read — no browser needed.
Read only
Input schema
{'type': 'object', 'required': ['token'], 'properties': {'token': {'type': 'string', 'description': 'Dashboard public_token (agent or manager dashboard, same project as your auth).'}, 'end_date': {'type': 'string', 'format': 'date'}, 'start_date': {'type': 'string', 'format': 'date', 'description': "Optional YYYY-MM-DD; defaults to the dashboard's default range (usually last 30 days)."}, 'include_data': {'type': 'boolean', 'default': True, 'description': 'false = layout/status only (faster), true = fetch live data for every widget.'}, 'max_table_rows': {'type': 'integer', 'default': 25, 'description': 'Cap rows returned per table/chart widget to keep the payload small (max 100).'}}, 'additionalProperties': False}
read_sheet
Read sheet
Read a range from a Google Sheet. Returns the 2D values array (rows of cells). Range uses A1 notation, e.g. "Sheet1!A1:D20" or "A:D". Requires a connected google_sheets integration.
Read only
Input schema
{'type': 'object', 'required': ['spreadsheet_id', 'range'], 'properties': {'range': {'type': 'string', 'description': 'A1 range, e.g. "Sheet1!A1:D20".'}, 'spreadsheet_id': {'type': 'string', 'description': 'Spreadsheet id (from the URL).'}}, 'additionalProperties': False}
read_site_file
Read site file
Read one theme or mu-plugin file of the client website (SFTP). Returns the content and its sha256 — pass that sha256 as expected_sha256 to write_site_file. Also lists the file's recent backups. Only files under wp-content/themes/ or wp-content/mu-plugins/ of the WordPress root (php, css, js, json, html, txt, svg, xml, max 512 KB). wp-config.php, .htaccess, uploads and plugins are out of reach by design.
Read only
Input schema
{'type': 'object', 'required': ['path'], 'properties': {'path': {'type': 'string', 'description': 'File relative to the WordPress root, e.g. "wp-content/themes/sharks/functions.php".'}}, 'additionalProperties': False}
record_kpi_values
Record KPI values
Write monthly values of AI osakond plan KPIs the platform cannot read from a connection — keywords in the top ten, AI mentions, social reach, and anything else without a live metric. values: [{kpi_id, month: "YYYY-MM", value}]. KPIs with a live metric (GA4 leads, Search Console clicks, Google/Meta Ads cost and conversions) update themselves; writing them here only fills months the source cannot answer. This is data, not a plan change: no version is made.
Input schema
{'type': 'object', 'required': ['values'], 'properties': {'token': {'type': 'string', 'description': 'Dashboard public_token. Optional — defaults to your own dashboard.'}, 'values': {'type': 'array', 'items': {'type': 'object', 'required': ['kpi_id', 'month', 'value'], 'properties': {'month': {'type': 'string'}, 'value': {'type': 'number'}, 'kpi_id': {'type': 'string'}}}}}, 'additionalProperties': False}
remove_google_ads_negative_keyword
Remove Google ads negative keyword
Remove one negative keyword from a Google Ads campaign (campaignCriteria:mutate, remove) so those searches can trigger ads again. Takes the criterion resource_name, which is what add_google_ads_negative_keywords returned when the keyword was created; it also appears in the account change history. Only a NEGATIVE KEYWORD can be removed with it — a campaign's location, language or schedule criteria are refused (not_a_negative_keyword), they are targeting, not exclusions. Goes through the human approval gate unless the Autonomy row "Reklaam › Negatiivsed märksõnad" is on autopilot.
Destructive
Input schema
{'type': 'object', 'required': ['criterion_resource_name'], 'properties': {'reason': {'type': 'string', 'description': 'Optional one sentence for the approval card: why this term should be allowed again.'}, 'criterion_resource_name': {'type': 'string', 'description': 'Full resource name, e.g. "customers/1234567890/campaignCriteria/20713245160~10023"'}}, 'additionalProperties': False}
repair_connection
Repair connection
Safely retry one connection with a bounded read-only live check. Marks it connected only after verified success, never deletes or rotates credentials, and preserves status on temporary or unsupported failures.
Destructive
Input schema
{'type': 'object', 'required': ['service'], 'properties': {'service': {'type': 'string', 'description': 'Service ID to retry.'}}, 'additionalProperties': False}
reply_google_review
Reply Google review
Post or replace the business owner's public reply to one Google review (PUT …/reviews/{review_id}/reply). review_id comes from get_google_business_reviews; comment is plain text, at most 4096 bytes. Sending the text the review already carries changes nothing: the answer is changed=false and no approval card is made.
Destructive
Input schema
{'type': 'object', 'required': ['review_id', 'comment'], 'properties': {'comment': {'type': 'string', 'description': "The reply text, plain, in the reviewer's language."}, 'review_id': {'type': 'string', 'description': 'review_id from get_google_business_reviews (or the full accounts/…/locations/…/reviews/… name).'}}, 'additionalProperties': False}
reply_social_comment
Reply social comment
Reply to a comment on the project's Facebook page or Instagram business account, as the page/account. Facebook replies land in the comment's thread; Instagram replies attach to the top-level comment (threads are one level deep). Requires pages_manage_engagement (Facebook) / instagram_manage_comments (Instagram) on the connection. This is an external write: it goes through the human approval gate unless the social channel is on autopilot.
Destructive
Input schema
{'type': 'object', 'required': ['channel', 'comment_id', 'message'], 'properties': {'channel': {'enum': ['facebook', 'instagram', 'tiktok', 'linkedin'], 'type': 'string'}, 'message': {'type': 'string', 'maxLength': 2200, 'description': 'Reply text posted publicly as the page/account.'}, 'comment_id': {'type': 'string', 'description': 'The comment to reply to, from get_social_comments.'}}, 'additionalProperties': False}
reply_to_client
Reply to client
Answer the client in a dashboard thread. Give task_id to answer under that "Sinult on vaja" item, or thread="general" for the dashboard-wide thread. Write like a person the client pays: short, concrete, what you will do with what they gave you and whether you still need anything. If their answer gives you everything, pass resolve_task=true — the item leaves the client's "Sinult on vaja" list (label cleared, task handed back to you in AI mode with the answer in its note) and the page shows "Agent sai vajaliku kätte". The client gets your reply by e-mail when they opted in (one mail per run, batched). Do NOT use this for asks: new asks are still update_strategy_task with label needs_human + VAJA: note + human_reason.
Input schema
{'type': 'object', 'required': ['body'], 'properties': {'body': {'type': 'string', 'description': 'Your reply, plain text (max 5000 chars).'}, 'token': {'type': 'string', 'description': 'Dashboard public_token. Omit for your own dashboard.'}, 'thread': {'type': 'string', 'description': '"general" for the dashboard-wide thread (ignored when task_id is given).'}, 'task_id': {'type': 'integer', 'description': 'Strategy task id of the "Sinult on vaja" item (from get_client_messages or get_strategy_status).'}, 'resolve_task': {'type': 'boolean', 'default': False, 'description': 'You got what you needed: clear the human label and take the task back.'}}, 'additionalProperties': False}
request_client_photos
Request client photos
Ask the client for real photos — what, why, how many, by when — as a message in their dashboard thread (the general thread, or under a "Sinult on vaja" item with task_id), with a standard note that the people in the photos must consent; the client gets the usual notification e-mail, and the photos they attach there appear in list_creative_assets as client_upload. Use it instead of an AI image whenever a post must show the client's real work, premises, team or customers. Not for AI osakond dashboards (the growth lead asks there), and an unanswered ask for the same photos is not repeated within 7 days.
Input schema
{'type': 'object', 'required': ['what', 'why'], 'properties': {'why': {'type': 'string', 'description': 'What the photos are for, in the client\'s language, e.g. "oktoobri Instagrami postitused ja uus teenuseleht".'}, 'tags': {'type': 'array', 'items': {'type': 'string'}, 'maxItems': 10, 'description': 'Photo-bank tags the received photos get, e.g. ["köök", "referents"].'}, 'what': {'type': 'string', 'description': 'What to photograph, concretely and in the client\'s language, e.g. "valmis köögid päevavalges, horisontaalselt, ilma inimesteta".'}, 'count': {'type': 'integer', 'description': 'How many photos you need (1–50).'}, 'token': {'type': 'string', 'description': "The client's dashboard public_token (template seo or team). Omit for your own dashboard."}, 'task_id': {'type': 'integer', 'description': 'Ask under this "Sinult on vaja" item instead of the general thread.'}, 'deadline': {'type': 'string', 'description': 'YYYY-MM-DD, today or later.'}, 'people_expected': {'type': 'boolean', 'default': False, 'description': "true when the photos will show people (team, customers): the message then asks the client to confirm everyone's consent."}}, 'additionalProperties': False}
restore_site_file
Restore site file
Undo a write_site_file: put the file back exactly as it was before that backup (a file the write created is removed). The restore is backed up too, so it can itself be undone. Health-checked like a write. Use backup_id from write_site_file, read_site_file or list_site_file_backups.
Destructive
Input schema
{'type': 'object', 'required': ['backup_id'], 'properties': {'note': {'type': 'string', 'description': 'Why you restore.'}, 'backup_id': {'type': 'integer'}}, 'additionalProperties': False}
retry_first_comment
Retry first comment
Post (or re-post) the first comment on an ALREADY PUBLISHED social post whose automatic first comment failed — first_comment_id is empty and first_comment_error explains why (commonly a missing pages_manage_engagement / instagram_manage_comments permission; fix the permission first, then call this). Optionally pass first_comment to replace the stored text. Refuses when the comment is already live or the post is not published.
Destructive
Input schema
{'type': 'object', 'required': ['social_post_id'], 'properties': {'first_comment': {'type': 'string', 'maxLength': 2200, 'description': 'Optional replacement comment text; omit to use the text stored on the post.'}, 'social_post_id': {'type': 'integer', 'minimum': 1}}, 'additionalProperties': False}
review_draft
Review draft
Manager action on a draft: inspect (read only), approve, request_changes (with a note), edit (replace the body), schedule (set scheduled_at), reject (with a note), or publish (mark published after the channel posting is done). cancel withdraws an already-approved or scheduled draft (same as reject; for linked social posts it also cancels the post before it reaches the channel). If you only have draft_id and need to see what it is, call inspect or omit action. retry applies only to drafts with a linked social post and is done from the unlocked manager dashboard, not here.
Input schema
{'type': 'object', 'required': ['draft_id'], 'properties': {'body': {'type': 'string', 'description': 'New body text for the edit action.'}, 'note': {'type': 'string', 'description': 'Feedback for request_changes / reject.'}, 'action': {'enum': ['inspect', 'approve', 'request_changes', 'edit', 'schedule', 'reject', 'cancel', 'publish', 'retry'], 'type': 'string', 'description': 'The review action. Omit for inspect/read-only.'}, 'draft_id': {'type': 'integer', 'description': 'The draft to act on.'}, 'scheduled_at': {'type': 'string', 'description': 'Datetime for the schedule action (e.g. 2026-06-20 09:00).'}}, 'additionalProperties': False}
revise_draft
Revise draft
Agent action: revise a draft the manager sent back (status changes_requested) — text (body), media (media_urls), and/or the requested time (scheduled_at). The SAME draft/social_post id is kept and the replaced version is archived in the card's revision history, so NEVER cancel + resubmit just to change content: revise instead. New text passes the same pre-review check as submit_draft; on qa_failed nothing changes — fix the listed issues and revise again. The draft returns to "pending" for re-approval (or its veto window restarts); a linked social post follows (caption/media/time) and returns to the manager queue. This is how you act on the manager's feedback shown in read_dashboard action_items.
Input schema
{'type': 'object', 'required': ['draft_id'], 'properties': {'body': {'type': 'string', 'description': 'The revised full text. Omit to keep the current text (media/time-only revision).'}, 'draft_id': {'type': 'integer', 'description': 'The draft to revise.'}, 'media_urls': {'type': 'array', 'items': {'type': 'string'}, 'maxItems': 10, 'description': 'Replacement media for the linked social post (public HTTPS URLs). Same rules as submit_social_post: reel/story exactly 1, carousel at least 2, Instagram images must be JPEG.'}, 'scheduled_at': {'type': 'string', 'description': 'New requested publish time (future datetime); applied when the manager approves.'}}, 'additionalProperties': False}
run_channel_agent_now
Run channel agent now
Manager/orchestrator only: start one server run of a channel agent now (it begins within a minute). See the outcome with list_agent_runs.
Input schema
{'type': 'object', 'required': ['channel'], 'properties': {'channel': {'type': 'string', 'description': 'seo, paid, paid_social, content, social, email or local'}, 'instructions': {'type': 'string', 'description': 'Optional one-off focus for this run'}}, 'additionalProperties': False}
schedule_email
Schedule email
Schedule an email to be sent at a specific future date and time. Provide recipient, subject, body (HTML or plain text), and the exact send time (YYYY-MM-DD HH:MM:SS). Supports CC/BCC. Use when the user wants to "send this email tomorrow" or "schedule a follow-up email."
Destructive
Input schema
{'type': 'object', 'required': ['to', 'subject', 'body', 'send_at'], 'properties': {'cc': {'type': 'array', 'items': {'type': 'string'}, 'description': 'CC recipients'}, 'to': {'type': 'string'}, 'bcc': {'type': 'array', 'items': {'type': 'string'}, 'description': 'BCC recipients'}, 'body': {'type': 'string'}, 'html': {'type': 'boolean', 'default': True}, 'send_at': {'type': 'string', 'description': 'When to send (YYYY-MM-DD HH:MM:SS)'}, 'subject': {'type': 'string'}}, 'additionalProperties': False}
score_citability
Score citability
Citability score 0–100 of one or more public pages: how easily an AI answer engine (ChatGPT, Perplexity, Gemini, Google AI Overviews) can lift a citable fact from the page. Checks answer-first structure (H1 + direct answer paragraph), concrete statistics, author attribution, freshness (published/modified date), Q&A blocks (FAQPage / question headings), structure (H2s, lists, tables, length), entity schema (Organization/LocalBusiness/Article/Service JSON-LD) and crawlability (noindex, canonical). Returns per-page score + grade + check details + recommendations, and average_score across pages. Works on any domain, so use it on competitors too. Typical input: the homepage and the main service page.
Destructive
Input schema
{'type': 'object', 'properties': {'url': {'type': 'string', 'description': 'Single URL alternative to urls.'}, 'urls': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Full URLs to score (1–5).'}}, 'additionalProperties': False}
scrape_website
Scrape website
Scrape and extract data from any public website. Can extract text content, meta tags (title, description, OG tags), headings structure, links, and images. Supports JavaScript-rendered pages and custom CSS selectors for specific elements. Use for competitor research, content analysis, price monitoring, or when the user asks to "check" or "look at" a specific website.
Read only
Input schema
{'type': 'object', 'required': ['url'], 'properties': {'url': {'type': 'string', 'description': 'URL to scrape'}, 'extract': {'type': 'array', 'items': {'enum': ['text', 'links', 'images', 'meta', 'headings', 'all'], 'type': 'string'}, 'default': ['text', 'meta'], 'description': 'What to extract from the page'}, 'javascript': {'type': 'boolean', 'default': True, 'description': 'Execute JavaScript on page'}, 'include_html': {'type': 'boolean', 'default': False, 'description': 'Accepted for crawler compatibility. The compact scraper response returns extracted text/meta/links/images, not raw page HTML.'}, 'wait_for_selector': {'type': 'string', 'description': 'CSS selector to wait for (for dynamic content)'}}, 'additionalProperties': False}
search
Search
Search the SharksAPI.AI tool catalog and connected project capabilities. Use this to find relevant SharksAPI tools, dashboards, integrations, or documentation before calling a specific tool.
Read only Destructive
Input schema
{'type': 'object', 'required': ['query'], 'properties': {'query': {'type': 'string', 'description': 'Search query, for example "Google Analytics traffic", "SEO keywords", "WordPress posts", or "dashboard strategy tasks".'}}, 'additionalProperties': False}
Output schema
{'type': 'object', 'required': ['results'], 'properties': {'results': {'type': 'array', 'items': {'type': 'object', 'required': ['id', 'title', 'url'], 'properties': {'id': {'type': 'string'}, 'url': {'type': 'string'}, 'text': {'type': 'string'}, 'title': {'type': 'string'}}, 'additionalProperties': False}}}, 'additionalProperties': False}
search_ariregister_by_name
Search ariregister by name
Search the Estonian Business Registry by company name keyword. No credentials needed — uses the public autocomplete endpoint. Returns up to 10 active companies with name, reg_code, and address. Use for quick lookups: "kas Bolt Technology on registreeritud", "leia kõik Eesti firmad nimega Tark", "find companies with Invest in name".
Read only
Input schema
{'type': 'object', 'required': ['keyword'], 'properties': {'limit': {'type': 'integer', 'default': 10, 'maximum': 10, 'minimum': 1, 'description': 'Max results (1–10). Default 10.'}, 'keyword': {'type': 'string', 'description': 'Company name or partial name to search for.'}}, 'additionalProperties': False}
search_ariregister_companies
Search ariregister companies
Search the Estonian Business Registry (ariregister.rik.ee) for companies by EMTAK sector code and annual turnover range. Returns name, reg_code, address, email, phone, emtak_code, turnover (EUR, from official annual reports). Requires free RIK credentials — register at ariregister.rik.ee/est/contract/step1 and add username/password to your Äriregister connection. Use for Estonian B2B prospecting: "leia IT firmad (EMTAK 6201) käibega 200k–600k", "find construction companies (EMTAK 4120) with turnover above 1M EUR", "millised Eesti logistikafirmad on keskmise suurusega". Companies without a published annual report are excluded.
Read only
Input schema
{'type': 'object', 'required': ['emtak_code', 'min_turnover'], 'properties': {'limit': {'type': 'integer', 'default': 20, 'maximum': 50, 'minimum': 1, 'description': 'Max companies to return (1–50). Default 20.'}, 'emtak_code': {'type': 'string', 'description': 'EMTAK sector code (e.g. "6201" software development, "4120" construction, "4711" food retail, "4941" road freight). See emtak.rik.ee.'}, 'max_turnover': {'type': 'integer', 'minimum': 0, 'description': 'Maximum annual turnover in EUR, inclusive. Omit for no upper bound.'}, 'min_turnover': {'type': 'integer', 'minimum': 0, 'description': 'Minimum annual turnover (müügitulu) in EUR, inclusive.'}}, 'additionalProperties': False}
search_drive
Search drive
Search Google Drive files by keyword across file names. Returns matching files with id, name, mime type, and web view link. Use to locate a specific document by name when folder path is unknown.
Read only
Input schema
{'type': 'object', 'required': ['query'], 'properties': {'limit': {'type': 'integer', 'default': 20}, 'query': {'type': 'string', 'description': 'Search term to match against file names.'}}, 'additionalProperties': False}
search_meta_ad_library
Search Meta ad library
Competitor ads from the Meta Ad Library API (Facebook, Instagram, Messenger, Audience Network, Threads): by page ids or search terms, per country, active or all. Per ad: page, primary texts, headlines, link captions, start/stop date and days running, platforms, snapshot URL, and for ads shown in the EU the EU reach, age/gender/country reach breakdown, targeting (age, gender, locations) and who paid. Returns a summary per page: active ads, long-runners (running ≥ 30 days — the ads the advertiser keeps paying for) and new launches in the last 14 days. Evidence for angle/offer/format mapping — longevity is a signal, not proof of profit. check_facebook_ads stays the quick yes/no.
Read only
Input schema
{'type': 'object', 'properties': {'limit': {'type': 'integer', 'maximum': 500, 'minimum': 1, 'description': 'Max ads (default 100).'}, 'page_ids': {'type': 'array', 'items': {'type': 'string'}, 'maxItems': 10, 'description': 'Facebook page ids of competitors (preferred: exact).'}, 'countries': {'type': 'array', 'items': {'type': 'string'}, 'description': 'ISO-2 reached countries, default ["EE"].'}, 'search_terms': {'type': 'string', 'description': 'Keyword search when page ids are unknown (brand name, product).'}, 'active_status': {'enum': ['ACTIVE', 'ALL', 'INACTIVE'], 'type': 'string', 'description': 'Default ACTIVE.'}, 'delivery_date_min': {'type': 'string', 'description': 'YYYY-MM-DD: only ads delivered since.'}}, 'additionalProperties': False}
search_serp_google
Search SERP Google
Live Google organic SERP for a keyword. Returns the top N ranked results with position, URL, title, description, and domain. Use this when the user asks "who ranks for X?", "what does Google show for keyword Y in Estonia?", for SERP snapshots before/after content launches, or for competitor discovery on a specific query. Default location is Estonia (2233), language Estonian (et). For bulk search volumes use keyword_search_volume instead; for a whole domain use domain_keywords.
Read only
Input schema
{'type': 'object', 'required': ['keyword'], 'properties': {'depth': {'type': 'integer', 'default': 10, 'description': 'How many SERP items to return (max 100)'}, 'limit': {'type': 'integer', 'default': 10, 'description': 'Alias for depth: how many SERP items to return (max 100).'}, 'keyword': {'type': 'string', 'description': 'Search query to run on Google'}, 'language': {'type': 'string', 'description': 'Alias for language_code (et, en, ru, fi, ...).'}, 'location': {'type': 'string', 'description': 'Alias for location_code. Accepts Estonia, United States, United Kingdom, or a numeric DataForSEO location code.'}, 'language_code': {'type': 'string', 'default': 'et', 'description': 'Language code (et, en, ru, fi, ...)'}, 'location_code': {'type': 'integer', 'default': 2233, 'description': 'DataForSEO location code (2233 = Estonia, 2840 = US, 2826 = UK)'}}, 'additionalProperties': False}
search_web_mentions
Search web mentions
DEPRECATED: use get_social_mentions instead. This tool will be removed in v2.2. Stub returns an error gracefully and does not perform a search.
Read only
Input schema
{'type': 'object', 'required': ['query'], 'properties': {'limit': {'type': 'integer', 'default': 50, 'description': 'Maximum results'}, 'query': {'type': 'string', 'description': 'Search query (brand name, keyword, etc)'}, 'sources': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Specific domains to search (optional)'}, 'days_back': {'type': 'integer', 'default': 30, 'description': 'Search results from last N days'}, 'exclude_domains': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Domains to exclude from results'}}, 'additionalProperties': False}
send_email
Send email
Send an email immediately via the connected email service. Supports HTML or plain text body, CC/BCC recipients, and file attachments. Use when the user asks to "send an email", "email this to someone", or "reach out to a client."
Destructive
Input schema
{'type': 'object', 'required': ['to', 'subject', 'body'], 'properties': {'cc': {'type': 'array', 'items': {'type': 'string'}, 'description': 'CC recipients. The response lists every address the message went to.'}, 'to': {'type': 'string', 'description': 'Recipient email address'}, 'bcc': {'type': 'array', 'items': {'type': 'string'}, 'description': 'BCC recipients'}, 'body': {'type': 'string', 'description': 'Email body (HTML or plain text)'}, 'html': {'type': 'boolean', 'default': True, 'description': 'Is body HTML?'}, 'subject': {'type': 'string', 'description': 'Email subject'}, 'attachments': {'type': 'array', 'items': {'type': 'object', 'properties': {'path': {'type': 'string'}, 'filename': {'type': 'string'}}}}}, 'additionalProperties': False}
send_meta_conversion_events
Send Meta conversion events
Send CRM outcomes to Meta through the Conversions API so delivery learns which leads became customers: lead-stage events (e.g. QualifiedLead, MeetingBooked, Converted) for Instant Form leads keyed on the Meta lead_id (action_source system_generated, Conversion Leads optimisation), or offline sales / website events with e-mail, phone, external_id, fbc/fbp. E-mail, phone, names and external_id are normalised and SHA-256 hashed on the server — raw personal data never leaves SharksAPI. event_id deduplicates against the pixel. Use test_event_code first (shows in Events Manager → Test events, affects nothing); the real send goes through the Postkast approval. The pixel must belong to the connected ad account.
Destructive
Input schema
{'type': 'object', 'required': ['pixel_id', 'events'], 'properties': {'events': {'type': 'array', 'items': {'type': 'object', 'required': ['event_name', 'event_time'], 'properties': {'fbc': {'type': 'string'}, 'fbp': {'type': 'string'}, 'email': {'type': 'string'}, 'phone': {'type': 'string'}, 'value': {'type': 'number'}, 'country': {'type': 'string', 'description': 'ISO-2, e.g. ee'}, 'lead_id': {'type': 'string', 'description': 'Meta Instant Form lead id (15–17 digits).'}, 'currency': {'type': 'string', 'description': 'Default EUR.'}, 'event_id': {'type': 'string', 'description': 'Dedup key (same as the pixel event, or the CRM stage change id).'}, 'last_name': {'type': 'string'}, 'event_name': {'type': 'string', 'description': 'Standard (Lead, Purchase, CompleteRegistration, Schedule…) or the CRM stage name used for Conversion Leads (e.g. "QualifiedLead").'}, 'event_time': {'type': 'string', 'description': 'When it happened, ISO 8601 with offset (e.g. 2026-09-20T14:05:00+03:00). Not older than 7 days for website events; lead-stage events within 28 days of the lead work best.'}, 'first_name': {'type': 'string'}, 'external_id': {'type': 'string', 'description': 'CRM contact id.'}, 'action_source': {'enum': ['system_generated', 'physical_store', 'phone_call', 'email', 'website', 'chat', 'business_messaging', 'other'], 'type': 'string', 'description': 'system_generated for CRM lead stages (default).'}, 'event_source_url': {'type': 'string'}}}, 'maxItems': 1000, 'minItems': 1}, 'pixel_id': {'type': 'string', 'description': 'Dataset / pixel id from get_meta_signal_health.'}, 'test_event_code': {'type': 'string', 'description': 'From Events Manager → Test events. With it Meta only shows the events.'}, 'lead_event_source': {'type': 'string', 'description': 'CRM name for Conversion Leads, e.g. "Pipedrive", "HubSpot", "Sharks CRM".'}}, 'additionalProperties': False}
send_resend_email
Send resend email
Send a transactional email via Resend email platform. Requires sender address (must be from a verified domain), recipient(s), subject, and HTML or plain text body. Use when asked to "send a transactional email", "email this notification via Resend", or "send a confirmation email."
Destructive
Input schema
{'type': 'object', 'required': ['from', 'to', 'subject'], 'properties': {'to': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Recipient email addresses'}, 'from': {'type': 'string', 'description': 'Sender email address'}, 'html': {'type': 'string', 'description': 'HTML email body'}, 'text': {'type': 'string', 'description': 'Plain text email body'}, 'subject': {'type': 'string', 'description': 'Email subject'}}, 'additionalProperties': False}
send_review_request
Send review request
Email 1-50 customers a short, personal request for a Google review, from the project's own connected mailbox: one plain-text email each with the business name and a single link (the review link from get_gbp_review_link unless you pass review_url), no tracking. Anyone asked in the last 180 days is skipped and reported by index — addresses are never echoed back. It is outbound mail: it follows the Autonomy row "Sisu › E-kirjad väljapoole" like send_email (a human click by default, refused on Manual).
Destructive
Input schema
{'type': 'object', 'required': ['recipients'], 'properties': {'intro': {'type': 'string', 'description': 'Optional opening paragraph in place of the default thank-you, at most 600 characters, no links.'}, 'language': {'enum': ['et', 'en'], 'type': 'string', 'description': 'et (default) or en.'}, 'recipients': {'type': 'array', 'items': {'type': 'object', 'required': ['email'], 'properties': {'name': {'type': 'string', 'description': 'Optional first name for the greeting.'}, 'email': {'type': 'string'}}, 'additionalProperties': False}, 'maxItems': 50, 'minItems': 1, 'description': 'The customers to ask, e.g. [{"email": "mari@example.ee", "name": "Mari"}]. Only people who bought or used the service.'}, 'review_url': {'type': 'string', 'description': "Optional https review link; defaults to the connected Business Profile's link."}, 'business_name': {'type': 'string', 'description': 'Optional name to sign with; defaults to the Business Profile title.'}}, 'additionalProperties': False}
set_agent_schedule
Set agent schedule
Manager/orchestrator only: when a channel agent (made by create_channel_agents) works on its own on the server. Each run it reads get_my_tasks, does the due work with its channel's tools and stops; writes that leave the platform follow the client's autonomy level and wait in the Postkast, and the platform makes each approved call itself. frequency=off stops it. Every tool call costs credits as usual.
Input schema
{'type': 'object', 'required': ['channel', 'frequency'], 'properties': {'time': {'type': 'string', 'description': 'HH:MM, Europe/Tallinn; default 06:00'}, 'channel': {'type': 'string', 'description': 'seo, paid, paid_social, content, social, email or local'}, 'weekday': {'enum': ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'], 'type': 'string', 'description': 'For weekly; default monday'}, 'frequency': {'enum': ['daily', 'weekly', 'off'], 'type': 'string'}, 'instructions': {'type': 'string', 'description': 'Standing instructions the agent gets on every run (focus, limits)'}, 'max_tool_calls': {'type': 'integer', 'maximum': 60, 'minimum': 5, 'description': 'Tool-call budget per run; default 25'}}, 'additionalProperties': False}
set_google_ads_ad_schedule
Set Google ads ad schedule
Set the ad schedule of one Google Ads campaign: the days and hours its ads may run, in the account's own time zone. Send the COMPLETE new schedule — slots missing from it are removed, slots that stay the same are kept untouched (with any bid adjustment they carry). Each slot is {day, start, end} with times on the quarter hour ("08:00", "17:45", end may be "24:00"); at most 6 slots per day, no overlaps. clear=true removes every slot so the campaign runs around the clock. The change is sent as ONE all-or-nothing mutate, so the campaign is never left half-scheduled. An identical schedule is a no-op. Goes through the approval gate — the card shows the old and new week — unless the Autonomy row "Reklaam › Reklaamigraafik" is on autopilot.
Destructive
Input schema
{'type': 'object', 'required': ['campaign_id'], 'properties': {'clear': {'type': 'boolean', 'description': 'true = remove the whole schedule (ads may run 24/7). Only with an empty or missing schedule.'}, 'reason': {'type': 'string', 'description': 'Optional one sentence for the approval card: why the hours change.'}, 'schedule': {'type': 'array', 'items': {'type': 'object', 'required': ['day', 'start', 'end'], 'properties': {'day': {'enum': ['MONDAY', 'TUESDAY', 'WEDNESDAY', 'THURSDAY', 'FRIDAY', 'SATURDAY', 'SUNDAY'], 'type': 'string'}, 'end': {'type': 'string', 'description': 'HH:MM on the quarter hour after start, up to 24:00'}, 'start': {'type': 'string', 'description': 'HH:MM on the quarter hour, 00:00..23:45'}}, 'additionalProperties': False}, 'description': 'The complete new weekly schedule, e.g. [{"day": "MONDAY", "start": "08:00", "end": "18:00"}, …]'}, 'campaign_id': {'type': 'string', 'description': 'Campaign id from list_google_ads_campaigns (digits).'}}, 'additionalProperties': False}
set_google_ads_ai_max_controls
Set Google ads AI max controls
Guardrails for AI Max / automated text on one campaign, through the Postkast approval: text guidelines (term_exclusions — words generated text must never use, max 25; messaging_restrictions — rules in plain language, max 40), text customization and final-URL expansion on/off (asset automation), URL exclusions (pages AI Max may never send traffic to), and search-term matching off for chosen ad groups (keywords only, no keywordless expansion). AI Max itself is switched on/off in Google Ads by a human. Read get_google_ads_ai_max_report first.
Destructive
Input schema
{'type': 'object', 'required': ['campaign_id'], 'properties': {'reason': {'type': 'string'}, 'campaign_id': {'type': 'string'}, 'exclude_urls': {'type': 'array', 'items': {'type': 'string'}, 'maxItems': 50, 'description': 'URL or URL prefix (e.g. "example.ee/karjaar") AI Max must never land on.'}, 'term_exclusions': {'type': 'array', 'items': {'type': 'string'}, 'maxItems': 25, 'description': "Replaces the campaign's list."}, 'text_customization': {'type': 'boolean', 'description': 'false = opt out of AI-generated text assets.'}, 'final_url_expansion': {'type': 'boolean', 'description': "false = keep traffic on the ads' own final URLs."}, 'messaging_restrictions': {'type': 'array', 'items': {'type': 'string'}, 'maxItems': 40, 'description': 'Replaces the campaign\'s list, e.g. "Ära luba sama päeva teenust".'}, 'disable_search_term_matching_ad_group_ids': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Ad groups that should serve on their keywords only.'}}, 'additionalProperties': False}
set_google_ads_campaign_budget
Set Google ads campaign budget
Change the daily budget of one Google Ads campaign (campaignBudgets:mutate, update mask "amount_micros"). This waits for a human click in the Postkast — the channel-level autopilot does not cover it and neither does a trusted first-party agent token. Only a human putting this very Autonomy row (Google Ads › "Kampaania päevaeelarve") on Autopilot lets it run without a click, and the ceilings below hold even then. Two ceilings a human set must hold: the campaign daily cap and the account daily cap (the sum of every enabled campaign's daily budget after the change). If either ceiling is missing the call is refused with budget_cap_not_set and no approval card is created — a human enters the numbers first. Over a ceiling: budget_over_cap, in BOTH directions (lowering 2000 to 500 under a 300 cap is still over the cap). The amount is whole euro cents above zero. The account must be in EUR, because the caps are in EUR. If the campaign budget is shared with other campaigns, the call is refused with budget_is_shared and the campaign ids, unless allow_shared is true; the approval then covers exactly that set of campaigns, and if the set or the current budget has moved by the time you execute, the approval is voided (budget_scope_changed / budget_changed_since_approval) and you ask for a new one.
Destructive
Input schema
{'type': 'object', 'required': ['campaign_id', 'daily_budget_eur'], 'properties': {'reason': {'type': 'string', 'description': 'Optional one sentence for the approval card and the audit log: why this budget should change.'}, 'campaign_id': {'type': 'string', 'description': 'Campaign id from list_google_ads_campaigns, e.g. "20713245160" (digits only, not the resource name)'}, 'allow_shared': {'type': 'boolean', 'description': 'Set true only after budget_is_shared told you which other campaigns use the same budget and you still mean to change all of them.'}, 'daily_budget_eur': {'type': 'number', 'maximum': 1000000, 'minimum': 0, 'description': 'The new daily budget in euros, at most two decimals, e.g. 25 or 12.50. Converted to micros for the API; compared against the caps in micros, so 300.01 is over a 300 cap.'}, 'affected_campaign_ids': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Ignored as input: the platform reads the campaigns sharing this budget itself and overwrites this field, so the human approves the real scope. It appears in the approval card and in the answer.'}}, 'additionalProperties': False}
set_marketing_plan
Set marketing plan
Create or update the shared marketing plan on a MANAGER dashboard — the team's common foundation. Holds the north-star goal, KPIs and strategic pillars. Each pillar lists agent_keys that map the plan to specific teammates; an agent sub-dashboard whose agent_key matches a pillar shows that pillar as "your pillar". Call this once after creating the manager dashboard, and again to revise. Re-calling replaces the active plan for that manager.
Input schema
{'type': 'object', 'required': ['manager_token', 'north_star'], 'properties': {'kpis': {'type': 'array', 'items': {'type': 'object'}, 'description': 'KPI objects: {name, current, target, unit, direction:"up"|"down"}. direction "down" = lower is better.'}, 'name': {'type': 'string', 'description': 'Plan name (e.g. "Q3 2026 Turundusplaan").'}, 'budget': {'type': 'string', 'description': 'Optional budget label (e.g. "€8000 / kuus").'}, 'period': {'type': 'string', 'description': 'Optional period label (e.g. "Q3 2026").'}, 'pillars': {'type': 'array', 'items': {'type': 'object'}, 'description': 'Strategic pillars: {name, objective, accent (hex), agent_keys:[...]}. agent_keys link the pillar to teammates by their agent_key.'}, 'audience': {'type': 'string', 'description': 'Optional target audience.'}, 'north_star': {'type': 'string', 'description': 'The single overarching goal for the period.'}, 'manager_token': {'type': 'string', 'description': 'Public token of the manager dashboard this plan governs.'}}, 'additionalProperties': False}
set_meta_adset_budget
Set Meta adset budget
Change the DAILY budget of one Meta ad set (POST /{id} daily_budget, in cents). Only for an ad set that has its own budget; one under an Advantage campaign budget is refused with budget_on_campaign — use set_meta_campaign_budget. This waits for a human click in the Postkast — the channel-level autopilot and trusted tokens do not cover it; only a human putting this very Autonomy row (Meta › "Päevaeelarve") on Autopilot lets it run without a click, and the ceilings hold even then. Two ceilings a human set must hold: one budget per day, and the whole ad account per day after the change; either missing → budget_cap_not_set and no card. Over a ceiling → budget_over_cap, in both directions. Whole euro cents above zero; EUR accounts only; a lifetime budget cannot be changed here (lifetime_budget_not_supported). If the budget moved between the approval and your repeat call, the approval is voided (budget_changed_since_approval).
Destructive
Input schema
{'type': 'object', 'required': ['adset_id', 'daily_budget_eur'], 'properties': {'reason': {'type': 'string', 'description': 'Optional one sentence for the approval card and the audit log: why this budget should change.'}, 'adset_id': {'type': 'string', 'description': 'Meta ad set id from list_meta_adsets (digits).'}, 'daily_budget_eur': {'type': 'number', 'maximum': 1000000, 'minimum': 0, 'description': 'The new daily budget in euros, at most two decimals, e.g. 15 or 22.50.'}}, 'additionalProperties': False}
set_meta_campaign_budget
Set Meta campaign budget
Change the DAILY budget of one Meta campaign (POST /{id} daily_budget, in cents). Only for a campaign with an Advantage campaign budget (budget_level "campaign" in list_meta_campaigns); a campaign whose ad sets carry the budgets is refused with budget_on_adsets. This waits for a human click in the Postkast — the channel-level autopilot and trusted tokens do not cover it; only a human putting this very Autonomy row (Meta › "Päevaeelarve") on Autopilot lets it run without a click, and the ceilings hold even then. Two ceilings a human set must hold: one budget per day, and the whole ad account per day after the change; either missing → budget_cap_not_set and no card. Over a ceiling → budget_over_cap, in both directions. Whole euro cents above zero; EUR accounts only; a lifetime budget cannot be changed here (lifetime_budget_not_supported). If the budget moved between the approval and your repeat call, the approval is voided (budget_changed_since_approval).
Destructive
Input schema
{'type': 'object', 'required': ['campaign_id', 'daily_budget_eur'], 'properties': {'reason': {'type': 'string', 'description': 'Optional one sentence for the approval card and the audit log: why this budget should change.'}, 'campaign_id': {'type': 'string', 'description': 'Meta campaign id from list_meta_campaigns (digits).'}, 'daily_budget_eur': {'type': 'number', 'maximum': 1000000, 'minimum': 0, 'description': 'The new daily budget in euros, at most two decimals, e.g. 15 or 22.50.'}}, 'additionalProperties': False}
set_project_profile
Set project profile
Save your person's onboarding answers (from get_onboarding_status questions_to_ask). Send only the fields you have; earlier answers are kept. Returns the updated onboarding status.
Input schema
{'type': 'object', 'properties': {'goals': {'type': 'array', 'items': {'type': 'string'}, 'description': '1-3 marketing goals in their words'}, 'notes': {'type': 'string'}, 'tools': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Marketing tools they use, e.g. "Google Analytics", "Google Ads", "WordPress"'}, 'markets': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Countries or regions they sell to'}, 'website': {'type': 'string', 'description': 'Main website URL'}, 'industry': {'type': 'string'}, 'ai_client': {'enum': ['claude', 'chatgpt', 'gemini', 'grok', 'copilot', 'other'], 'type': 'string', 'description': 'The AI your person talks to you through'}, 'company_name': {'type': 'string'}, 'business_model': {'enum': ['services', 'ecommerce', 'saas', 'local', 'other'], 'type': 'string'}, 'monthly_budget_eur': {'type': 'number'}, 'decision_maker_email': {'type': 'string', 'description': 'Who approves the plan and spending'}}, 'additionalProperties': False}
submit_ad_creative
Submit ad creative
Put a new Meta ad creative on the AI osakond dashboard for the client to approve, or a new version of one (replaces_id — after the client asked for a change; the old ad keeps running until the new version is approved and launched). Nothing starts in Meta before the client presses "Kinnita". Refused while the brand guide is incomplete (get_brand_guide.brand_ready = false). approval_reasons: why it needs the client, besides being new (e.g. "hind tekstis", "inimesed pildil").
Input schema
{'type': 'object', 'properties': {'text': {'type': 'string', 'description': 'The primary text the ad shows.'}, 'media': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Public URLs of the image(s) or video.'}, 'start': {'type': 'string', 'description': 'YYYY-MM-DD, when it should start.'}, 'title': {'type': 'string'}, 'token': {'type': 'string', 'description': 'Dashboard public_token. Optional — defaults to your own dashboard.'}, 'format': {'type': 'string', 'description': 'e.g. "Video 0:20", "Karussell", "Pilt"'}, 'audience': {'type': 'string'}, 'platform': {'enum': ['meta', 'youtube', 'chatgpt'], 'type': 'string', 'description': "Where it runs: meta (default), youtube (Google Ads video) or chatgpt (sponsored card). A new version keeps its predecessor's platform."}, 'placements': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Feed, Reels, Stories, …'}, 'replaces_id': {'type': 'integer', 'description': 'The creative this is a new version of.'}, 'approval_reasons': {'type': 'array', 'items': {'type': 'string'}}}, 'additionalProperties': False}
submit_bing_urls
Submit Bing URLs
Ask Bing to crawl up to 100 new or changed URLs of the connected site now (Bing URL Submission API, SubmitUrlBatch). Bing's daily quota is returned; unused quota does not carry over. Use after publishing or fixing a page. Nothing on the website changes — this only asks Bing to recrawl.
Destructive
Input schema
{'type': 'object', 'required': ['urls'], 'properties': {'urls': {'type': 'array', 'items': {'type': 'string'}, 'maxItems': 100, 'minItems': 1, 'description': 'Full URLs of the connected site.'}}, 'additionalProperties': False}
submit_draft
Submit draft
Submit a piece of content for the marketing manager to approve — a social post, web text, newsletter, blog/news article, ad text, event text, campaign message or SEO text change. Before anything is created, a pre-review check reads the project's confirmed facts, brand rules and the manager's earlier feedback: if it finds a blocking problem (unproven claim, contradiction with a fact, wrong month/season, broken brand rule, dead link, placeholder) NOTHING is submitted and you get status qa_failed with the issues — fix them and call submit_draft again (takes up to ~1 minute). On AUTOPILOT the draft is auto-approved and you proceed to publish; on VETO the draft goes through by itself after the veto window (auto_approve_at) unless the manager stops it; otherwise it waits in the Postkast. If a memory constraint marks this specific content as an exception that a human must see, pass require_approval=true. Content must be anonymous marketing copy — never include applicant personal data.
Input schema
{'type': 'object', 'required': ['type', 'title', 'body'], 'properties': {'body': {'type': 'string', 'description': 'The full draft text to be reviewed.'}, 'type': {'enum': ['social_post', 'web_text', 'newsletter', 'blog', 'ad_text', 'event_text', 'campaign_message', 'seo_change'], 'type': 'string', 'description': 'Content type.'}, 'title': {'type': 'string', 'description': 'Short headline shown in the list.'}, 'channel': {'type': 'string', 'description': 'Where it goes: facebook, instagram, linkedin, email, web, blog, google_ads, meta_ads, event.'}, 'deadline': {'type': 'string', 'description': 'Due date YYYY-MM-DD or today/daysAgo tokens (optional).'}, 'priority': {'enum': ['low', 'medium', 'high'], 'type': 'string', 'description': 'low | medium | high (default medium).'}, 'manager_token': {'type': 'string', 'description': "Manager dashboard public_token to attach this draft to (optional; defaults to the project's manager dashboard)."}, 'related_activity': {'type': 'string', 'description': 'Related campaign/activity name (optional).'}, 'require_approval': {'type': 'boolean', 'description': "Ask for a human review on an autopilot channel. Honored only when the title names a manager's call — money (prices, budget, billing), a contract or legal text, personal data or brand positioning; otherwise ignored, because autopilot means you carry the work through. Name the topic in the title when you set it."}}, 'additionalProperties': False}
submit_indexnow
Submit IndexNow
Notify IndexNow search engines (Bing, Yandex, Seznam, Naver, Yep) that up to 100 URLs of ONE of the project's own sites were added, changed or deleted. Needs the project's IndexNow key file on that host once: the first call returns the exact file name and content to publish (or confirms it is live) — WordPress sites can instead enable Rank Math → Instant Indexing. URLs must belong to a site connected to this project (Search Console, Bing, WordPress). Google does not use IndexNow.
Destructive
Input schema
{'type': 'object', 'required': ['urls'], 'properties': {'urls': {'type': 'array', 'items': {'type': 'string'}, 'maxItems': 100, 'minItems': 1, 'description': 'Full URLs, all on the same host.'}, 'check_only': {'type': 'boolean', 'description': 'Only verify/return the key-file setup, submit nothing.'}}, 'additionalProperties': False}
submit_social_post
Submit social post
Submit a Facebook or Instagram post, reel, carousel, or story — or a TikTok video — for human approval. Instagram images must be JPEG (PNG is rejected by Meta); Instagram has no native scheduling, so scheduled posts are published by this platform at scheduled_at. TikTok: channel=tiktok, type=reel, exactly one video (mp4/mov) in media_urls, caption at most 2200 characters, no link / first_comment / share_to_story; set ai_generated=true for AI-made video (TikTok requires the label). Submit every TikTok video here before it goes out, so the client sees it in the content plan. Until the app passes the TikTok Direct Post audit the platform cannot post it: once approved, you (the submitting agent) upload the video yourself in TikTok Studio for its slot with exactly the same caption — no Postkast task is made; at the slot the status turns awaiting_manual. After the audit the platform posts it itself. Either way it is marked published within about 15 minutes of the video being on TikTok (matched by the start of the caption). It waits for an unlocked manager dashboard to approve it, unless the Autonomy slider puts this post type (link share, post, reel, story) on autopilot — then it is approved on submit and ships at its slot.
Input schema
{'type': 'object', 'required': ['channel'], 'properties': {'link': {'type': 'string', 'description': 'Facebook HTTPS link; Instagram does not support link posts.'}, 'type': {'enum': ['post', 'reel', 'carousel', 'story'], 'type': 'string', 'description': 'Default post. Use reel, carousel, or story only when the media shape needs it.'}, 'caption': {'type': 'string', 'description': 'Post caption.'}, 'channel': {'enum': ['facebook', 'instagram', 'tiktok', 'linkedin'], 'type': 'string', 'description': "linkedin = the project's LinkedIn company page: type post (caption with an optional link card or one JPG/PNG/GIF image) or carousel (2-10 images), caption required and at most 3000 characters, no video/reel/story, first_comment at most 1250 characters; scheduled posts go out at scheduled_at. Refused with the missing step until a page admin has allowed LinkedIn publishing for the project."}, 'group_key': {'type': 'string', 'maxLength': 100, 'description': 'Give EVERY channel/format variant of the same content piece the same group_key (e.g. "story-pakk-2026-08-26"): the approvals view then shows ONE card with one Approve/Cancel/Schedule for the whole group instead of a card per variant. Always set this when submitting the same content to several channels.'}, 'media_urls': {'type': 'array', 'items': {'type': 'string'}, 'maxItems': 10}, 'ai_generated': {'type': 'boolean', 'description': 'TikTok: the video is AI-generated or AI-edited, posted with the TikTok AI-content label.'}, 'publish_mode': {'enum': ['draft', 'schedule', 'publish'], 'type': 'string', 'description': 'Default draft. Use schedule with scheduled_at or publish when requesting immediate publication after approval.'}, 'scheduled_at': {'type': 'string', 'description': 'Future datetime, required only for schedule.'}, 'first_comment': {'type': 'string', 'maxLength': 2200, 'description': 'Optional comment posted by the platform right after publishing (e.g. the full link, since Instagram captions are not clickable). Not supported for stories. Requires pages_manage_engagement (Facebook) / instagram_manage_comments (Instagram) on the connection.'}, 'internal_label': {'type': 'string', 'maxLength': 120, 'description': 'Human-readable card title for the approvals dashboard, e.g. "Story, Paide Vesi, N 27.08 kl 12:15". Dashboard-only — NEVER published to the channel. Always set this for media-only posts (stories, reels) whose caption is empty, so the reviewer is not shown a raw media URL.'}, 'share_to_story': {'type': 'boolean', 'description': "Reels only: after publishing, the platform also shares the same 9:16 video to the channel's Story automatically (no separate story submission needed). Best effort — a story failure never fails the published reel; see story_post_id / story_error on the record."}, 'idempotency_key': {'type': 'string', 'maxLength': 100}}, 'additionalProperties': False}
trends_interest_over_time
Trends interest over time
Get search interest over time for a keyword from Google Trends (12 months default). Returns a time series of relative search interest (0-100) showing how popular a keyword is over time. Great for seasonality analysis, trend detection, and comparing keyword popularity across periods. Optionally filter by country and custom timeframe. Works without a connection via scraping fallback, but SerpAPI key gives structured data.
Read only
Input schema
{'type': 'object', 'required': ['keyword'], 'properties': {'geo': {'type': 'string', 'description': 'Country code to filter by (e.g. "US", "EE", "GB"). Leave empty for worldwide.'}, 'keyword': {'type': 'string', 'description': 'Keyword to analyze (e.g. "digital marketing")'}, 'timeframe': {'type': 'string', 'description': 'Time range (e.g. "today 12-m", "today 3-m", "today 5-y", "2023-01-01 2023-12-31"). Default: "today 12-m"'}}, 'additionalProperties': False}
trends_related_queries
Trends related queries
Get related queries for a keyword from Google Trends — both "rising" (breakout/surging) and "top" (most popular) related searches. Discover what people also search for alongside your keyword. Essential for content ideation, finding long-tail keywords, and understanding user intent around a topic. Works without a connection via scraping fallback.
Read only
Input schema
{'type': 'object', 'required': ['keyword'], 'properties': {'geo': {'type': 'string', 'description': 'Country code to filter by (e.g. "US", "EE"). Leave empty for worldwide.'}, 'keyword': {'type': 'string', 'description': 'Keyword to find related queries for (e.g. "SEO tools")'}}, 'additionalProperties': False}
trends_trending_searches
Trends trending searches
Get real-time trending searches in a country from Google Trends. Find viral topics, breaking news keywords, and currently surging search terms. Useful for newsjacking, real-time content marketing, and spotting opportunities to create timely content that rides trending waves. Defaults to US if no country specified.
Read only
Input schema
{'type': 'object', 'required': [], 'properties': {'geo': {'type': 'string', 'description': 'Country code (e.g. "US", "EE", "GB", "DE"). Default: "US"'}}, 'additionalProperties': False}
trustpilot_find_business
Trustpilot find business
Find a business on Trustpilot by domain name. Returns the business unit ID, TrustScore (1-5), total review count, star distribution, and display name. Use the returned business unit ID for subsequent trustpilot_get_reviews or trustpilot_get_profile calls. Essential for competitor reputation monitoring or auditing your own brand presence on Trustpilot.
Read only
Input schema
{'type': 'object', 'required': ['domain'], 'properties': {'domain': {'type': 'string', 'description': 'Business domain to search for (e.g. "example.com")'}}, 'additionalProperties': False}
trustpilot_get_profile
Trustpilot get profile
Get the full business profile from Trustpilot including TrustScore, star rating, total review count, business categories, website URL, response rate to reviews, and claimed status. Provides a comprehensive overview of a company's Trustpilot reputation. Requires a business unit ID from trustpilot_find_business.
Read only
Input schema
{'type': 'object', 'required': ['business_unit_id'], 'properties': {'business_unit_id': {'type': 'string', 'description': 'Trustpilot business unit ID (from trustpilot_find_business)'}}, 'additionalProperties': False}
trustpilot_get_reviews
Trustpilot get reviews
Get recent reviews for a business on Trustpilot. Returns individual reviews with star rating (1-5), review title, full text, date created, reviewer display name, and language. Requires a business unit ID from trustpilot_find_business. Use to analyze customer sentiment, identify recurring complaints, or monitor review trends over time.
Read only
Input schema
{'type': 'object', 'required': ['business_unit_id'], 'properties': {'limit': {'type': 'integer', 'default': 20, 'description': 'Number of reviews to return (default 20)'}, 'business_unit_id': {'type': 'string', 'description': 'Trustpilot business unit ID (from trustpilot_find_business)'}}, 'additionalProperties': False}
trustpilot_reply_review
Trustpilot reply review
Reply to a specific Trustpilot review on behalf of the business. Requires OAuth business account authentication (api_key, api_secret, username, password in connection credentials). Use to respond to customer feedback, address complaints publicly, or thank customers for positive reviews. The reply will appear publicly on the Trustpilot review page.
Destructive
Input schema
{'type': 'object', 'required': ['review_id', 'message'], 'properties': {'message': {'type': 'string', 'description': 'Reply message text'}, 'review_id': {'type': 'string', 'description': 'ID of the review to reply to'}}, 'additionalProperties': False}
ubersuggest_domain
Ubersuggest domain
Get a domain overview from Ubersuggest — estimated monthly organic traffic, domain authority score, total backlinks, top organic keywords, and top pages by traffic. Great for competitive analysis, benchmarking your site against competitors, and finding content gaps. Works without a connection via scraping fallback.
Read only
Input schema
{'type': 'object', 'required': ['domain'], 'properties': {'domain': {'type': 'string', 'description': 'Domain to analyze (e.g. "example.com", without https://)'}}, 'additionalProperties': False}
ubersuggest_keywords
Ubersuggest keywords
Get keyword suggestions from Ubersuggest (Neil Patel's tool) with search volume, SEO difficulty score, paid difficulty, and CPC estimates. Provides a broader set of keyword ideas including questions, prepositions, and comparisons. Works without a connection via scraping fallback, but an API key gives structured data. Good complement to Google Keyword Planner.
Read only
Input schema
{'type': 'object', 'required': ['keyword'], 'properties': {'country': {'type': 'string', 'description': 'Country code in lowercase (e.g. "us", "ee", "gb"). Default: "us"'}, 'keyword': {'type': 'string', 'description': 'Seed keyword to get suggestions for (e.g. "content marketing")'}, 'language': {'type': 'string', 'description': 'Ignored compatibility field. Ubersuggest targeting is controlled by country.'}}, 'additionalProperties': False}
update_ad_creative
Update ad creative
Confirm what you did in Meta for an AI osakond ad creative: status=running (launched or relaunched — only after the client approved it; a new version going live retires the one it replaces), status=paused (you paused it in Meta), status=rejected (Meta rejected it, or it will not run — say why in the chat). Also: external_ad_id (the Meta ad id), text_synced=true (the client's text is live in Meta), result {leads, cpl, spend} for the row. Approval itself is always the client's.
Input schema
{'type': 'object', 'required': ['id'], 'properties': {'id': {'type': 'integer'}, 'token': {'type': 'string', 'description': 'Dashboard public_token. Optional — defaults to your own dashboard.'}, 'result': {'type': 'object', 'properties': {'cpl': {'type': 'number'}, 'leads': {'type': 'number'}, 'spend': {'type': 'number'}}}, 'status': {'enum': ['running', 'paused', 'rejected'], 'type': 'string'}, 'text_synced': {'type': 'boolean'}, 'external_ad_id': {'type': 'string'}}, 'additionalProperties': False}
update_client_request
Update client request
Move a client request along on the AI osakond dashboard: status (agent_working | in_plan | needs_client_approval | done | declined — needs_growth_lead only the growth lead clears), kind (event | campaign | event_campaign) and status_note (one line the client sees under the row, e.g. "4 postitust sisuplaanis").
Input schema
{'type': 'object', 'required': ['request_id'], 'properties': {'kind': {'enum': ['event', 'campaign', 'event_campaign'], 'type': 'string'}, 'token': {'type': 'string', 'description': 'Dashboard public_token. Optional — defaults to your own dashboard.'}, 'status': {'enum': ['agent_working', 'in_plan', 'needs_client_approval', 'done', 'declined'], 'type': 'string'}, 'request_id': {'type': 'integer'}, 'status_note': {'type': 'string'}}, 'additionalProperties': False}
update_dashboard
Update dashboard
Partially update an existing dashboard by token. Supports changing name/description/dates/password, adding new widgets, removing widgets by position, and updating existing widget content (e.g. refresh a marketing plan).
Input schema
{'type': 'object', 'required': ['token'], 'properties': {'name': {'type': 'string'}, 'token': {'type': 'string'}, 'markets': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Countries for the market picker of the client view, ISO-3166-1 alpha-3 (e.g. ["est","fin"]). Empty array removes the picker.'}, 'password': {'type': ['string', 'null'], 'description': 'Set a new viewer password (plaintext, will be bcrypt-hashed). Pass null to remove protection. Omit this field to leave the existing password unchanged.'}, 'expires_at': {'type': ['string', 'null'], 'format': 'date-time'}, 'add_widgets': {'type': 'array', 'description': 'New widgets to append. Same shape as widgets in create_dashboard.'}, 'client_view': {'enum': ['seo', 'team', 'grid'], 'type': 'string', 'description': 'Switch the page the client sees: "seo" (AI agent · SEO/GEO client view), "team" (AI tiim: SEO + paid ads on one page) or "grid" (classic widgets). See create_dashboard.'}, 'description': {'type': 'string'}, 'update_widgets': {'type': 'array', 'description': 'Widgets to mutate by position — e.g. [{"position": 2, "content": "## New plan"}]. For strategy_card widgets, pass {"source":{"mode":"human_controlled"}} or {"source":{"mode":"ai_controlled"}} to change card mode without replacing tasks.'}, 'default_end_date': {'type': 'string', 'format': 'date'}, 'default_date_range': {'type': 'string'}, 'default_start_date': {'type': 'string', 'format': 'date'}, 'remove_widget_positions': {'type': 'array', 'items': {'type': 'integer'}, 'description': 'Position numbers of widgets to delete'}}, 'additionalProperties': False}
update_drive_file
Update drive file
Overwrite the content of an existing Drive file (regular files like txt/csv/json — not native Google Docs/Sheets). Returns bytes_written and web_view_link. Requires a connected google_drive integration.
Destructive
Input schema
{'type': 'object', 'required': ['file_id', 'content'], 'properties': {'content': {'type': 'string', 'description': 'New full content.'}, 'file_id': {'type': 'string', 'description': 'Drive file id to overwrite.'}, 'mime_type': {'type': 'string', 'description': 'Optional MIME type.'}}, 'additionalProperties': False}
update_gbp_profile
Update gbp profile
Change the business description and/or the regular opening hours of the connected Google Business Profile (Business Information API PATCH with an explicit updateMask: only the fields you pass, and only those that differ from what is live). description is at most 750 characters; regular_hours replaces the whole weekly schedule — one entry per open stretch, days you leave out show as closed, close_day defaults to open_day (or the next day when close_time is earlier) and 24:00 closes at midnight.
Destructive
Input schema
{'type': 'object', 'properties': {'description': {'type': 'string', 'description': 'The "from the business" description, plain text, at most 750 characters.'}, 'regular_hours': {'type': 'array', 'items': {'type': 'object', 'required': ['open_day', 'open_time', 'close_time'], 'properties': {'open_day': {'enum': ['MONDAY', 'TUESDAY', 'WEDNESDAY', 'THURSDAY', 'FRIDAY', 'SATURDAY', 'SUNDAY'], 'type': 'string'}, 'close_day': {'enum': ['MONDAY', 'TUESDAY', 'WEDNESDAY', 'THURSDAY', 'FRIDAY', 'SATURDAY', 'SUNDAY'], 'type': 'string'}, 'open_time': {'type': 'string', 'description': 'HH:MM, 24-hour clock.'}, 'close_time': {'type': 'string', 'description': 'HH:MM, 24-hour clock.'}}, 'additionalProperties': False}, 'description': 'The full weekly schedule, e.g. [{"open_day":"MONDAY","open_time":"09:00","close_time":"17:00"}].'}}, 'additionalProperties': False}
update_google_ads_rsa
Update Google ads RSA
Change the texts of one responsive search ad IN PLACE (AdService ads:mutate): headlines, descriptions and/or the final URL. The ad keeps its id and history, but Google reviews it again and its learning partly restarts, so change texts deliberately, not daily. headlines: 3..15, each at most 30 characters, no duplicates; descriptions: 2..4, each at most 90 characters. Send the FULL new list of what you change — it replaces the old list. Pins: pass `pinned` to say which text is fixed to which position; without `pinned`, a headline or description whose text stays the same keeps its old pin. Validated before anything is sent (rsa_text_too_long names the offending items). Identical texts are a no-op (changed=false, no card). Goes through the approval gate — the card shows the old and new texts side by side — unless the Autonomy row "Reklaam › Reklaamitekstid" is on autopilot. ad_id comes from list_google_ads_ads.
Destructive
Input schema
{'type': 'object', 'required': ['ad_id'], 'properties': {'ad_id': {'type': 'string', 'description': 'The ad id from list_google_ads_ads (digits).'}, 'pinned': {'type': 'object', 'properties': {'HEADLINE_1': {'type': 'string'}, 'HEADLINE_2': {'type': 'string'}, 'HEADLINE_3': {'type': 'string'}, 'DESCRIPTION_1': {'type': 'string'}, 'DESCRIPTION_2': {'type': 'string'}}, 'description': 'Optional pins: position => the exact text to fix there. Giving it replaces all pins of the lists you send; {} removes them.', 'additionalProperties': False}, 'reason': {'type': 'string', 'description': 'Optional one sentence for the approval card: why the texts change.'}, 'final_url': {'type': 'string', 'description': 'The new landing page, a full https:// URL.'}, 'headlines': {'type': 'array', 'items': {'type': 'string'}, 'description': 'The complete new headline list, 3..15 texts of at most 30 characters each.'}, 'descriptions': {'type': 'array', 'items': {'type': 'string'}, 'description': 'The complete new description list, 2..4 texts of at most 90 characters each.'}}, 'additionalProperties': False}
update_gtm_tag
Update GTM tag
Edit an existing tag in the GTM WORKSPACE by tag_id (from list_gtm_tags): rename it, change or add parameters (merged by key, the rest is kept), replace firing_trigger_ids, or pause/unpause it with paused. Fields left out stay as they are. Not live until the human publishes the version in GTM.
Destructive
Input schema
{'type': 'object', 'required': ['tag_id'], 'properties': {'name': {'type': 'string', 'description': 'New tag name'}, 'notes': {'type': 'string', 'description': 'Replace the note shown in GTM'}, 'paused': {'type': 'boolean', 'description': 'true pauses the tag (it stays in the container but never fires), false resumes it'}, 'tag_id': {'type': ['string', 'integer'], 'description': 'Tag id from list_gtm_tags'}, 'parameters': {'type': 'object', 'description': 'Parameters to set, same keys as create_gtm_tag (e.g. eventName, measurementId, eventParameters, html). Merged by key into the existing parameters.'}, 'firing_trigger_ids': {'type': 'array', 'items': {'type': ['string', 'integer']}, 'description': 'Replaces the firing trigger list (at least one id)'}, 'blocking_trigger_ids': {'type': 'array', 'items': {'type': ['string', 'integer']}, 'description': 'Replaces the exception trigger list; pass [] to clear'}}, 'additionalProperties': False}
update_merchant_products
Update merchant products
Fix product data in Google Merchant Center through a supplemental API data source named "SharksAPI parandused": only the attributes you send are overridden, the client's own feed stays untouched and one delete of the source undoes everything. Creates that supplemental source and links it to the primary source on first use. Allowed attributes: title, description, brand, gtins, mpn, identifierExists, googleProductCategory, productTypes, color, size, material, pattern, ageGroup, gender, condition, productHighlights, customLabel0, customLabel1, customLabel2, customLabel3, customLabel4. Never invent GTINs or specs — take them from the catalog or the product page. Goes through the Postkast approval; Google reprocesses products within minutes to hours.
Destructive
Input schema
{'type': 'object', 'required': ['products'], 'properties': {'reason': {'type': 'string'}, 'products': {'type': 'array', 'items': {'type': 'object', 'required': ['offer_id', 'content_language', 'feed_label', 'attributes'], 'properties': {'offer_id': {'type': 'string'}, 'attributes': {'type': 'object', 'description': 'camelCase Merchant attributes, e.g. {"title":"…","gtins":["4740000000001"],"customLabel0":"winner"}.'}, 'feed_label': {'type': 'string', 'description': 'e.g. "EE"'}, 'content_language': {'type': 'string', 'description': 'e.g. "et"'}}}, 'maxItems': 200, 'minItems': 1}, 'primary_data_source_id': {'type': 'string', 'description': 'Primary source the corrections apply to (default: the only / first primary product source).'}}, 'additionalProperties': False}
update_plan_activity
Update plan activity
Update a plan activity — change its title, months, date, channel, linked draft, notes or task_ref. If task_ref is linked, status becomes derived from the strategy task; manual status updates are blocked until task_ref is cleared with null.
Input schema
{'type': 'object', 'required': ['activity_id'], 'properties': {'date': {'type': 'string'}, 'notes': {'type': 'string'}, 'title': {'type': 'string'}, 'months': {'type': 'array', 'items': {'type': 'integer'}}, 'status': {'enum': ['planned', 'in_progress', 'done'], 'type': 'string'}, 'channel': {'type': 'string'}, 'task_ref': {'type': ['object', 'null'], 'required': ['token', 'widget_id', 'task_id'], 'properties': {'token': {'type': 'string', 'description': 'Child dashboard public_token where the strategy card lives.'}, 'task_id': {'type': 'integer', 'description': 'Task id on that strategy card.'}, 'widget_id': {'type': 'integer', 'description': 'Strategy-card widget_id.'}}, 'description': 'Link this activity to a strategy-card task. When set, activity status is derived from that task. Pass null to unlink and make status manual again.'}, 'activity_id': {'type': 'integer'}, 'content_draft_id': {'type': 'integer'}}, 'additionalProperties': False}
update_plan_document
Update plan document
Create or replace the marketing-plan DOCUMENT (full markdown). This is the dynamic plan the human also edits on the /plan page. CONTRACT: whenever the document changes, the manager (Turundusjuht) must re-align subagent tasks with the new plan (delegate_to_agents / manage_strategy_card / update_strategy_task / add_plan_activity) and then call mark_plan_tasks_synced. If you are the manager and sync tasks in the same run, pass mark_synced=true. Otherwise the plan is flagged "tasks not synced" on the dashboard and a team-memory reminder is written for the manager's next run. Anonymous marketing content only — no personal data.
Input schema
{'type': 'object', 'required': ['document'], 'properties': {'document': {'type': 'string', 'description': 'The full plan document as markdown (replaces the previous version, max ~200k chars).'}, 'mark_synced': {'type': 'boolean', 'description': 'Pass true only when subagent tasks are ALREADY re-aligned with this version in the same run (manager doing both at once).'}, 'manager_token': {'type': 'string', 'description': "Manager dashboard token (optional; defaults to the project's manager dashboard)."}}, 'additionalProperties': False}
update_seo_dashboard
Update SEO dashboard
Write ONE section of the SEO client view. Sections: hero, goal, meeting, growth_comment, channels, money, social, meta_creatives, highlights, next, keywords, gsc_queries, striking, gsc_pages, ai_visibility, competitors, ga4_channels, ga4_kpis, pagespeed, backlinks, markets, google_ads, meta_ads, worklog, footer, trends. Dashboards with a market filter (get_seo_dashboard → markets, e.g. est + fin) show a market switch to the client: pass market="fin" to write the FINNISH version of a section (Finnish keywords, Finnish AI questions, Finnish results with their own KPI numbers) — it replaces the site-wide section only while the client has Finland selected; without market you write the site-wide version. Replace semantics: the section becomes exactly `data` (pass delete=true to remove it and fall back to the server/task data). The page is in the client's language and words: plain Estonian, one number the client feels, no jargon (the page explains SEO terms itself). Typical monthly routine: hero (headline + caveat), goal (quarter target), highlights (3–4 results with a number each), next (3–5 upcoming things), keywords (fixed 4–8 terms for the rank chart + top10 in/total), ai_visibility (your fixed AI question set checked in ChatGPT / Claude / Google AI Mode / AI Overview — never Perplexity — + why-not reasons), backlinks (Ahrefs numbers), competitors (only if you do not maintain a competitor_watch widget). Search Console / GA4 / PageSpeed blocks are filled by the server — only override them (gsc_queries, gsc_pages, ga4_channels, ga4_kpis, pagespeed) when the connection is missing. Validation errors name the key and the expected shape; get_seo_dashboard returns the full schema.
Input schema
{'type': 'object', 'required': ['section'], 'properties': {'data': {'type': 'object', 'description': 'The section payload (see get_seo_dashboard → schema[section]).', 'additionalProperties': True}, 'token': {'type': 'string', 'description': 'Dashboard public_token. Omit for your own dashboard.'}, 'delete': {'type': 'boolean', 'default': False, 'description': 'Remove the section instead of writing it.'}, 'domain': {'type': 'string', 'description': 'Host of one of the dashboard\'s domains (get_seo_dashboard → domains, e.g. "kookjakodu.fi") to write the version shown when the client picks that domain. Combine with market for one domain × country pair. Lookup on the page: market+domain → domain → market → site-wide.'}, 'market': {'type': 'string', 'description': 'ISO-3166-1 alpha-3 of one of the dashboard\'s markets (e.g. "fin") to write the market-specific version. Omit for the site-wide section.'}, 'section': {'enum': ['hero', 'goal', 'meeting', 'growth_comment', 'channels', 'money', 'social', 'meta_creatives', 'highlights', 'next', 'keywords', 'gsc_queries', 'striking', 'gsc_pages', 'ai_visibility', 'competitors', 'ga4_channels', 'ga4_kpis', 'pagespeed', 'backlinks', 'markets', 'google_ads', 'meta_ads', 'worklog', 'footer', 'trends'], 'type': 'string', 'description': 'Which section to write.'}}, 'additionalProperties': False}
update_sheet
Update sheet
Write (overwrite) values into a Google Sheet range. values is a 2D array of rows, e.g. [["Name","Email"],["Mari","mari@x.ee"]]. Uses USER_ENTERED so formulas/dates are parsed. Requires a connected google_sheets integration.
Destructive
Input schema
{'type': 'object', 'required': ['spreadsheet_id', 'range', 'values'], 'properties': {'range': {'type': 'string', 'description': 'A1 range where the top-left cell anchors the write, e.g. "Sheet1!A1".'}, 'values': {'type': 'array', 'items': {'type': 'array', 'items': {'type': ['string', 'number', 'boolean', 'null']}}, 'description': '2D array of rows.'}, 'spreadsheet_id': {'type': 'string'}}, 'additionalProperties': False}
update_strategy_task
Update strategy task
Toggle a task on a strategy card — mark as completed or pending. Use this when the AI agent has finished executing a task (e.g. updated a meta description, submitted a re-index request). Agents may update any strategy task they can access, including human-controlled tasks; completed tasks are recorded with completed_by=ai. Use get_strategy_status to see each task's task_mode/effective_mode for coordination. Returns the updated task state. Optionally set note (free text) and label (one of: blocked, needs_human, needs_access, in_progress) to annotate task state. Identify the task by task_id (DB id — the "#id" shown on the dashboard) OR task_number (1-indexed order from get_strategy_status). task_id takes precedence if both are supplied.
Input schema
{'type': 'object', 'required': ['token', 'widget_id'], 'properties': {'note': {'type': ['string', 'null'], 'description': 'Optional free-text note explaining task state (e.g. why blocked, what is missing). Pass null or omit to leave unchanged.'}, 'label': {'enum': [None, 'blocked', 'needs_human', 'needs_access', 'in_progress'], 'type': ['string', 'null'], 'description': 'Optional state label. in_progress = you are on it. blocked = something stops you (note required: what). needs_human / needs_access put the task on the manager\'s "Postkast" queue (/inbox) — note (start with VAJA: …) AND human_reason are required, and the label is refused when a platform tool already covers the ask (WordPress pages/redirects/seo/schema, submit_social_post, send_email): call the tool instead. The CLIENT\'s own page ("Sinult on vaja") shows only what nobody but the client can give: needs_access (their credential / owner grant) and asks you address to them with "VAJA: KLIENT: …" (their prices, their choice, their file). decision / manual_ui / no_api go to the Marketing Sharks team (Postkast), not the client; "VAJA: TIIM: …" keeps a task internal regardless. One open ask per topic: update the existing task instead of adding a duplicate. Pass null to clear.'}, 'token': {'type': 'string', 'description': 'Dashboard public_token'}, 'task_id': {'type': 'integer', 'description': 'Task ID within the strategy card. Either task_id or task_number is required. task_id takes precedence if both are supplied.'}, 'widget_id': {'type': 'integer', 'description': 'Strategy card widget ID'}, 'is_skipped': {'type': 'boolean', 'description': 'Read-only compatibility field from get_strategy_status. false is ignored; true is rejected because only a human can deactivate/skip a task from the dashboard UI.'}, 'task_number': {'type': 'integer', 'description': 'Alternative to task_id: 1-indexed order of the task within the strategy card (as shown in get_strategy_status output). NB: the dashboard shows the DB id ("#1877" = task_id 1877), not the order — prefer task_id. Either task_id or task_number is required.'}, 'completed_at': {'type': ['string', 'null'], 'description': 'Read-only compatibility field from get_strategy_status. Ignored on write; timestamps are set by the platform.'}, 'completed_by': {'type': ['string', 'null'], 'description': 'Read-only compatibility field from get_strategy_status. Ignored on write; completed tasks are recorded as completed_by=ai by the platform.'}, 'human_reason': {'enum': [None, 'decision', 'access', 'no_api', 'manual_ui'], 'type': ['string', 'null'], 'description': 'Required with needs_human / needs_access. decision = manager must decide (budget, go/no-go). access = credential, OAuth click or permission you lack. no_api = the platform has no tool for this action. manual_ui = must be done by hand in a third-party UI (Google Ads, GTM, hosting panel, ssh).'}, 'is_completed': {'type': 'boolean', 'description': 'true to mark done, false to reopen. Omit to leave completion state unchanged (note/label-only update).'}}, 'additionalProperties': False}
update_wp_page
Update WordPress page
Update a WordPress service/landing PAGE: title, content (full HTML — send the complete body, it replaces the old one), excerpt, slug or status. This is how CTR fixes on service pages get done without wp-admin. Pass only the fields you are changing.
Destructive
Input schema
{'type': 'object', 'required': ['page_id'], 'properties': {'slug': {'type': 'string', 'description': 'URL slug. Changing it breaks old links — pair with create_wp_redirect.'}, 'title': {'type': 'string', 'description': 'Page H1/title.'}, 'status': {'type': 'string', 'description': 'publish | draft | pending | private.'}, 'content': {'type': 'string', 'description': 'Full HTML body — replaces the existing content.'}, 'excerpt': {'type': 'string'}, 'page_id': {'type': 'integer'}}, 'additionalProperties': False}
update_wp_post
Update WordPress post
Update an existing WordPress post by ID. Can modify title, content, status, excerpt, categories, tags, featured image, and SEO meta description. Only include fields you want to change. meta_description is saved to Rank Math right after the post, the way update_wp_seo_meta saves it; meta_description.saved in the result says whether it was stored. Use when the user wants to "edit a post", "update the blog", or "change post status to published."
Destructive
Input schema
{'type': 'object', 'required': ['post_id'], 'properties': {'meta': {'type': 'object', 'description': 'Registered post meta as key → value, e.g. {"header_image": 168145} sets the ACF hero image ("Posti pildid") on marketingsharks.ee. A key the site has not exposed to the REST API fails with wp_meta_not_registered instead of being dropped.', 'additionalProperties': True}, 'tags': {'type': 'array', 'items': {'type': 'integer'}}, 'title': {'type': 'string'}, 'author': {'type': 'string', 'description': 'Change the post author: WordPress user ID, login, email or display name.'}, 'status': {'enum': ['publish', 'draft', 'pending', 'private'], 'type': 'string'}, 'content': {'type': 'string'}, 'excerpt': {'type': 'string'}, 'post_id': {'type': 'integer', 'description': 'WordPress post ID'}, 'tag_names': {'type': 'array', 'items': {'type': 'string'}, 'description': "Tag names instead of IDs (replaces the post's tags; missing tags are created)."}, 'categories': {'type': 'array', 'items': {'type': 'integer'}}, 'category_names': {'type': 'array', 'items': {'type': 'string'}, 'description': "Category names/slugs instead of IDs (replaces the post's categories)."}, 'featured_media': {'type': 'integer'}, 'meta_description': {'type': 'string', 'description': 'SEO meta description shown in Google (max ~155 chars). Stored in Rank Math (rank_math_description) once the post is updated; check meta_description.saved in the result.'}}, 'additionalProperties': False}
update_wp_schema
Update WordPress schema
Set structured data (Rank Math schema) on a post or page — Article, FAQPage, Service, HowTo etc. Pass the schema map exactly as Rank Math stores it. Use to fill Article+FAQPage gaps found in a GEO/SEO audit.
Destructive
Input schema
{'type': 'object', 'required': ['object_id', 'schemas'], 'properties': {'schemas': {'type': 'object', 'description': 'Rank Math schema map, e.g. {"schema-1":{"@type":"FAQPage","mainEntity":[...]}}.'}, 'object_id': {'type': 'integer'}}, 'additionalProperties': False}
update_wp_seo_meta
Update WordPress SEO Meta
Set Rank Math SEO fields for a post or page: SEO title, meta description, focus keyword (rank_math_focus_keyword), canonical URL, robots, and the Open Graph / social share image. This is the CTR lever: rewrite the search-result title and description without touching the page content. Keep seo_title <= 60 chars and meta_description <= 155 chars. Use this right after create_wp_post to set the Rank Math focus keyword.
Destructive
Input schema
{'type': 'object', 'required': ['object_id'], 'properties': {'type': {'type': 'string', 'description': 'Accepted for compatibility with get_wp_seo_meta: posts/post or pages/page.'}, 'robots': {'type': 'array', 'items': {'type': 'string'}, 'description': 'e.g. ["index","follow"] or ["noindex"].'}, 'og_image': {'type': 'string', 'description': 'Absolute URL of the Open Graph / Facebook share image (Rank Math "Facebook image"; Twitter uses it too by default). Pass a media library URL, e.g. the featured image URL.'}, 'object_id': {'type': 'integer', 'description': 'Post or page ID.'}, 'seo_title': {'type': 'string', 'description': 'Title shown in Google (max ~60 chars).'}, 'og_image_id': {'type': 'integer', 'description': 'Media library attachment ID of og_image, when known (lets Rank Math pick the right size).'}, 'canonical_url': {'type': 'string', 'description': 'Absolute URL — use when two pages compete for the same query.'}, 'focus_keyword': {'type': 'string', 'description': 'Rank Math focus keyword(s); separate several with commas, primary first.'}, 'meta_description': {'type': 'string', 'description': 'Description shown in Google (max ~155 chars).'}}, 'additionalProperties': False}
upload_gbp_photo
Upload gbp photo
Add a photo to the connected Google Business Profile from a public image URL that Google downloads (v4 media, mediaFormat PHOTO). category decides where it shows: COVER, PROFILE, LOGO, EXTERIOR, INTERIOR, PRODUCT, AT_WORK, FOOD_AND_DRINK, MENU, COMMON_AREA, ROOMS, TEAMS or ADDITIONAL (default); a COVER or PROFILE photo replaces the current one. Google needs at least 250 px on the short edge and 10 KB.
Destructive
Input schema
{'type': 'object', 'required': ['photo_url'], 'properties': {'category': {'enum': ['COVER', 'PROFILE', 'LOGO', 'EXTERIOR', 'INTERIOR', 'PRODUCT', 'AT_WORK', 'FOOD_AND_DRINK', 'MENU', 'COMMON_AREA', 'ROOMS', 'TEAMS', 'ADDITIONAL'], 'type': 'string', 'description': 'Default ADDITIONAL.'}, 'photo_url': {'type': 'string', 'description': 'Public http(s) URL of a JPG or PNG image.'}}, 'additionalProperties': False}
upload_offline_conversions
Upload offline conversions
Send CRM outcomes (qualified lead, meeting held, won deal with value) to a Google Ads import conversion action through Google's Data Manager API, so Smart Bidding learns from real sales instead of form fills. Each row needs a click id (gclid / gbraid / wbraid) and/or the customer's e-mail or phone — e-mail and phone are normalised and SHA-256 hashed on the server before sending. The same transaction_id sent again with a new value is treated by Google as an adjustment, not a duplicate. Consent (EU DMA) must be stated. Use validate_only first; the real upload goes through the Postkast approval. Needs the google_data_manager connection and an UPLOAD_CLICKS action (create_google_ads_offline_conversion_action).
Destructive
Input schema
{'type': 'object', 'required': ['conversion_action_id', 'rows', 'consent'], 'properties': {'rows': {'type': 'array', 'items': {'type': 'object', 'required': ['conversion_time'], 'properties': {'email': {'type': 'string', 'description': 'Raw or already SHA-256 hex.'}, 'gclid': {'type': 'string'}, 'phone': {'type': 'string', 'description': 'E.164 (+3725…) raw or SHA-256 hex.'}, 'value': {'type': 'number'}, 'gbraid': {'type': 'string'}, 'wbraid': {'type': 'string'}, 'consent': {'enum': ['granted', 'denied', 'unspecified'], 'type': 'string'}, 'transaction_id': {'type': 'string', 'description': 'CRM deal/lead id — dedupe key and adjustment key.'}, 'conversion_time': {'type': 'string', 'description': 'When the outcome happened, ISO 8601 with offset, e.g. 2026-09-20T14:05:00+03:00.'}}}, 'maxItems': 2000, 'minItems': 1}, 'consent': {'enum': ['granted', 'denied', 'unspecified'], 'type': 'string', 'description': 'Ad user data + ad personalization consent for the whole batch (row "consent" overrides). For EU users send "granted" only when the CRM holds that consent.'}, 'currency': {'type': 'string', 'description': 'ISO 4217, default EUR.'}, 'validate_only': {'type': 'boolean', 'description': 'Google validates the batch and stores nothing.'}, 'conversion_action_id': {'type': 'string', 'description': 'Google Ads conversion action id (type UPLOAD_CLICKS).'}}, 'additionalProperties': False}
upload_wp_media
Upload WordPress media
Upload an image to the WordPress media library from a public URL or a base64 payload and set its alt text, title and caption. Returns the attachment ID plus source_url, width and height — use the ID as featured_media, as meta.header_image (article hero) or as og_image_id in update_wp_seo_meta. Replaces uploading through wp-admin for blog hero, featured and social share images. Images only, max 10 MB.
Input schema
{'type': 'object', 'properties': {'url': {'type': 'string', 'description': 'Public http(s) URL of the image to fetch. Either url or file_base64 is required.'}, 'title': {'type': 'string', 'description': 'Media title shown in the library.'}, 'caption': {'type': 'string'}, 'alt_text': {'type': 'string', 'description': 'Alt text (accessibility + SEO).'}, 'filename': {'type': 'string', 'description': 'File name in the media library, e.g. "kodulehe-rentimine-fb.png". Defaults to the URL basename; the extension follows the detected image type.'}, 'file_base64': {'type': 'string', 'description': 'Base64-encoded image bytes; a data:image/...;base64, prefix is accepted. Either url or file_base64 is required.'}}, 'additionalProperties': False}
validate_schema_type
Validate schema type
Validate a specific Schema.org type (e.g. Product, Article, FAQPage, LocalBusiness) on a webpage. Checks if the schema exists, scores completeness by checking required and recommended fields, and provides a ready-to-use JSON-LD example if the schema is missing. Use when asked "do we have Product schema?" or "is our FAQ markup correct?" or "add LocalBusiness schema."
Read only
Input schema
{'type': 'object', 'required': ['url', 'schema_type'], 'properties': {'url': {'type': 'string', 'description': 'URL of the page to validate'}, 'schema_type': {'type': 'string', 'description': 'Schema.org type to validate (e.g. Article, Product, FAQPage, LocalBusiness, Organization, BreadcrumbList, Event, Recipe, VideoObject, JobPosting, HowTo, Course)'}}, 'additionalProperties': False}
write_site_file
Write site file
Replace (or create) one theme or mu-plugin file on the client website — for technical fixes such as removing duplicate stylesheet enqueues, deferring scripts, preloading the LCP image. Send the COMPLETE new file content. Safety is built in: the previous version is backed up, PHP is syntax-checked before upload, the file is hash-verified, and if the home page then shows a 5xx or PHP fatal the change is rolled back automatically. Goes through the approval gate unless the "Arendaja › Teema- ja pluginafailide muutmine" autonomy row is on autopilot. Always read_site_file first and pass expected_sha256; creating a new file needs no sha. Only files under wp-content/themes/ or wp-content/mu-plugins/ of the WordPress root (php, css, js, json, html, txt, svg, xml, max 512 KB). wp-config.php, .htaccess, uploads and plugins are out of reach by design.
Destructive
Input schema
{'type': 'object', 'required': ['path', 'content', 'note'], 'properties': {'note': {'type': 'string', 'description': 'One line: what this change does and why (shown to the manager and kept with the backup).'}, 'path': {'type': 'string', 'description': 'File relative to the WordPress root.'}, 'content': {'type': 'string', 'description': 'The complete new file content.'}, 'expected_sha256': {'type': 'string', 'description': 'sha256 from read_site_file. Required when the file already exists; the write is refused if the live file changed since.'}}, 'additionalProperties': False}
Added
search_meta_ad_library
Oct. 2, 2026, 2:40 a.m.
Added
send_meta_conversion_events
Oct. 2, 2026, 2:40 a.m.
Added
get_meta_signal_health
Oct. 2, 2026, 2:40 a.m.
Added
get_meta_ad_creatives
Oct. 2, 2026, 2:40 a.m.
Added
get_meta_ad_insights
Oct. 2, 2026, 2:40 a.m.
Added
update_merchant_products
Oct. 2, 2026, 2:40 a.m.
Added
list_merchant_data_sources
Oct. 2, 2026, 2:40 a.m.
Added
get_merchant_products
Oct. 2, 2026, 2:40 a.m.
Added
get_data_manager_request_status
Oct. 2, 2026, 2:40 a.m.
Added
upload_offline_conversions
Oct. 2, 2026, 2:40 a.m.
Added
get_offline_conversion_upload_status
Oct. 2, 2026, 2:40 a.m.
Added
create_google_ads_offline_conversion_action
Oct. 2, 2026, 2:40 a.m.
Added
set_google_ads_ai_max_controls
Oct. 2, 2026, 2:40 a.m.
Added
add_google_ads_shared_negatives
Oct. 2, 2026, 2:40 a.m.
Added
get_google_ads_gaql_report
Oct. 2, 2026, 2:40 a.m.
Added
list_google_ads_negative_lists
Oct. 2, 2026, 2:40 a.m.
Added
get_google_ads_pmax_report
Oct. 2, 2026, 2:40 a.m.
Added
get_google_ads_ai_max_report
Oct. 2, 2026, 2:40 a.m.
Added
get_google_ads_search_terms
Oct. 2, 2026, 2:40 a.m.
Added
submit_indexnow
Oct. 2, 2026, 2:40 a.m.
Added
check_url_status
Oct. 2, 2026, 2:40 a.m.
Added
submit_bing_urls
Oct. 2, 2026, 2:40 a.m.
Added
get_bing_backlinks
Oct. 2, 2026, 2:40 a.m.
Added
get_bing_url_info
Oct. 2, 2026, 2:40 a.m.
Added
list_gsc_sitemaps
Oct. 2, 2026, 2:40 a.m.
Added
inspect_gsc_url
Oct. 2, 2026, 2:40 a.m.
Added
list_change_impacts
Oct. 2, 2026, 2:40 a.m.
Added
request_client_photos
Oct. 2, 2026, 2:40 a.m.
Added
list_creative_assets
Oct. 2, 2026, 2:40 a.m.
Added
generate_image
Oct. 2, 2026, 2:40 a.m.