# AXO MCP tool reference > The AXO MCP server lets AI agents operate website personalization end to end. This public reference documents 126 tools; operator and diagnostic tools are available to connected agents at runtime but omitted here. Hosted endpoint: https://axoapp.ai/api/mcp (streamable HTTP). Authenticate with a scoped mcpt_ token minted in the AXO dashboard (Settings → MCP Tokens). Scopes: read < write < admin. ## Analytics & lift Read performance, holdout lift, optimizer state, events, and sessions. ### get_agent_usage `[read]` AI assistant usage: conversations, messages, tokens, estimated cost. ### get_ai_generations `[read]` Read the AI generation history for a content variant — the prompt + guardrails snapshot + provider + model + DAM provenance that produced each piece of AI-generated content on this variant. Use to audit off-brand creative ("why does this image feel wrong?") or to trace why a specific variant looks the way it does. Returns { generations, count } with newest first. Each row carries prompt, response, model, tokens, inferred_cost, guardrails (brand_voice + active_briefs + segment), and dam_provider when the asset was push-through'd to a customer DAM. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `variant_id` | string | yes | content_variants.id to read provenance for. | ### get_analytics `[read]` Get dashboard analytics overview: total sessions, conversions, revenue, segment breakdown, and trend data for the current site. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `days` | number | no | Number of days to look back (default: 30) | ### get_backtest `[read]` Get backtest results showing segment performance, variant impact, conversion rates, and revenue attribution. Use this to evaluate how well personalization is working. ### get_events `[read]` Get recent site events: pageviews, clicks, conversions, custom events. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `limit` | number | no | Max events (default 100) | ### get_form_funnel `[read]` Form conversion funnel analytics: views → starts → submits → abandons, per form and per page, with field-level drop-off. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `window` | "24h" \| "7d" \| "30d" \| "90d" | no | Lookback window (default 30d) | ### get_lift_report `[read]` Get revenue lift analysis showing the incremental impact of personalization vs. control group. ### get_scorecard `[read]` Get the AI Scorecard — the plain-language verdict on whether personalization is beating the 10% holdout control group. Returns status (winning/flat/losing/learning), site-level lift % with statistical significance (z-test p-value), with-AXO vs holdout conversion rates, and a per-segment breakdown. Falls back to a labeled projected lift when live holdout traffic is too thin. Prefer this over get_lift_report for "is the AI working?" questions. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `days` | integer | no | Number of days to look back (default: 30) | ### get_segment_performance `[read]` Performance metrics for a segment: sessions, conversions, rate, revenue, AOV. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `segment_id` | string | yes | Segment ID | ### get_sitemap_health `[read]` Sitemap crawl status, page counts, health metrics. ### get_tag_health `[read]` Tag health: recent beacon count, pageviews, personalizations, render errors, last event. ### get_variant_performance `[read]` Performance metrics for a content variant: impressions, conversions, rate, render errors. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `variant_id` | string | yes | Variant ID | ## Audience & segments Query and build behavioral segments; look up, merge, and link profiles. ### create_segment `[write]` Create a new custom behavioral segment with a name, description, and signal rules. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | yes | Segment name | | `description` | string | no | Behavioral description | | `emoji` | string | no | Emoji icon | | `signal_rules` | object | no | Matching signal rules | ### delete_profile `[admin]` Permanently delete a profile and all associated data (GDPR erasure). Removes identifiers, unlinks sessions, deletes the profile. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `profile_id` | string | yes | Profile UUID to delete | ### export_audience `[write]` Export a segment's audience for a batch email campaign. Returns JSON rows by default; set format:"webhook" to POST them to a URL. For an email blast list set email_only:true — only profiles with a captured email are included (anonymous visitors excluded). Works for behavioral AND custom/affinity segments (auto-detected). include_pii is required to emit emails and is recorded for compliance. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `segment_id` | string | yes | Segment ID to export | | `format` | "json" \| "webhook" | no | Output format (default json) | | `destination` | string | no | Webhook URL (required when format=webhook) | | `email_only` | boolean | no | Only include profiles with an email; produce a campaign-ready email list (implies include_pii) | | `include_pii` | boolean | no | Include the profile email column (opt-in; audited) | | `include_affinities` | boolean | no | Append each profile's top-3 brand affinities | ### generate_audience_clusters `[write]` Manually run K-Means machine-learning clustering against recent behavioral profile activity. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `k` | number | no | Number of clusters to generate | ### get_audience_report `[read]` Get the audience intelligence report with behavioral clusters, engagement tiers, and actionable recommendations. ### get_profile `[read]` Get detailed profile information including timeline, identifiers, CRM attributes, lifetime signals, session history, lead status (lead_captured history), and the opportunities this profile is a contact/lead on. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `profile_id` | string | yes | The profile UUID to look up | ### get_segment_members `[read]` Paginated list of profiles in a segment with their identifiers. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `segment_id` | string | yes | Segment ID | | `limit` | number | no | Max results (default 50) | | `offset` | number | no | Pagination offset | ### get_segments `[read]` List all behavioral segments with session counts, conversion rates, and descriptions. Use this to understand how visitors are being classified. ### get_sessions `[read]` Get recent visitor sessions with behavioral signals, segment assignment, and page URLs. Useful for understanding real-time visitor behavior. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `limit` | number | no | Max results (default: 50) | | `segment` | string | no | Filter by segment ID | ### link_identifier `[write]` Link a new identifier (email, phone, external_id) to a profile. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `profile_id` | string | yes | Profile ID | | `type` | "email" \| "phone" \| "external_id" | yes | Identifier type | | `value` | string | yes | Identifier value | ### list_dedup_candidates `[read]` Find profiles sharing identifiers (merge candidates for deduplication). ### list_leads `[read]` List captured leads (lead_captured events) for this site: contact info, scheduled appointment slot, behavioral segment, and source page. ### merge_profiles `[admin]` Merge two profiles. Moves identifiers, sessions, conversions from source to target, deletes source. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `source_id` | string | yes | Profile to merge FROM (deleted) | | `target_id` | string | yes | Profile to merge INTO (kept) | ### search_profiles `[read]` Search visitor profiles by email, segment, or identification status. Returns profile list with identifiers and session counts. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `search` | string | no | Search by email or identifier value | | `segment` | string | no | Filter by segment ID | | `identified` | "true" \| "false" | no | Filter by identified status | | `limit` | number | no | Max results (default: 50, max: 200) | ### unlink_identifier `[write]` Remove an identifier from a profile. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `profile_id` | string | yes | Profile ID | | `identifier_id` | string | yes | Identifier record ID | ### update_profile `[write]` Update a profile segment override or lifetime signals. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `profile_id` | string | yes | Profile ID | | `segment_id` | string | no | Override segment | | `lifetime_signals` | object | no | Lifetime signal data | ### update_segment `[write]` Update a segment: rename, edit description, change emoji, visibility, or signal rules. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | yes | Segment ID | | `display_name` | string | no | New display name | | `description` | string | no | New description | | `emoji` | string | no | New emoji | | `visible` | boolean | no | Show/hide segment | | `signal_rules` | object | no | New signal rules | ## Placements & personalization Author zones and variants, wire placements, and manage the render surface. ### attach_asset_to_variant `[write]` Attach a library asset to a content variant field — overwrites whatever image was on that field with the asset's blob_url. Also copies the asset's provenance (prompt, brief / reference / planner attribution, tags) into the variant's generated_metadata so the audit trail follows the image. Returns { ok, asset_id, variant_id, blob_url, field_key }. Use after search_assets surfaces an existing asset that matches what the operator wants — saves a generation call. The variant's image_url is also synced to the asset's blob_url so the runtime tag picks it up immediately. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `asset_id` | string | yes | Asset id from search_assets (asset_ shape). | | `variant_id` | string | yes | content_variants.id to attach to. | | `field_key` | string | yes | The payload field key on the variant to overwrite (e.g. "image_url", "hero_image_url"). | | `alt` | string | no | Optional alt text override. When omitted, the variant's existing image_alt is preserved. | ### author_move `[read]` Author a "move object" placement: relocate an EXISTING element on the page to a new location, WITHOUT changing its copy or injecting new content (pure rearrangement). Creates a source zone (element_selector = the element to move) + a move_object content variant whose payload carries the destination anchor + position. Use after a two-pick (the extension / preview picker gives you source_selector + dest_selector). Target ONE segment via segment_id, OR all_visitors:true for everyone (the default — moves are usually global). CAUTION: once published this ships to the live site within ~60s. To preview without persisting on a no-tag site, use the extension demo flow instead. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `page_pattern` | string | yes | URL pattern the move applies to (e.g. "/", "/blog/*") | | `source_selector` | string | yes | CSS selector of the EXISTING element to relocate (the object to move) | | `dest_selector` | string | yes | CSS selector of the destination anchor to move it next to / into | | `position` | "before" \| "after" \| "inside_start" \| "inside_end" | no | Where to place the source relative to the destination. Default "after". ("replace" is intentionally not allowed for a move — it would destroy the destination.) | | `zone_key` | string | no | Zone identifier. Defaults to a generated "move_*" key. | | `display_name` | string | no | Human-readable name for the move. | | `segment_id` | string | no | Audience segment. Omit when all_visitors is true. | | `all_visitors` | boolean | no | Apply to ALL visitors regardless of segment (default true for moves). When false, provide segment_id. | ### clone_trigger_template `[write]` Clone a system or site template into a new site-owned template. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `template_id` | string | yes | Source template ID | | `name` | string | no | Name for the clone | ### configure_product_reco `[write]` Configure a product_reco variant: choose recommendation mode (auto / curated / mixed), retrieval strategy, and pin curated products. Use list_products to find product IDs. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `variant_id` | string | yes | Existing product_reco variant ID | | `source` | "auto" \| "curated" \| "mixed" | yes | auto: Vibe Engine picks all products. curated: only show pinned product_ids. mixed: pinned products first, engine fills the rest. | | `strategy` | "session_behavior" \| "bestsellers" \| "new_arrivals" \| "similar" | no | Engine retrieval strategy (used when source=auto or mixed). Default session_behavior. | | `limit` | integer | no | Max products to render (default 5). | | `category` | string | no | Restrict candidates to this category (case-insensitive exact match). | | `product_ids` | string[] | no | Catalog product IDs to pin. Required when source=curated. Optional when source=mixed. | ### create_campaign `[write]` Create a new campaign with a brief (objective, offer, tone, themes). | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | yes | Campaign name | | `brief` | object | no | Campaign brief | | `status` | "active" \| "draft" \| "paused" \| "archived" | no | | | `starts_at` | string | no | ISO-8601 start date for automated scheduling | | `ends_at` | string | no | ISO-8601 end date for automated scheduling | | `eligibility` | object | no | Advanced segment matching rules (e.g. segment_member, audience_signals) | | `priority` | number | no | Evaluation priority (higher = evaluated first) | ### create_content_variant `[write]` Create a personalized content variant for a zone + segment combination. For product_reco variants, create with an empty payload ({}) and then call configure_product_reco to set the recommendation mode and curated products. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `zone_id` | string | yes | Zone ID | | `segment_id` | string | no | Target segment ID (legacy mode, or mirrored from eligibility) | | `type` | "overlay" \| "hero_swap" \| "copy_swap" \| "product_reco" \| "move_object" | yes | Variant type | | `payload` | object | yes | Variant payload. For overlay/hero_swap/copy_swap: { headline, body, cta, image_url }. For product_reco: pass {} and configure via configure_product_reco. For move_object: { dest_selector, position } — but prefer author_move, which also creates the source zone. | | `eligibility` | object | no | Advanced segment matching rules (e.g. segment_member, audience_signals) | | `priority` | number | no | Evaluation priority (higher = evaluated first) | | `campaign_id` | string | no | Link this variant to an orchestration campaign | ### create_form `[write]` Create a reusable lead-capture form template. The payload is the form design; it is copied onto each placement. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | yes | Internal template name | | `payload` | object | yes | Form design: { title, cta_text, tcpa_text, accent_color, fields (subset of name/email/phone), calendar_enabled } | ### create_page_config `[write]` Create a page type configuration for sitemap analysis. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `page_type` | string | yes | Page type (product, category, blog) | | `url_pattern` | string | yes | URL pattern to match | | `selectors` | object | no | CSS selectors for page elements | ### create_trigger `[write]` Create a new triggered message. Requires name, mode (immediate|dormancy), watch_event, and at least one destination. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | yes | Human-readable name | | `description` | string | no | | | `mode` | "immediate" \| "dormancy" | yes | Fire mode | | `watch_event` | string | yes | Event type to watch | | `cancel_event` | string | no | Event that cancels dormancy | | `criteria` | object | no | Matching criteria | | `delay_ms` | number | no | Dormancy delay in ms | | `window_ms` | number | no | Cancel-event window in ms | | `identifier_type` | "email" \| "phone" \| "device" \| "external_id" \| "profile_id" | no | | | `destinations` | object[] | yes | Destination configs | | `cooldown_per_profile_ms` | number | no | | | `global_rate_limit_per_min` | number | no | | | `optimization_mode` | "axo_bandit" \| "external" | no | Optimization mode (axo_bandit or external) | ### create_trigger_template `[write]` Create a new site-owned payload template for triggered messages. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | yes | Template name | | `description` | string | no | | | `format` | "json" \| "html" \| "form" | yes | Template format | | `body` | string | yes | Template body with mustache placeholders | | `example_destination` | string | no | Intended destination type | ### create_zone `[write]` Create a new personalization zone on the site. For lightbox zones (zone_key="lightbox"), pass display_rules to set when/where/how-often the popup fires; otherwise call list_lightbox_presets and use one of those rule objects verbatim. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `page_pattern` | string | yes | URL pattern (e.g. "/", "/product*") | | `zone_key` | string | yes | Zone identifier | | `display_name` | string | yes | Human-readable name | | `element_selector` | string | no | CSS selector | | `position` | string | no | Position (before/after/replace) | | `display_rules` | object | no | Lightbox-only display rules (DisplayRules shape — see lib/display-rules.ts). Sub-objects: trigger {type, delay_ms?, scroll_pct?, inactivity_ms?}, page_targeting {exclude[]}, audience {visitor_type, converted, device[]}, frequency {cap, n_days?, cooldown_seconds?}, suppression {after_dismiss_days?, after_convert_days?, mutual_exclusion?}. The API sanitizes — bad fields are dropped, not 400d. Ignored on non-lightbox zones. | ### delete_campaign `[admin]` Delete a campaign permanently. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `campaign_id` | string | yes | Campaign ID | ### delete_content_variant `[admin]` Soft-delete a content variant. The variant is hidden immediately but recoverable via restore_content_variant within 30 days. A history snapshot is automatically created before deletion. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `variant_id` | string | yes | Variant ID | ### delete_form `[write]` Delete a form template. Already-deployed placements are unaffected (placements copy the payload). | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | yes | Form template ID | ### delete_page_config `[admin]` Delete a page type configuration. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `config_id` | string | yes | Config ID | ### delete_trigger `[admin]` Permanently delete a trigger and its fire history. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `trigger_id` | string | yes | Trigger ID | ### delete_trigger_template `[admin]` Delete a site-owned trigger payload template. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `template_id` | string | yes | Template ID | ### delete_zone `[admin]` Delete a zone and all its content variants. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `zone_id` | string | yes | Zone ID | ### draft_content_variant `[write]` Use AI to generate a content variant draft for a segment + zone. Returns suggested headline, body, and CTA. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `segment_id` | string | yes | Target segment | | `zone_key` | string | no | Zone key (e.g. "hero") | | `variant_type` | "overlay" \| "hero_swap" \| "copy_swap" | no | Variant type | ### get_optimizer `[read]` Get the multi-armed bandit optimizer status. Shows Thompson Sampling allocation weights, which variants are winning, conversion rates per variant, and Beta distribution parameters. ### get_trigger `[read]` Get full trigger configuration: events, dormancy, identifier type, destinations, payload templates. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `trigger_id` | string | yes | Trigger ID | ### get_trigger_template `[read]` Get full details of a trigger payload template. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `template_id` | string | yes | Template ID | ### get_zones `[read]` Get personalization zones. Pass zone_id to fetch a single zone (recommended when working on a specific zone — full response is 200KB+). Without zone_id, returns all zones for the site. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `zone_id` | string | no | If provided, return only this zone (much smaller response — use this when repairing a specific zone's field_schema) | ### list_campaigns `[read]` List all campaigns for the site with status and briefs. ### list_forms `[read]` List reusable lead-capture form templates for this site. Each has a name and a payload (title, cta_text, tcpa_text, accent_color, fields[], calendar_enabled). ### list_lightbox_presets `[read]` List the canned lightbox display-rule presets (Welcome offer, Exit intent newsletter, Cart recovery, Promo bar, Returning visitor offer). Each preset returns a complete DisplayRules object that can be passed verbatim as create_zone.display_rules or update_zone.display_rules. Use this instead of authoring the rules JSON from scratch unless you need a custom combination. ### list_page_configs `[read]` List page type configurations (product, category, blog). ### list_trigger_fires `[read]` Get the audit log of fire attempts for a trigger: successes, errors, skipped fires with skip_reason. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `trigger_id` | string | yes | Trigger ID | | `limit` | number | no | Max rows (default 100, max 500) | ### list_trigger_templates `[read]` List available payload templates: system seeds and site-owned custom templates. ### list_triggers `[read]` List all triggered messages for the site with watch event, mode, destinations, and enabled status. ### place_lead_form `[write]` Deploy a lead-capture form onto a page: creates a lead_form content variant bound to a zone (anchor) + audience. The form INSERTS relative to the anchor by `position` (default "after" — slots between sections without taking over). Target ONE segment via `segment_id`, OR set `all_visitors: true` to show the form to EVERYONE regardless of segment (provide exactly one). Get a payload from list_forms (copy-on-place) or pass one directly. To anchor somewhere that is not yet a zone, call extension_pick_element then create_zone first. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `zone_id` | string | yes | Anchor zone to place the form relative to | | `segment_id` | string | no | Audience segment to show it to. Omit when all_visitors is true. | | `all_visitors` | boolean | no | Show the form to ALL visitors regardless of segment. When true, omit segment_id. | | `payload` | object | yes | Form design payload (e.g. from a template via list_forms) | | `position` | "after" \| "before" \| "inside_start" \| "inside_end" \| "replace" | no | Where the form inserts relative to the anchor element. Default "after". "replace" takes over the anchor (legacy / dedicated containers). | ### restore_content_variant `[write]` Restore a content variant. Two modes: (1) pass only variant_id to un-delete a soft-deleted variant; (2) also pass version to roll back the payload to a specific historical version (use get_content_history to find version numbers). Restoring to a version is itself snapshotted, so you can always roll forward again. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `variant_id` | string | yes | Variant ID to restore | | `version` | integer | no | History version to restore payload to. Omit to only un-delete. | ### suggest_donation_amounts `[read]` Return the segment-aware donation ask ladder for a donor — the amounts a fundraising form should show first, plus the recurrence default + rationale. Pass `segment_suffix` for the default ladder per segment (e.g. "donor_ready", "high_capacity_uncontacted", "lapsed_quarterly"), OR pass `profile_id` to personalise off the donor's CRM-fed attributes (last_gift_amount_cents / recurring_amount_cents / lifetime_giving_cents / capacity_score). When `profile_id` is given without `segment_suffix`, the profile's current segment is used. Returns { ladder: { amounts_cents, recurrence, rationale, highlight_index?, highlight_label? }, resolved }. Amounts are in CENTS. Use before authoring a copy_swap variant that writes the amounts onto a donation form, or when the agent needs to suggest "what should we ask for" from the donor context. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `segment_suffix` | string | no | verticals.ts segment suffix (e.g. donor_ready, high_capacity_uncontacted, lapsed_quarterly). | | `profile_id` | string | no | Profile to personalise off — last gift, recurring amount, capacity. CRM attributes pulled from profiles.attributes. | | `last_gift_amount_cents` | integer | no | Override (cents). Useful when profile data is stale or unavailable. | | `recurring_amount_cents` | integer | no | Override (cents). For recurring_card_declined the ladder surfaces ONLY this amount. | | `lifetime_giving_cents` | integer | no | Override (cents). Elevates the high-capacity ladder when ≥ $10k. | | `capacity_score` | number | no | Override (0..1). Elevates the high-capacity ladder when ≥ 0.9. | ### test_fire_trigger `[write]` Fire a trigger against a test target, bypassing cooldown/rate limits. Goes through the real dispatch pipeline — WILL send real email/SMS. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `trigger_id` | string | yes | Trigger ID | | `profile_id` | string | no | Profile ID | | `identifier` | object | no | Test target identifier | | `event_properties` | object | no | Override event properties | ### update_campaign `[write]` Update a campaign name, brief, or status. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `campaign_id` | string | yes | Campaign ID | | `name` | string | no | | | `brief` | object | no | | | `status` | "active" \| "draft" \| "paused" \| "archived" | no | | | `starts_at` | string \| null | no | | | `ends_at` | string \| null | no | | | `eligibility` | object \| null | no | | | `priority` | number | no | | ### update_content_variant `[write]` Update a content variant payload or active status. A history snapshot of the previous state is automatically saved before the update, so changes are always reversible via restore_content_variant. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `variant_id` | string | yes | Variant ID | | `payload` | object | no | Updated payload | | `active` | boolean | no | Enable/disable | | `type` | "overlay" \| "hero_swap" \| "copy_swap" \| "product_reco" \| "move_object" | no | | | `eligibility` | object | no | | | `priority` | number | no | | | `segment_id` | string | no | | | `campaign_id` | string \| null | no | | ### update_form `[write]` Update a form template name and/or payload. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | yes | Form template ID | | `name` | string | no | New name | | `payload` | object | no | Updated form design | ### update_page_config `[write]` Update a page type configuration. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `config_id` | string | yes | Config ID | | `url_pattern` | string | no | Updated URL pattern | | `selectors` | object | no | Updated selectors | ### update_trigger `[write]` Update an existing trigger. Pass only the fields to change. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `trigger_id` | string | yes | Trigger ID | | `name` | string | no | | | `description` | string | no | | | `enabled` | boolean | no | | | `mode` | "immediate" \| "dormancy" | no | | | `watch_event` | string | no | | | `cancel_event` | string | no | | | `criteria` | object | no | | | `delay_ms` | number | no | | | `window_ms` | number | no | | | `identifier_type` | string | no | | | `destinations` | object[] | no | | | `cooldown_per_profile_ms` | number | no | | | `global_rate_limit_per_min` | number | no | | | `optimization_mode` | "axo_bandit" \| "external" | no | Optimization mode | ### update_trigger_template `[write]` Update a site-owned trigger payload template. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `template_id` | string | yes | Template ID | | `name` | string | no | | | `description` | string | no | | | `format` | "json" \| "html" \| "form" | no | | | `body` | string | no | | | `example_destination` | string | no | | ### update_zone `[write]` Update an existing zone (selector, name, priority, approval, display_rules, or field schema). To add a missing field (e.g. image_url): call get_zones(zone_id) first to read the existing field_schema, then pass the full updated array with the new entry appended. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `zone_id` | string | yes | Zone ID | | `display_name` | string | no | | | `element_selector` | string | no | | | `approved` | boolean | no | | | `priority` | number | no | | | `display_rules` | object | no | Lightbox display rules — same shape as create_zone.display_rules. Send the full object to overwrite; omit to leave unchanged. Sanitized at the API. | | `field_schema` | object[] | no | Full replacement field schema — pass the complete array including existing entries you want to keep. Read the current schema first with get_zones(zone_id). | ## Content variants Draft, edit, and version the content served into zones. ### get_content `[read]` Get content variants. Pass zone_id to fetch only variants for a single zone (recommended — the full response is 1MB+). Without zone_id, returns all variants for the site. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `zone_id` | string | no | If provided, return only variants for this zone (much smaller response — use this when working on a specific zone) | ### get_content_history `[read]` Get the version history for a content variant. Returns up to 20 snapshots ordered newest first, each with version number, who changed it (api or dashboard), when, and the full payload. Use this before calling restore to find the version you want. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `variant_id` | string | yes | Variant ID to inspect | ### list_content_sources `[read]` List captured content-backlog sources for the blog pipeline. Filter by status (new/used/skipped) and recency. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `status` | "new" \| "used" \| "skipped" | no | Default: new | | `days` | number | no | Look-back window in days (default 30) | ### log_article `[write]` Log an interesting article, link, or point of view into the content backlog. The weekly blog pipeline drafts posts from these. Provide a url and/or a note explaining why it matters. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `url` | string | no | Link to the article/source (optional if note is given) | | `title` | string | no | Title of the article (optional) | | `note` | string | no | Your angle: why this is interesting, what point it supports (optional if url is given) | | `tags` | string[] | no | Freeform tags, e.g. ["agentic", "segmentation"] | ## Catalog & recommendations Import products, manage the taxonomy, and configure recommendation zones. ### get_catalog_import_status `[read]` Get the status and list of imported products in the catalog. ### get_site_taxonomy `[read]` Retrieve the parsed taxonomy mapping representing the site hierarchy. ### import_catalog `[write]` Import a payload of products into the product catalog. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `products` | object[] | yes | Array of products to import | ### list_products `[read]` Search and list catalog products/items for a site. Allows filtering by category, specific product IDs, or including ignored items. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `ids` | string[] | no | Array of specific product IDs to fetch (optional) | | `category` | string | no | Filter by category (optional) | | `include_ignored` | boolean | no | If true, include ignored products in the output (default false) | | `limit` | number | no | Max results (default 100, max 500) | ### list_taxonomy_terms `[read]` List the site's taxonomy terms — the brand/topic/category vocabulary that drives per-visitor interest/affinity scoring. Optionally filter by dimension. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `dimension` | "brand" \| "topic" \| "category" | no | Filter to one dimension | ### merge_categories `[write]` Merge and rename product categories (renames a category across all products in sitemap and page profiles). | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `old_category` | string | yes | Current category name to rename | | `new_category` | string | yes | New category name | ### reclassify_catalog_item `[read]` Change a catalog product/item details (category, name, brand, description, sku, price) or mark it as ignored (which hides it from the personalization catalog and excludes it from variant recommendation). Sets is_override to true. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `item_id` | string | yes | Catalog product UUID | | `category` | string | no | New category name (optional) | | `name` | string | no | New product name (optional) | | `brand` | string | no | New brand name (optional) | | `description` | string | no | New product description (optional) | | `sku` | string | no | New SKU (optional) | | `price` | string | no | New price (optional) | | `ignored` | boolean | no | Set to true to ignore the product, false to restore (optional) | ## Assets & brand Generate images, manage the DAM, and extract brand guidelines. ### extract_brand_guidelines `[write]` Extract brand features (colors, theme configurations) directly from the live homepage. ### generate_image `[write]` Generate a NEW image via the site's BYOK image provider (gemini | openai | firefly). Real, paid API call (~$0.04) — call search_assets FIRST and reuse an existing asset when one matches. provider + prompt required. Optional: model, width, height, negative_prompt; use_brief prepends brand-voice + active-campaign context; zone_key / variant_type add visual context; reference_images (catalog product / URL / data URL) and plan_with_claude require experimental_creative_enabled. When experimental_generative_dam_enabled is on, the image is persisted and the result carries asset_id + blob_url — pass that asset_id to attach_asset_to_variant to place it on a variant. The base64 data_url is OMITTED from the result (too large); fetch blob_url for the bytes. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `provider` | "gemini" \| "openai" \| "firefly" | yes | BYOK provider. The site must have active credentials saved for it. | | `prompt` | string | yes | What to generate (max 4000 chars). | | `model` | string | no | Optional provider model id (e.g. "imagen-4.0-generate-001", "gpt-image-1"). Omit for the provider default. | | `width` | integer | no | Optional pixel width. | | `height` | integer | no | Optional pixel height. | | `negative_prompt` | string | no | Optional — things to avoid in the image. | | `use_brief` | boolean | no | When true, prepend brand voice + active campaign brief context. Default false. | | `zone_key` | string | no | Optional zone hint (e.g. "hero") woven into the prompt. | | `variant_type` | string | no | Optional variant-type hint (overlay \| hero_swap \| copy_swap). | | `reference_images` | object[] | no | Optional reference images (subject/style). Requires experimental_creative_enabled. | | `plan_with_claude` | boolean | no | When true, Claude drafts a detailed shot prompt before dispatch. Requires experimental_creative_enabled. Default false. | ### get_asset `[read]` Fetch one DAM asset by id — includes the full generation_metadata (user_prompt, enriched_prompt, brief / reference / planner attribution) and tags. Use to inspect an image's provenance before re-using or attaching it. search_assets returns the list view (no generation_metadata); this is the detail view. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `asset_id` | string | yes | Asset id (asset_ shape). | ### import_figma_brand `[write]` Import and configure site brand definitions from a Figma file URL. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `figma_url` | string | yes | URL to the Figma file/component | ### list_dam_connections `[read]` List the customer's DAM connections (Cloudinary, S3-compatible, etc.) for this site — masked credentials, active flag, provider metadata. Use before search_dam to discover which DAMs are wired (or to confirm one is connected before suggesting search_dam to the operator). Returns { connections: [{ id, provider, provider_meta, config_preview, active, ... }] }; credentials in config_preview are masked (api_secret as "••••XXXX"). Empty array when no DAM is connected. ### list_image_gen_keys `[read]` List BYOK image-gen provider credentials for this site (Gemini, OpenAI, Adobe Firefly). The generate_image tool routes through whichever has saved credentials + provider matches the request. Use to discover which providers are available before suggesting generate_image, or to confirm a custom_model_id (BYOM) is set on a connection. Returns { keys: [...] } with masked credentials. ### list_text_gen_keys `[read]` List BYOM text-gen credentials for this site (OpenAI-compatible endpoints — vLLM, Ollama, Azure OpenAI, LM Studio). When a key is active AND experimental_byom_enabled is on, /api/content/draft routes the variant-authoring AI calls through it instead of platform Anthropic. Use to discover whether the operator has BYOM text wired before suggesting draft_content_variant. Returns { keys: [...] } with masked api_key fields. ### register_dam_asset `[read]` Create an AXO thin asset record from a brand-DAM asset (e.g. one returned by search_dam). Returns { id, url, reused } — the id is the asset_ you pass to attach_asset_to_variant. Dedups by (site_id, dam_provider, dam_asset_id) so picking the same asset twice reuses the existing row. No bytes pass through AXO; the asset stays in the customer's DAM. Gated on experimental_byo_dam_enabled + an active connection for the named provider. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `provider` | string | yes | Vendor id from the search_dam hit ("cloudinary" \| "s3_compatible"). | | `dam_asset_id` | string | yes | Vendor-side id from the hit (Cloudinary public_id, S3 key). | | `external_url` | string | yes | Public URL from the hit (Cloudinary secure_url, S3 public URL). | | `mime_type` | string | no | Optional, defaults to image/png. | | `width` | number | no | Optional pixel width. | | `height` | number | no | Optional pixel height. | | `name` | string | no | Optional display name for the AXO library. Defaults to the asset id. | ### search_assets `[read]` Search the generative DAM asset library for previously-generated images. Filters: q (text match on name + prompt, ILIKE), subject (tags.subject exact), theme (tags.themes contains), provider (gemini|openai|firefly), include_archived (default false). Returns up to `limit` assets with their blob_url, name, prompt, provider/model, and auto-tagged subject/scene/themes/palette. Use this BEFORE generating new images — if the operator asks for "a warm autumn kitchen background" and one already exists in the library, attaching it saves $0.04 of generation cost and ~3 seconds of wall-clock. Requires experimental_generative_dam_enabled on site_config.product_catalog. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `q` | string | no | Text match against name + prompt (ILIKE). | | `subject` | string | no | Exact match on tags.subject (e.g. "kitchen"). | | `theme` | string | no | Tag in tags.themes (e.g. "minimalist"). | | `provider` | "gemini" \| "openai" \| "firefly" | no | | | `include_archived` | boolean | no | | | `limit` | integer | no | Default 20. | ### search_dam `[read]` Search the customer's CONNECTED brand DAM (Cloudinary, S3-compatible) for assets — including ones the brand team uploaded directly without going through AXO. Use when the brand owns assets you want to BIND to a variant rather than generate fresh: the brand has approved imagery you should reuse. q matches filename + public_id + tag values (Cloudinary) or key-substring (S3); folder scopes to a folder prefix; tags filters to assets carrying ALL of the listed tags (Cloudinary only — S3 tags aren't indexed for search). Returns hits with asset_id (vendor public_id / S3 key), external_url, mime_type, tags, folder. THREE-STEP BIND FLOW: search_dam → register_dam_asset (creates AXO thin record + returns asset_id) → attach_asset_to_variant (binds to a variant field with provenance). Returns empty when no DAM is connected — search_assets handles the AXO-side library separately. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `q` | string | no | Free-text query — matched against filename, public_id, and tag values. | | `folder` | string | no | Restrict to a folder/prefix (e.g. "axo/franken-store-com"). | | `tags` | string[] | no | Restrict to assets carrying ALL of these tags (Cloudinary only — S3 ignores). | | `limit` | number | no | Default 30, max 100. | | `provider` | string | no | Optional provider scope ("cloudinary" \| "s3_compatible"). When omitted, uses the site's first active DAM connection. | ### update_asset `[write]` Update a DAM asset: rename (name), replace its tags (tags object), or archive/unarchive (archived). Pass archived:true to soft-delete — it disappears from search_assets but any variant already pointing at its blob_url keeps working; archived:false restores it. At least one of name | tags | archived must be set. The blob bytes are never mutated. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `asset_id` | string | yes | Asset id (asset_ shape). | | `name` | string | no | New display name (max 200 chars). | | `tags` | object | no | Replacement tags object. Overwrites the existing tags. | | `archived` | boolean | no | true to archive (soft-delete / hide from search), false to restore. | ## Integrations & sync Connect destinations, test them, and sync CRM/Salesforce data. ### create_integration `[write]` Create a new integration (klaviyo, braze, resend, webhook, meta_capi, google_ec). | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `type` | string | yes | Integration type | | `config` | object | yes | Config (API keys, endpoints) | | `events` | string[] | no | Events to fire on | | `active` | boolean | no | Enable immediately | ### delete_integration `[admin]` Delete an integration permanently. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `integration_id` | string | yes | Integration ID | ### get_integration `[read]` Get full config for a single integration. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `integration_id` | string | yes | Integration ID | ### get_integration_logs `[read]` Recent fire log for an integration with success/error stats. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `integration_id` | string | yes | Integration ID | | `limit` | number | no | Max rows (default 50) | ### list_integrations `[read]` List all integrations (Klaviyo, Braze, Resend, webhooks, CAPI) with status. ### sync_crm `[write]` Push CRM records to enrich visitor profiles. Matches by email, phone, or external_id. Attributes (ltv, plan, customer_tier, etc.) are merged into the matched profile. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `records` | object[] | yes | Array of CRM records to sync (max 1000) | | `source` | string | no | Source label (e.g. "salesforce", "hubspot") | ### test_integration `[write]` Send a test payload to an integration to verify the connection works. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `integration_id` | string | yes | Integration ID | ### update_integration `[write]` Update integration config, events, or active status. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `integration_id` | string | yes | Integration ID | | `config` | object | no | | | `events` | string[] | no | | | `active` | boolean | no | | ## Site & configuration Site config, verticals, taxonomy, sitemap health, and page configs. ### analyze_sitemap `[read]` Analyze a semantic sitemap structure to optimize category mapping internally. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `options` | object | no | Configuration/tuning options for the analysis run | ### apply_vertical_pack `[write]` Apply (or re-apply) a vertical pack to the current site. Seeds any missing segments, zones, and variants from the pack and updates the site vertical. Idempotent — existing items are preserved. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `vertical` | "ecommerce" \| "home_services" \| "saas" \| "financial" \| "healthcare" \| "nonprofit" | yes | | ### define_affinity_terms `[read]` Create or update taxonomy terms (brand/topic/category) with the keyword + URL-pattern rules that map pages to that object. These feed per-visitor affinity scoring and the "Interest / affinity" segment leaf. object_key defaults to a slug of the label. Example term: { dimension:"brand", label:"Titleist", keywords:["titleist"], url_patterns:["/titleist"] }. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `terms` | object[] | yes | Terms to upsert | ### discover_sitemap `[write]` Discover and map semantic URLs from the site, identifying structure automatically. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `url` | string | no | Force extraction starting from a specific URL | ### get_site_config `[read]` Get current site configuration: brand, mode, conversion goal, settings. ### get_vertical_pack `[read]` Get the full contents of a vertical pack (segments, zones, variants) before applying it. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `vertical` | "ecommerce" \| "home_services" \| "saas" \| "financial" \| "healthcare" \| "nonprofit" | yes | | ### list_verticals `[read]` List available industry vertical packs (ecommerce, home_services, saas, financial, healthcare, nonprofit). Each pack bundles default segments, zones, and variants tailored to that industry. ### update_site_config `[write]` Update site settings: brand, mode, conversion goal(s), zone overlap mode, holdout, passive_mode. Pass `goals` (array) to set the typed multi-goal list — primary + optional supporting goals. `conversion_goal` (single URL string) is the legacy single-goal field; passing it materializes a primary URL-kind goal. Pass one OR the other, not both. `passive_mode: true` locks out first-party PII (no lead forms, no identify/CRM writes) while keeping anonymous behavioral + goal/conversion tracking — use for no-PII pilots. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `mode` | "active" \| "backtest" | no | | | `conversion_goal` | string | no | | | `goals` | object[] | no | | | `brand_primary` | string | no | | | `brand_accent` | string | no | | | `brand_font` | string | no | | | `zone_overlap_mode` | "all" \| "first" \| "priority" | no | | | `disable_holdout` | boolean | no | | | `holdout_pct` | integer | no | | | `passive_mode` | boolean | no | | ## CRM & pipeline Manage the customer-facing sales pipeline: opportunities, contacts, tasks. ### get_crm_status `[read]` Get CRM sync history and enrichment statistics. Shows how many profiles have CRM attributes, total enrichment coverage, and recent sync logs. ### get_salesforce_status `[read]` Get Salesforce integration status, sync history, and coverage stats. Shows connection state, recent syncs, and how many profiles are enriched from Salesforce. ### pipeline_add_contact `[write]` Add a contact (name, email, phone, role) to a CRM opportunity. Set is_primary to make them the headline contact. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `opportunity_id` | string | yes | The opportunity id (opp_…) | | `name` | string | yes | Contact full name | | `email` | string | no | Email address | | `phone` | string | no | Phone number | | `role` | string | no | Role, e.g. "Owner" | | `is_primary` | boolean | no | Make this the primary contact | ### pipeline_add_note `[write]` Append a note to a CRM opportunity's activity timeline (append-only): call summaries, next steps, observations. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `opportunity_id` | string | yes | The opportunity id (opp_…) | | `body` | string | yes | The note text (max 10k chars) | ### pipeline_add_task `[write]` Add a task (next step) to a CRM opportunity: "send the quote", "follow up Friday". Every open deal should have a next step — the earliest-due open task shows as the deal's next step on the board and in the digest. due_date is day-granular. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `opportunity_id` | string | yes | The opportunity id (opp_…) | | `title` | string | yes | What needs doing, imperative, ≤200 chars — e.g. "Send revised quote" | | `due_date` | string | no | YYYY-MM-DD (omit for undated) | | `body` | string | no | Optional detail / context | ### pipeline_create_opportunity `[write]` Create a CRM opportunity. Stage must be a key from pipeline_get_funnel (omit for the first open stage). value_cents is the deal value in cents. custom carries values for the account's defined custom fields (see settings.fields). | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `company` | string | yes | Company / customer name | | `title` | string | no | Deal title (default: " deal") | | `stage` | string | no | Funnel stage key (default: first open stage) | | `value_cents` | number | no | Deal value in cents | | `website` | string | no | Company website URL | | `source` | string | no | Where the deal came from | | `notes` | string | no | Free-form notes | | `expected_close_date` | string | no | YYYY-MM-DD | | `custom` | object | no | Custom-field values keyed by the defs in settings.fields | ### pipeline_get_funnel `[read]` The account's CRM pipeline definition: ordered stages (key, label, open/won/lost kind, close probability, stale_after_days) plus module settings (auto_create_from_leads, lost_reasons, fields, digest, …) and a vertical preset (suggested stages/lost reasons/fields for the account's business type — a seed to offer, never auto-applied). Call this FIRST before creating or moving opportunities — stage keys are per-account vocabulary, not a fixed set. ### pipeline_get_opportunity `[read]` One CRM opportunity in full: fields, firmographic enrichment, contacts, tasks, and the activity timeline. Contacts and the company carry live on-site behavioral context — segments, interests/affinities (brand/topic/category), high-intent page signals, sessions, conversions, recency, and hotness — plus a rollup of other open deals at the same company domain. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `opportunity_id` | string | yes | The opportunity id (opp_…) | ### pipeline_list_opportunities `[read]` List the account's CRM opportunities (max 500, newest first) with stage, value, primary contact, hot-lead flag — plus the funnel stages for grouping into a board view. ### pipeline_list_prospects `[read]` Shadow opportunities ("Companies on your site"): corporate-email domain clusters of identified visitors whose behavior crossed the intent threshold, with evidence (people, sessions this week, top pages). These are deal CANDIDATES AXO observed — not yet in the pipeline. To ratify one, show it to the user and create an opportunity with pipeline_create_opportunity (company from the domain, contacts from the people, source "axo_prospect"). Domains already on open/won deals and dismissed domains are excluded. ### pipeline_list_tasks `[read]` List CRM tasks (next steps) across the account's opportunities, earliest-due first. Default: open tasks only. Use due_before with today's date to find overdue tasks, or opportunity_id to see one deal's list. An open deal with no open task has "no next step" — worth flagging to the user. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `status` | string | no | open\|done\|skipped\|all (default open) | | `opportunity_id` | string | no | Narrow to one opportunity (opp_…) | | `due_before` | string | no | YYYY-MM-DD — only tasks due strictly before this date (overdue scan) | ### pipeline_log_activity `[write]` Log a touchpoint (email, call, or meeting) on a CRM opportunity's timeline. Use external_ref (e.g. "gmail:", "gcal:") for idempotency — re-logging the same ref returns the existing row instead of duplicating, so sweep agents can re-run safely. For plain observations use pipeline_add_note; for inferred stage moves use pipeline_suggest_stage_move. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `opportunity_id` | string | yes | The opportunity id (opp_…) | | `kind` | string | yes | email\|call\|meeting | | `body` | string | yes | What happened — summary shown on the timeline (max 10k chars) | | `occurred_at` | string | no | When it happened, ISO 8601 (defaults to now; stored in metadata) | | `external_ref` | string | no | Idempotency key, e.g. "gmail:189ab…" — strongly recommended for swept sources | ### pipeline_propose_funnel `[write]` Turn a plain-language description of how the business sells into a validated pipeline proposal: stages with probabilities, settings, and a rationale. READ-ONLY — returns the proposal plus the current stages for diffing; nothing is saved. Apply with pipeline_set_funnel after the user approves. Uses an AI call (allowance-metered). | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `description` | string | yes | The user's plain-language description of their sales process (10-4000 chars) | ### pipeline_set_funnel `[write]` Save the account's CRM pipeline: stages replace wholesale, settings merge per key (a single knob never wipes the others). Stage validation: 3-12 stages, snake_case keys, exactly one won + one lost stage, probabilities 0-100, optional stale_after_days (1-365, open stages) for the stale-deal nudge; a stage currently holding opportunities cannot be removed (move them first). Omit stages to change settings alone. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `stages` | object[] | no | The complete ordered stage list — replaces the existing funnel wholesale; omit to keep the current ladder and only touch settings | | `auto_create_from_leads` | boolean | no | When true, captured website leads auto-create/attach opportunities. Omit to leave unchanged. | | `lost_reasons` | string[] | no | Lost-reason vocabulary (max 12, each ≤40 chars) — powers the picker and the "why we lose" grouping; deals can still record any free-text reason. Omit to leave unchanged. | | `fields` | object[] | no | Custom-field definitions for opportunities (max 10); money = integer cents; options required for select. Omit to leave unchanged. | ### pipeline_suggest_stage_move `[write]` Propose (not perform) a stage move on a CRM opportunity: appends a suggestion the user accepts or dismisses in the CRM. USE THIS whenever you INFER a deal progressed — pipeline_update_opportunity is only for user-directed moves. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `opportunity_id` | string | yes | The opportunity id (opp_…) | | `to_stage` | string | yes | The proposed funnel stage key | | `reason` | string | yes | The evidence, 1-3 sentences — shown verbatim on the timeline | ### pipeline_update_opportunity `[write]` Update a CRM opportunity — move stage (auto-logs a stage_change and fires the behavioral rail), change value, title, close date, custom fields, or record a lost_reason. Only pass changed fields. IMPORTANT: only move stages when the user asked for the move or approved a suggestion; when you merely INFER progress, use pipeline_suggest_stage_move instead. When moving a deal to the lost stage, ask for (or infer from the user's words) a short lost_reason. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `opportunity_id` | string | yes | The opportunity id (opp_…) | | `stage` | string | no | New funnel stage key | | `company` | string | no | Company name | | `title` | string | no | Deal title | | `value_cents` | number | no | Deal value in cents | | `website` | string | no | Company website URL | | `source` | string | no | Deal source | | `notes` | string | no | Free-form notes (replaces existing) | | `expected_close_date` | string | no | YYYY-MM-DD | | `lost_reason` | string | no | Why the deal was lost, ≤80 chars — free text; prefer one of settings.lost_reasons when it fits. Only settable on a deal in (or moving to) the lost stage; cleared on reopen. | | `custom` | object | no | Custom-field values to merge (null deletes a key), keyed by the defs in settings.fields | ### pipeline_update_task `[write]` Update a CRM task: complete it (status done), skip it, reopen it, reschedule (due_date), or edit the title/body. Completing or skipping logs a system activity on the deal's timeline. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `task_id` | string | yes | The task id (task_…) | | `status` | string | no | open\|done\|skipped | | `title` | string | no | New title | | `body` | string | no | New detail (empty string clears) | | `due_date` | string | no | New due date YYYY-MM-DD (empty string clears) | ### trigger_salesforce_sync `[write]` Trigger a Salesforce sync. Direction can be outbound (push AXO→SF), inbound (pull SF→AXO), or bidirectional. | Parameter | Type | Required | Description | | --- | --- | --- | --- | | `direction` | "outbound" \| "inbound" \| "bidirectional" | no | Sync direction (default: uses configured direction) |