MCP · Tool reference

MCP tool reference

169 tools the AXO MCP server exposes, grouped by domain. Each lists the scope it requires — a token can only call tools at or below its scope. Generated from the server, so it never drifts from what an agent sees. (A handful of operator and diagnostic tools are available to connected agents at runtime but omitted here.)

Analytics & lift

Read performance, holdout lift, optimizer state, events, and sessions.

get_agent_usageread

AI assistant usage: conversations, messages, tokens, estimated cost.

no parameters
get_ai_generationsread

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.

1 parameter
ParameterTypeDescription
variant_id
required
stringcontent_variants.id to read provenance for.
get_analyticsread

Get dashboard analytics overview: total sessions, conversions, revenue, segment breakdown, and trend data for the current site. hour_distribution is session COUNTS only — for conversion rate by time of day / day of week, use get_daypart_performance.

1 parameter
ParameterTypeDescription
days
optional
numberNumber of days to look back for windowed metrics (default: 90, max: 365); visitor_mix and significance are always all-time
get_backtestread

Get backtest results showing segment performance, variant impact, conversion rates, and revenue attribution. All figures are windowed (default 90 days) and the window is echoed back in the response. Retired segments are included when they still took sessions in the window, because retiring a segment does not stop traffic scoring into it. This is not the verdict on whether personalization is working — use get_scorecard for that.

1 parameter
ParameterTypeDescription
days
optional
numberNumber of days to look back (default: 90, max: 365)
get_daypart_performanceread

Conversion performance by day-of-week × hour-of-day, in the visitor's LOCAL time (first-touch stamps: the hour the visit STARTED; dow 0=Sunday..6=Saturday). THE source for "when do visitors convert / when should campaigns run?" — never infer timing from a time-based segment's lift, which usually comes from the segment's other clauses. Returns: `grid` (dow×hour cells, up to 168 — only combinations with at least one session appear, so never index it positionally; raw sessions and converting_sessions per cell, no per-cell rate on purpose: cells are small, judge significance from the counts before ranking them), `weekday_weekend` and `hour_blocks` rollups (with rates — prefer these for headlines; blocks are a fixed vocabulary, so check the grid for a peak straddling a block boundary), `window` (rates are floored at first conversion, like the dashboard CVR — days/floored say what span the rates actually cover), and `coverage` (measured_sessions the grid describes, vs rate_window_sessions — every session in that same floored window). Numerators are primary-goal converting sessions (the conversions ledger, as in get_analytics conversion_stats), but computed over the measured subset only: sessions without first-touch stamps and simulator sessions are EXCLUDED, never guessed, so rates here legitimately differ from conversion_stats wherever coverage is below 100% or simulator traffic exists — that gap is deliberate exclusion, not a data problem.

1 parameter
ParameterTypeDescription
days
optional
numberDays to look back (clamped to 1-365, default: 90); the rate window still floors at the first recorded conversion
get_eventsread

Get recent site events: pageviews, clicks, conversions, custom events.

1 parameter
ParameterTypeDescription
limit
optional
numberMax events (default 100)
get_form_funnelread

Form conversion funnel analytics: views → starts → submits → abandons, per form and per page, with field-level drop-off.

1 parameter
ParameterTypeDescription
window
optional
"24h" | "7d" | "30d" | "90d"Lookback window (default 30d)
get_lift_reportread

CONVERSION-RATE lift vs the always-on holdout control group (not revenue — revenue lift lives on get_scorecard). Default: the per-variant table. Pass `offer_id` for the per-OFFER roll-up (#1476): treated-vs-holdout CVR pooled across the offer's placements, delivery volume, and — once discount capture is live — an observed `redemption` block (redemptions, order-level discount spend, holdout-redemption leakage signal) that is explicitly NON-CAUSAL: redemption says people accepted free money, and the holdout comparison is the causal number. The response's `not_measured` array names what the report deliberately does not claim (incremental margin needs observed exposure). Pass offer_id="" (empty string) to get every offer on the site. The response carries `holdout_epoch` — arms are measured per VISITOR only since `epoch_started_at` (#1380 cutover); pre-cutover per-visit sessions are excluded, so a window that spans the cutover covers fewer sessions than its day-count implies.

2 parameters
ParameterTypeDescription
offer_id
optional
stringOffer to roll up (from list_offers). Empty string = all offers. Omit entirely for the per-variant table.
days
optional
integerWindow in days (default 30).
get_scorecardread

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. The response carries `holdout_epoch` — the verdict is computed on per-VISITOR sessions only since `epoch_started_at` (#1380 cutover); pre-cutover per-visit sessions are excluded, so a window spanning the cutover covers fewer sessions than its day-count implies.

1 parameter
ParameterTypeDescription
days
optional
integerNumber of days to look back (default: 30)
get_segment_performanceread

Performance metrics for a segment: sessions, conversions, rate, revenue, AOV. Also returns `attribution` (30-day window): `label_timing` says how many of the converting sessions ending in this segment already carried the label BEFORE they converted - `post_conversion_label_share` near 0 means the blended conversion_rate is real, while a high share means the segment absorbs converters after the fact (their conversion behavior produced the classifying signals) and the blended rate must never be quoted as intent or opportunity. `entry_label` is the strictest cohort - sessions already in this segment at their first event - and its conversion_rate is the honest predictive number to quote when the share is high. `attribution` is null when the segment has no conversions to attribute or the measurement failed.

1 parameter
ParameterTypeDescription
segment_id
required
stringSegment ID
get_sitemap_healthread

Sitemap crawl status, page counts, health metrics.

no parameters
get_tag_healthread

Tag health: 24h beacon/pageview/personalization counts, render errors, first and last event time (lifetime, not windowed), and status — healthy (beacons in 24h) | no_data (none in 24h but this site HAS reported before, so something stopped) | no_signal (never reported at all; a fresh or unvisited install, not evidence of breakage). Also per-goal liveness (goal_liveness / goals_never_fired_90d): a goal with last_fired_at null has fired ZERO times in 90 days — usually a misconfigured detection rule (wrong URL pattern, tag not on the conversion page), not an absence of conversions.

1 parameter
ParameterTypeDescription
site_id
optional
stringRequired on cross-site super-admin sessions: which site to read (from get_account_status). Ignored on site-scoped sessions, which always read their own site.
get_variant_performanceread

Performance metrics for a content variant: impressions, conversions, rate, render errors.

1 parameter
ParameterTypeDescription
variant_id
required
stringVariant ID

Audience & segments

Query and build behavioral segments; look up, merge, and link profiles.

create_segmentwrite

Create a new custom behavioral segment with a name, description, and signal rules.

4 parameters
ParameterTypeDescription
name
required
stringSegment name
description
optional
stringBehavioral description
emoji
optional
stringEmoji icon
signal_rules
optional
objectMatching signal rules
delete_profileadmin

Permanently delete a profile and all associated data (GDPR erasure). Removes identifiers, unlinks sessions, deletes the profile.

1 parameter
ParameterTypeDescription
profile_id
required
stringProfile UUID to delete
designate_optin_formwrite

Designate a SITE-NATIVE form (one the customer already has — newsletter, contact, signup) for opt-in lead capture, or update its field selectors. On submit of a matching form the tag captures the email (plus name/phone ONLY when their field selectors are set here or via data-axo-*-field attributes) into Leads/profiles/CRM. Works on native Episerver/Optimizely Forms too — their AJAX submit is captured via the same vendor hook that fires form_submit. For split-name forms (First + Last as separate inputs, e.g. Episerver) set first_name_field + last_name_field and the tag joins them into the one stored name; use name_field for a single combined input. Upserts by form_selector (max 20 designated forms). This reads visitor-entered PII from the customer's own form — only designate forms the customer owns and has asked to capture; it is inert in passive mode. Verify the selector matches exactly one <form> on the live page first (e.g. via get_form_funnel form ids or probe_zone_binding).

6 parameters
ParameterTypeDescription
form_selector
required
stringCSS selector matching the <form> element (e.g. "#newsletter-form", "form.contact")
email_field
optional
stringCSS selector (within the form) for the email input. Optional — without it the tag falls back to input[type=email] / name-contains-"email" heuristics.
name_field
optional
stringCSS selector for a single combined name input. Captured ONLY when designated. For split first/last inputs use first_name_field + last_name_field instead.
first_name_field
optional
stringCSS selector for a first-name input on a split-name form (e.g. Episerver). Joined with last_name_field into the one stored name; takes precedence over name_field. Captured ONLY when designated.
last_name_field
optional
stringCSS selector for a last-name input on a split-name form. Joined with first_name_field into the one stored name. Captured ONLY when designated.
phone_field
optional
stringCSS selector for the phone input. Phone is captured ONLY when designated (newsletter-grade opt-in — never TCPA/SMS consent).
explain_variant_exposureread

Answer "why did this visitor see this variant?" - or why they saw nothing - with a trace assembled from records. Returns `trace`, an ordered list of claims each carrying the exact rows it rests on: the cohort the scorer assigned and the signals behind it, the holdout arm and which bucketing epoch it was made under, the zone, every live variant's targeting predicate evaluated through the same evaluator the tag itself uses, allocation, and the personalization_applied event that names what actually rendered. Also returns `answer`, the same trace rendered to text by a pure function - no model writes any part of this response. TRACED, NOT INFERRED: report the verdict and the claims AS WRITTEN, offer the cited records when asked how you know, and never supply a reason the trace does not contain. Claims marked "unknown" are first-class answers with a stated reason, not gaps to fill. The most important one: display-rule outcomes (country and schedule gates) are evaluated in the visitor's browser and deliberately never beaconed or persisted, so nothing server-side can say whether one refused this visitor - say exactly that rather than guessing. A visitor in the holdout saw nothing BY DESIGN, and that is a complete and correct answer, not a fault. Identify the visitor by their durable vt_sid visitor id (sessions.cookie_session_id, returned by get_sessions and get_profile) or by a single session id. Name a zone to ask why nothing served there; omit it to explain the most recent recorded exposure. Read-only: reading a trace never changes what AXO serves.

3 parameters
ParameterTypeDescription
visitor
required
stringVisitor id (sessions.cookie_session_id) or session id (sessions.id)
zone
optional
stringZone id or zone_key. Omit to resolve the zone from the visitor's most recent exposure record
window_days
optional
numberLookback window: 1, 7 (default), or 30
export_audiencewrite

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.

7 parameters
ParameterTypeDescription
segment_id
required
stringSegment ID to export
format
optional
"json" | "webhook"Output format (default json)
destination
optional
stringWebhook URL (required when format=webhook)
email_only
optional
booleanOnly include profiles with an email; produce a campaign-ready email list (implies include_pii)
include_pii
optional
booleanInclude the profile email column (opt-in; audited)
include_affinities
optional
booleanAppend each profile's top-3 brand affinities
include_scores
optional
booleanAppend behavioral scores: intent_score (0–100 value-bid signal), lifecycle_stage, and signals (abandonment/milestone seed keys)
generate_audience_clusterswrite

Manually run K-Means machine-learning clustering against recent behavioral profile activity.

1 parameter
ParameterTypeDescription
k
optional
numberNumber of clusters to generate
get_profileread

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.

1 parameter
ParameterTypeDescription
profile_id
required
stringThe profile UUID to look up
get_segment_membersread

Paginated list of profiles in a segment with their identifiers.

3 parameters
ParameterTypeDescription
segment_id
required
stringSegment ID
limit
optional
numberMax results (default 50)
offset
optional
numberPagination offset
get_segment_orchestrationread

List everything currently acting on one segment - zone variants, triggers, recurring audience syncs and recent exports - each annotated with whether the goals measured downstream of it are the goal the segment's conversion thesis names. Serving is zone-local, so five touchpoints can pull one segment in five directions with nothing above them noticing; this is the view where that disagreement becomes visible. Alignment is MEASURED, never inferred from copy: a variant is credited with the goals hit in sessions that saw it, a trigger with the goals hit by profiles after it fired. Below the observation floors the verdict is "undetermined" with a reason - report those as written rather than treating them as alignment. A segment whose thesis says "insufficient evidence" has no primary goal to align against, and alignment_blocked_by says so instead of every touchpoint being guessed at. Exports are annotated with whether the THESIS travelled with the membership list, not with a goal: AXO does not observe what an audience converts to off-platform. Descriptive only - this view reports what it finds and never re-targets anything. Use it when asked why a segment is underperforming, or before adding another touchpoint to a segment that already has several.

2 parameters
ParameterTypeDescription
segment_id
required
stringSegment id, from get_segments
window_days
optional
numberMeasurement window: 7, 30 (default), or 90
get_segment_thesisread

Get one segment's conversion thesis in full: which site goals it most over- or under-reaches versus the site baseline, an operator-readable reading, the evidence behind that reading (member vs site-wide sessions, conversion rates, and per-goal reach measured in the window), the confidence, and whether the thesis is stale. Works for pack, custom, ad-source, and ML-discovered segments. Every figure traces to a measurement in the window; a segment with too little traffic returns an explicit insufficient-evidence reading rather than a guess. Descriptive only - reading a thesis never changes what AXO serves.

2 parameters
ParameterTypeDescription
segment_id
required
stringSegment id, from get_segments
window_days
optional
numberEvidence window: 7, 30 (default), or 90
get_segmentsread

List all behavioral segments (plus operator-built custom segments) with session counts, conversion rates, descriptions, and each segment's conversion thesis. Counts are live over the last 30 days, consistent with get_analytics segment_distribution. Use this to understand how visitors are being classified. Segments AXO discovered from behavior also carry `discovery`: what the group keyed on, as plain comparisons against the site average ("about 3x the site average"), plus its size, share of traffic, how many recent refreshes it has appeared in, and a coarse quality grade. Use it to explain why a discovered segment exists. `discovery` is null for rule-based segments (read their signal_rules instead) and for discovered ones the latest run did not produce. Its comparisons are deliberately coarse and its states ("too small to characterize", "no distinguishing signals") are honest — report them as written and do not extrapolate exact figures from them. Where `discovery` says what a group keyed on and the description says WHO is in it, `thesis` says why it matters to conversion: which site goals it over- or under-reaches, a short reading, and how much evidence is behind it. `thesis` is null when none has been built yet, and carries stale:true when the goals or the segment membership changed after it was written. Use get_segment_thesis for the full evidence behind one segment. The thesis is descriptive: it does not change what AXO serves. Every row also carries `expected_alignment`: non-null when the segment's own DEFINITION is upstream of, or overlapping with, a site goal, so its lift on that goal is fixed by construction rather than discovered - a form-starter segment against a form-submit goal, or a cart-adder against a purchase goal - or MEASURED from label-vs-conversion ordering (reason `post_goal_labeling`): a large share of the segment's conversions only received the segment label at or after the conversion itself, meaning visitors are classified by behavior the conversion produces, not behavior that predicts it. Scorer rows also carry `label_timing` (30-day window): of the converting sessions ending in this segment, how many carried the label before converting - `post_conversion_label_share` near 0 means the blended conversion_rate is trustworthy, and null label_timing means the measurement did not run (not that the segment is clean). When `expected_alignment` is set, report the number if asked but never present it as a finding, an opportunity, or evidence that the segment is high-intent, and never lead an audience report with it; its `label` says why in one sentence. null means the ordinary case, where the lift IS a finding.

no parameters
get_sessionsread

Get recent visitor sessions with behavioral signals, segment assignment, and page URLs. Useful for understanding real-time visitor behavior.

2 parameters
ParameterTypeDescription
limit
optional
numberMax results (default: 50)
segment
optional
stringFilter by segment ID
link_identifierwrite

Link a new identifier (email, phone, external_id) to a profile.

3 parameters
ParameterTypeDescription
profile_id
required
stringProfile ID
type
required
"email" | "phone" | "external_id"Identifier type
value
required
stringIdentifier value
list_dedup_candidatesread

Find profiles sharing identifiers (merge candidates for deduplication).

no parameters
list_leadsread

List captured leads (lead_captured events) for this site: contact info, scheduled appointment slot, behavioral segment, and source page.

no parameters
list_optin_formsread

List the SITE-NATIVE forms designated for opt-in lead capture. Designated forms are the only native forms the tag ever reads values from — on submit, the email (and name/phone when field selectors are designated) lands in Leads, profiles, and CRM auto-intake. Forms can also be designated config-free by adding the data-axo-optin attribute in the site's own HTML; those do NOT appear here. Use get_form_funnel to discover which native forms exist and how they perform before designating one.

no parameters
merge_profilesadmin

Merge two profiles. Moves identifiers, sessions, conversions from source to target, deletes source.

2 parameters
ParameterTypeDescription
source_id
required
stringProfile to merge FROM (deleted)
target_id
required
stringProfile to merge INTO (kept)
mint_link_tokenswrite

Mint single-use link tokens so an email sent from a third-party ESP (Klaviyo, HubSpot, Mailchimp, Braze, Salesforce Marketing Cloud) can identify the recipient on click. Give it the column the ESP list is keyed on — usually email — and it returns a merge-field column: paste axo_token (or axo_link, if you pass landing_url) into the send, and when a recipient clicks, the AXO tag on the landing page redeems it and the anonymous session merges with their known profile. Recipients with no matching profile come back under unresolved_recipients and simply get no token; their send still works, the visitor just stays anonymous. IMPORTANT: this is deterministic identity, not authentication — a forwarded email hands it to whoever opens it, so use it to personalize content, never to unlock account data, order history or PII. Tokens are single-use and expire (72h default); re-mint per send rather than reusing a column. Profiles that declined marketing consent are skipped automatically.

5 parameters
ParameterTypeDescription
recipients
required
string[]Identifier values from the ESP list, one per recipient. Max 200 per call from this tool.
identifier_type
optional
stringWhat the recipients array contains: email|email_sha256|phone|phone_sha256|external_id|profile_id. Defaults to email, the realistic ESP join key.
landing_url
optional
stringAbsolute URL the email links to. When given, each row also gets a ready-to-paste tokenized URL.
ttl_seconds
optional
numberToken lifetime. Defaults to 72h; capped at 14 days. Raise it when the send is scheduled well after the export.
format
optional
stringOutput shape: 'rows' or 'csv'. Defaults to csv, which is upload-ready.
remove_optin_formwrite

Remove a native form's opt-in capture designation by its form_selector (see list_optin_forms). The tag stops reading that form on the next config refresh; already-captured leads are unaffected.

1 parameter
ParameterTypeDescription
form_selector
required
stringform_selector of the designation to remove (exact match)
search_profilesread

Search visitor profiles by email, segment, or identification status. Returns profile list with identifiers and session counts.

4 parameters
ParameterTypeDescription
search
optional
stringSearch by email or identifier value
segment
optional
stringFilter by segment ID
identified
optional
"true" | "false"Filter by identified status
limit
optional
numberMax results (default: 50, max: 200)
unlink_identifierwrite

Remove an identifier from a profile.

2 parameters
ParameterTypeDescription
profile_id
required
stringProfile ID
identifier_id
required
stringIdentifier record ID
update_profilewrite

Update a profile segment override or lifetime signals.

3 parameters
ParameterTypeDescription
profile_id
required
stringProfile ID
segment_id
optional
string | nullOverride segment. The assignment is pinned — automatic classification will not overwrite it. Pass null to release the pin and resume automatic classification. Omit to leave the segment untouched.
lifetime_signals
optional
objectLifetime signal data
update_segmentwrite

Update a segment: rename, edit description, change emoji, visibility, or signal rules.

6 parameters
ParameterTypeDescription
id
required
stringSegment ID
display_name
optional
stringNew display name
description
optional
stringNew description
emoji
optional
stringNew emoji
visible
optional
booleanShow/hide segment
signal_rules
optional
objectNew signal rules

Placements & personalization

Author zones and variants, wire placements, and manage the render surface.

attach_asset_to_variantwrite

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.

4 parameters
ParameterTypeDescription
asset_id
required
stringAsset id from search_assets (asset_<uuid> shape).
variant_id
required
stringcontent_variants.id to attach to.
field_key
required
stringThe payload field key on the variant to overwrite (e.g. "image_url", "hero_image_url").
alt
optional
stringOptional alt text override. When omitted, the variant's existing image_alt is preserved.
author_movewrite

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.

8 parameters
ParameterTypeDescription
page_pattern
required
stringURL pattern the move applies to (e.g. "/", "/blog/*")
source_selector
required
stringCSS selector of the EXISTING element to relocate (the object to move)
dest_selector
required
stringCSS selector of the destination anchor to move it next to / into
position
optional
"before" | "after" | "inside_start" | "inside_end"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
optional
stringZone identifier. Defaults to a generated "move_*" key.
display_name
optional
stringHuman-readable name for the move.
segment_id
optional
stringAudience segment. Omit when all_visitors is true.
all_visitors
optional
booleanApply to ALL visitors regardless of segment (default true for moves). When false, provide segment_id.
clone_trigger_templatewrite

Clone a system or site template into a new site-owned template.

2 parameters
ParameterTypeDescription
template_id
required
stringSource template ID
name
optional
stringName for the clone
configure_product_recowrite

Configure a product_reco variant: choose recommendation mode (auto / curated / mixed), retrieval strategy, catalog filters, catalog weights, and pinned products. A FILTER removes items ("do not recommend anything with 10 or fewer in stock"); a WEIGHT re-ranks them without hiding them ("de-emphasise low stock"). Reach for a weight whenever the ask is to show something less rather than not at all. Call list_catalog_filter_fields first so field names are real. Use list_products to find product IDs.

8 parameters
ParameterTypeDescription
variant_id
required
stringExisting product_reco variant ID
source
required
"auto" | "curated" | "mixed"auto: Vibe Engine picks all products. curated: only show pinned product_ids. mixed: pinned products first, engine fills the rest.
strategy
optional
"session_behavior" | "bestsellers" | "new_arrivals" | "similar"Engine retrieval strategy (used when source=auto or mixed). Default session_behavior.
limit
optional
integerMax products to render (default 5).
category
optional
stringRestrict candidates to this category (case-insensitive exact match).
product_ids
optional
string[]Catalog product IDs to pin. Required when source=curated. Optional when source=mixed.
filters
optional
object[]Catalog filters, ANDed. e.g. [{"field":"inventory_quantity","op":"gt","value":10}] serves only items with more than 10 in stock. Applied to auto-ranked AND pinned items alike. Pass [] to clear.
catalog_weights
optional
object[]Catalog scoring weights. e.g. [{"field":"inventory_quantity","op":"lt","value":10,"weight":0.5}] de-emphasises nearly-sold-out items without hiding them. Weights re-rank auto-ranked recommendations and deliberately do NOT reorder curated pins, which are an ordering the operator authored by hand. Pass [] to clear.
create_campaignwrite

Create a new campaign with a brief (objective, offer, tone, themes).

7 parameters
ParameterTypeDescription
name
required
stringCampaign name
brief
optional
objectCampaign brief
status
optional
"active" | "draft" | "paused" | "archived"
starts_at
optional
stringISO-8601 start date for automated scheduling
ends_at
optional
stringISO-8601 end date for automated scheduling
eligibility
optional
objectAdvanced segment matching rules (e.g. segment_member, audience_signals)
priority
optional
numberEvaluation priority (higher = evaluated first)
create_content_variantwrite

Create a personalized content variant for a zone + segment combination. For copy_swap/hero_swap, check the zone's field_schema (get_zones) FIRST and key the payload by its payload_key/canonical_name entries — a payload sharing NO renderable key with a schema-bearing zone binds nothing and is refused with a 400 naming the accepted keys. Do not copy another variant's payload shape without checking the target zone's schema. For product_reco variants, create with an empty payload ({}) and then call configure_product_reco to set the recommendation mode and curated products.

8 parameters
ParameterTypeDescription
zone_id
required
stringZone ID
segment_id
optional
stringTarget segment ID (legacy mode, or mirrored from eligibility)
type
required
"overlay" | "hero_swap" | "copy_swap" | "product_reco" | "move_object"Variant type
payload
required
objectVariant 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
optional
objectAdvanced segment matching rules (e.g. segment_member, audience_signals)
priority
optional
numberEvaluation priority (higher = evaluated first)
campaign_id
optional
stringLink this variant to an orchestration campaign
destination_page_id
optional
stringMake this a ROUTE to an axo Page (migration 260): the CTA URL is then SERVER-derived (<pageUrl>?vt_route=<variantId>) — do not supply URL fields in the payload. Prefer create_route.
create_formwrite

Create a reusable lead-capture form template. The payload is the form design; it is copied onto each placement.

2 parameters
ParameterTypeDescription
name
required
stringInternal template name
payload
required
objectForm design: { title, cta_text, tcpa_text, success_text, accent_color, fields (subset of name/email/phone), calendar_enabled }
create_offerwrite

Create an offer in this site's library. It is ALWAYS created as an UNAPPROVED DRAFT: a human must ratify it in the dashboard (approve the terms, and attest the code exists and is active in their commerce platform) before it can ever serve. There is no `status` argument here and no tool on any surface that can make an offer live — that transition is dashboard-only, by construction. MONEY IS CENTS AND PERCENTS ARE BASIS POINTS, integers only: value_bp 2500 = 25% off, value_cents 1000 = $10 off. The write is REJECTED when the depth exceeds the site's max_discount_pct ceiling, or when it meets/exceeds the site's gross margin (every order at that depth loses money and no conversion lift can fix it). `code` must be a discount code the merchant's platform ALREADY honors — fulfillment_mode accepts only "existing_code". Returns { id, warnings }; warnings cover mirrored terms and the break-even lift this discount needs. Then place it with place_offer.

19 parameters
ParameterTypeDescription
name
required
stringInternal offer name (max 200 chars)
offer_type
required
"percent" | "fixed" | "free_shipping" | "gift" | "tiered"percent needs value_bp. fixed needs value_cents. free_shipping/gift/tiered carry no single headline value, so the depth cap and break-even hint do not apply to them.
value_bp
optional
integerPercent discount in BASIS POINTS, 0-10000 (2500 = 25.00%). Required for offer_type=percent.
value_cents
optional
integerFixed discount in CENTS (1000 = $10.00). Required for offer_type=fixed.
currency
optional
string3-letter ISO-4217 code (e.g. "USD"). Leave unset for percent / free_shipping.
code
optional
stringThe discount code AS IT EXISTS in the merchant's commerce platform. AXO never mints codes. Two live offers cannot claim the same code.
min_order_cents
optional
integerMIRRORED TERM (cents): minimum basket. Displayed as fine print and used to reason about a fixed offer's depth — their platform enforces it, and if the two disagree theirs wins.
max_discount_cents
optional
integerMIRRORED TERM (cents): cap on the discount. Displayed as fine print only; AXO never enforces it at checkout.
max_exposures_per_visitor
optional
integerThe ONE cap AXO owns and enforces: how many times we show this offer to one visitor. There is deliberately no redemption limit — that ledger belongs to the merchant's platform.
starts_at
optional
stringISO-8601 timestamp the offer becomes servable.
ends_at
optional
stringISO-8601 timestamp the offer stops serving. Must be after starts_at. Enforced at config-build time, so the offer goes dark everywhere on the next build.
stacking
optional
"exclusive" | "stackable" | "group"MIRRORED TERM, rendered as fine print ("Not combinable"). Default "exclusive". Their cart decides what actually stacks.
fulfillment_mode
optional
"existing_code"Only "existing_code" is accepted: we reference a code the merchant already honors and never mint one. Minting is deliberately deferred — it is where AXO would start competing with their loyalty platform on accounting and liability.
tiers
optional
object[]For offer_type=tiered: up to 10 entries of { min_order_cents, value_bp | value_cents }.
gift_sku
optional
stringFor offer_type=gift: the catalog SKU the merchant adds to the cart. Required for gift offers.
eligibility
optional
objectSegmentPredicate (same shape as a content variant's eligibility), so loyalty tier / lapse (crm_attribute, profile_attribute) and anonymous behavior (propensity, intent, affinity) feed ONE evaluator.
redeem_url
optional
stringWhere the offer CTA sends the visitor. Falls back to the placement's own cta_href when unset.
terms_url
optional
stringFull terms page; the renderer links it as "Terms apply".
presentation
optional
objectDefault presentation inherited by every placement: { headline, body, cta, cta_href, show_code, show_expiry }. A placement's own presentation keys win over these.
create_page_configwrite

Create a page type configuration for sitemap analysis.

3 parameters
ParameterTypeDescription
page_type
required
stringPage type (product, category, blog)
url_pattern
required
stringURL pattern to match
selectors
optional
objectCSS selectors for page elements
create_triggerwrite

Create a new triggered message. Requires name, mode (immediate|dormancy), watch_event, and at least one destination.

13 parameters
ParameterTypeDescription
name
required
stringHuman-readable name
description
optional
string
mode
required
"immediate" | "dormancy"Fire mode
watch_event
required
stringEvent type to watch
cancel_event
optional
stringEvent that cancels dormancy
criteria
optional
objectMatching criteria
delay_ms
optional
numberDormancy delay in ms
window_ms
optional
numberCancel-event window in ms
identifier_type
optional
"email" | "phone" | "device" | "external_id" | "profile_id"
destinations
required
object[]Destination configs
cooldown_per_profile_ms
optional
number
global_rate_limit_per_min
optional
number
optimization_mode
optional
"axo_bandit" | "external"Optimization mode (axo_bandit or external)
create_trigger_templatewrite

Create a new site-owned payload template for triggered messages.

5 parameters
ParameterTypeDescription
name
required
stringTemplate name
description
optional
string
format
required
"json" | "html" | "form"Template format
body
required
stringTemplate body with mustache placeholders
example_destination
optional
stringIntended destination type
create_zonewrite

Create a new personalization zone on the site. For lightbox zones (zone_key="lightbox"), pass display_rules to set when/where/who/how-often the popup fires — including country targeting (audience.country) and day/hour windows (schedule); otherwise call list_lightbox_presets and use one of those rule objects verbatim.

6 parameters
ParameterTypeDescription
page_pattern
required
stringURL pattern (e.g. "/", "/product*")
zone_key
required
stringZone identifier
display_name
required
stringHuman-readable name
element_selector
optional
stringCSS selector
position
optional
stringPosition (before/after/replace)
display_rules
optional
objectLightbox-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[], country[]}, schedule {days[], hours[], tz}, frequency {cap, n_days?, cooldown_seconds?}, suppression {after_dismiss_days?, after_convert_days?, mutual_exclusion?}. audience.country takes ISO 3166-1 alpha-2 codes ("GB", not "UK" — invalid codes are DROPPED, which turns the filter off rather than erroring, so read the saved rules back to confirm). schedule.days is 0=Sunday..6=Saturday, schedule.hours is [{start,end}] with end EXCLUSIVE and end<=start wrapping past midnight, and schedule.tz is either "visitor" (default — each visitor's own device clock, so 11-14 is everyone's lunchtime) or an IANA zone like "America/Chicago" (one real-world window everyone sees at the same instant). The API sanitizes — bad fields are dropped, not 400d. Ignored on non-lightbox zones.
delete_campaignadmin

Delete a campaign permanently.

1 parameter
ParameterTypeDescription
campaign_id
required
stringCampaign ID
delete_content_variantadmin

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.

1 parameter
ParameterTypeDescription
variant_id
required
stringVariant ID
delete_formwrite

Delete a form template. Already-deployed placements are unaffected (placements copy the payload).

1 parameter
ParameterTypeDescription
id
required
stringForm template ID
delete_offerwrite

Soft-delete an offer. It vanishes from list_offers and stops being hydrated on the next config build, but the row survives so historical per-offer lift stays attributable. Its PLACEMENTS are deliberately not deleted: they keep their offer_id, hydrate to nothing, and are dropped from tag config, so the page shows no half-resolved offer rather than a stale code — fail closed. If a slot should now carry something else, remove or repoint the placement yourself with delete_content_variant.

1 parameter
ParameterTypeDescription
id
required
stringOffer ID (from list_offers)
delete_page_configadmin

Delete a page type configuration.

1 parameter
ParameterTypeDescription
config_id
required
stringConfig ID
delete_triggeradmin

Permanently delete a trigger and its fire history.

1 parameter
ParameterTypeDescription
trigger_id
required
stringTrigger ID
delete_trigger_templateadmin

Delete a site-owned trigger payload template.

1 parameter
ParameterTypeDescription
template_id
required
stringTemplate ID
delete_zoneadmin

Delete a zone and all its content variants.

1 parameter
ParameterTypeDescription
zone_id
required
stringZone ID
draft_content_variantwrite

Use AI to generate a content variant draft for a segment + zone. Returns suggested headline, body, and CTA.

3 parameters
ParameterTypeDescription
segment_id
required
stringTarget segment
zone_key
optional
stringZone key (e.g. "hero")
variant_type
optional
"overlay" | "hero_swap" | "copy_swap"Variant type
get_optimizerread

Get the multi-armed bandit optimizer status. Shows Thompson Sampling allocation weights, which variants are winning, conversion rates per variant, and Beta distribution parameters.

no parameters
get_triggerread

Get full trigger configuration: events, dormancy, identifier type, destinations, payload templates.

1 parameter
ParameterTypeDescription
trigger_id
required
stringTrigger ID
get_trigger_templateread

Get full details of a trigger payload template.

1 parameter
ParameterTypeDescription
template_id
required
stringTemplate ID
get_zonesread

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.

1 parameter
ParameterTypeDescription
zone_id
optional
stringIf provided, return only this zone (much smaller response — use this when repairing a specific zone's field_schema)
list_campaignsread

List all campaigns for the site with status and briefs.

no parameters
list_formsread

List reusable lead-capture form templates for this site. Each has a name and a payload (title, cta_text, tcpa_text, success_text, accent_color, fields[], calendar_enabled).

no parameters
list_lightbox_presetsread

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.

no parameters
list_offersread

List this site's offer library plus the guardrail dials every offer write is validated against. Returns each non-deleted offer (name, status, offer_type, value_bp / value_cents, code, validity window, stacking, approved, code_verified_at), `site_dials` (max_discount_pct — the hard depth ceiling; gross_margin_pct — null when the operator has not configured one), and a per-offer `break_even` hint: the relative conversion lift the discount must produce just to pay for itself (d / (m - d)), null when no margin rate is set. Call this before authoring or placing anything — it is how you tell a ratified, servable offer (status "live" AND approved AND code_verified_at) from a draft that will render nothing. AXO is a SHADOW promo layer: these rows REFERENCE a discount code the merchant's own platform already honors; we never mint one and never touch redemption accounting.

no parameters
list_page_configsread

List page type configurations (product, category, blog).

no parameters
list_trigger_firesread

Get the audit log of fire attempts for a trigger: successes, errors, skipped fires with skip_reason.

2 parameters
ParameterTypeDescription
trigger_id
required
stringTrigger ID
limit
optional
numberMax rows (default 100, max 500)
list_trigger_templatesread

List available payload templates: system seeds and site-owned custom templates.

no parameters
list_triggersread

List all triggered messages for the site with watch event, mode, destinations, and enabled status.

no parameters
place_lead_formwrite

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.

5 parameters
ParameterTypeDescription
zone_id
required
stringAnchor zone to place the form relative to
segment_id
optional
stringAudience segment to show it to. Omit when all_visitors is true.
all_visitors
optional
booleanShow the form to ALL visitors regardless of segment. When true, omit segment_id.
payload
required
objectForm design payload (e.g. from a template via list_forms). Optional form_id string is sent with each capture and drives CRM funnel routing (form_routing).
position
optional
"after" | "before" | "inside_start" | "inside_end" | "replace"Where the form inserts relative to the anchor element. Default "after". "replace" takes over the anchor (legacy / dedicated containers).
place_offerwrite

Deploy an offer into a zone: creates a type="offer" content variant bound to a zone + audience. Target ONE segment via `segment_id`, OR set `all_visitors: true` to show it to EVERYONE regardless of segment (provide exactly one). The placement stores ONLY the offer_id plus presentation overrides — the economics (value, code, window, terms) are joined in from the offer row on every config build, which is what makes an offer ending at midnight go dark everywhere instead of leaving a stale code on the page. The renderer writes into the anchor zone's element, so pick a zone whose contents the offer should own (create_zone first if none exists). Two DIFFERENT offers cannot compete in one zone + audience and the write is rejected if you try: the optimizer ranks on conversion rate, so given a choice of depths it always crowns the deepest one and reports the lost margin as a win — competing arms must share one offer and vary only presentation. Placing an unapproved or non-live offer succeeds but serves nothing until a human ratifies it in the dashboard; check status/approved via list_offers first.

5 parameters
ParameterTypeDescription
offer_id
required
stringOffer to serve (from list_offers). Must belong to this site and not be deleted.
zone_id
required
stringZone whose element the offer renders into
segment_id
optional
stringAudience segment to show it to. Omit when all_visitors is true.
all_visitors
optional
booleanShow the offer to ALL visitors regardless of segment. When true, omit segment_id.
presentation
optional
objectPer-placement presentation overrides — { headline, body, cta, cta_href, show_code, show_expiry }. These win over the offer's own presentation defaults. Never put economics here: value and code come from the offer row.
restore_content_variantwrite

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.

2 parameters
ParameterTypeDescription
variant_id
required
stringVariant ID to restore
version
optional
integerHistory version to restore payload to. Omit to only un-delete.
suggest_donation_amountsread

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.

6 parameters
ParameterTypeDescription
segment_suffix
optional
stringverticals.ts segment suffix (e.g. donor_ready, high_capacity_uncontacted, lapsed_quarterly).
profile_id
optional
stringProfile to personalise off — last gift, recurring amount, capacity. CRM attributes pulled from profiles.attributes.
last_gift_amount_cents
optional
integerOverride (cents). Useful when profile data is stale or unavailable.
recurring_amount_cents
optional
integerOverride (cents). For recurring_card_declined the ladder surfaces ONLY this amount.
lifetime_giving_cents
optional
integerOverride (cents). Elevates the high-capacity ladder when ≥ $10k.
capacity_score
optional
numberOverride (0..1). Elevates the high-capacity ladder when ≥ 0.9.
test_fire_triggerwrite

Fire a trigger against a test target, bypassing cooldown/rate limits. Goes through the real dispatch pipeline — WILL send real email/SMS.

4 parameters
ParameterTypeDescription
trigger_id
required
stringTrigger ID
profile_id
optional
stringProfile ID
identifier
optional
objectTest target identifier
event_properties
optional
objectOverride event properties
update_campaignwrite

Update a campaign name, brief, or status.

8 parameters
ParameterTypeDescription
campaign_id
required
stringCampaign ID
name
optional
string
brief
optional
object
status
optional
"active" | "draft" | "paused" | "archived"
starts_at
optional
string | null
ends_at
optional
string | null
eligibility
optional
object | null
priority
optional
number
update_content_variantwrite

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. When replacing a copy_swap/hero_swap payload, read-modify-write against the zone's field_schema keys — a re-keyed payload sharing NO renderable key with the zone is refused with a 400 naming the accepted keys.

9 parameters
ParameterTypeDescription
variant_id
required
stringVariant ID
payload
optional
objectUpdated payload
active
optional
booleanEnable/disable
type
optional
"overlay" | "hero_swap" | "copy_swap" | "product_reco" | "move_object"
eligibility
optional
object
priority
optional
number
segment_id
optional
string
campaign_id
optional
string | null
destination_page_id
optional
string | nullRe-point the route at another page, or null to clear it (strips the vt_route attribution param). On a routed variant the CTA URL stays server-derived; activating re-validates the destination is published.
update_formwrite

Update a form template name and/or payload.

3 parameters
ParameterTypeDescription
id
required
stringForm template ID
name
optional
stringNew name
payload
optional
objectUpdated form design
update_offerwrite

Update an offer's terms, or move it between draft / paused / archived. `status` accepts ONLY those three. "live" is a dashboard-only transition gated on human approval plus code verification, and it is refused outright on the API-key path that every agent surface authenticates with — so you CAN pause or archive an offer that is misbehaving, and you CANNOT start one. Ask the operator to approve it in the dashboard instead. Editing the economics (offer_type, value_bp, value_cents, currency, tiers, gift_sku, code) UN-RATIFIES the offer and it stops serving until a human re-approves: approval attaches to specific terms, not to a row id, so a 10%-off offer approved yesterday can never silently become 40% off today — the response reports `approval_reset`. Changing `code` also clears the code verification. Same units and guardrails as create_offer (cents, basis points, the site depth ceiling, the margin floor). OMITTING a field leaves it untouched; sending it as NULL REMOVES it, which is how you make a promo open-ended (ends_at: null = runs indefinitely) or drop a threshold, a cap or a link. Only starts_at, ends_at, min_order_cents, max_discount_cents, max_exposures_per_visitor, code, redeem_url and terms_url accept null — null on anything else is rejected rather than ignored, so a mistaken null never silently no-ops. The response echoes what you removed as `cleared`.

20 parameters
ParameterTypeDescription
id
required
stringOffer ID (from list_offers)
status
optional
"draft" | "paused" | "archived"draft | paused | archived only. "live" is dashboard-only and is rejected on this path — no agent tool can make an offer servable.
name
optional
stringNew internal name (max 200 chars)
offer_type
optional
"percent" | "fixed" | "free_shipping" | "gift" | "tiered"Changing this un-ratifies the offer.
value_bp
optional
integerPercent discount in BASIS POINTS, 0-10000 (2500 = 25.00%). Changing it un-ratifies the offer.
value_cents
optional
integerFixed discount in CENTS. Changing it un-ratifies the offer.
currency
optional
string3-letter ISO-4217 code. Changing it un-ratifies the offer.
code
optional
string | nullDiscount code as it exists in the merchant's platform. Changing it un-ratifies the offer AND clears code_verified_at, so a human must re-verify it. null removes the code — do this only for an offer that needs none (an automatic discount, a free-shipping threshold), because a code-less offer CANNOT be verified and so cannot go live again until a code is set.
min_order_cents
optional
integer | nullMIRRORED TERM (cents) — fine print only; their platform enforces it. null removes the minimum-spend threshold.
max_discount_cents
optional
integer | nullMIRRORED TERM (cents) — fine print only; their platform enforces it. null removes the cap.
max_exposures_per_visitor
optional
integer | nullHow many times WE show it to one visitor — the only cap AXO enforces. null uncaps it.
starts_at
optional
string | nullISO-8601 start of the validity window. null removes the start date, so it is valid from now.
ends_at
optional
string | nullISO-8601 end of the validity window; must be after starts_at. null removes the end date, so the offer runs INDEFINITELY until someone pauses it — the only way to express an open-ended promo.
stacking
optional
"exclusive" | "stackable" | "group"MIRRORED TERM rendered as fine print.
tiers
optional
object[]Tier ladder for offer_type=tiered (max 10). Changing it un-ratifies the offer.
gift_sku
optional
stringGift SKU for offer_type=gift. Changing it un-ratifies the offer.
eligibility
optional
objectSegmentPredicate gating who the offer is valid for.
redeem_url
optional
string | nullWhere the offer CTA sends the visitor. null removes it.
terms_url
optional
string | nullFull terms page. null removes it.
presentation
optional
objectDefault presentation inherited by placements: { headline, body, cta, cta_href, show_code, show_expiry }.
update_page_configwrite

Update a page type configuration.

3 parameters
ParameterTypeDescription
config_id
required
stringConfig ID
url_pattern
optional
stringUpdated URL pattern
selectors
optional
objectUpdated selectors
update_triggerwrite

Update an existing trigger. Pass only the fields to change.

15 parameters
ParameterTypeDescription
trigger_id
required
stringTrigger ID
name
optional
string
description
optional
string
enabled
optional
boolean
mode
optional
"immediate" | "dormancy"
watch_event
optional
string
cancel_event
optional
string
criteria
optional
object
delay_ms
optional
number
window_ms
optional
number
identifier_type
optional
string
destinations
optional
object[]
cooldown_per_profile_ms
optional
number
global_rate_limit_per_min
optional
number
optimization_mode
optional
"axo_bandit" | "external"Optimization mode
update_trigger_templatewrite

Update a site-owned trigger payload template.

6 parameters
ParameterTypeDescription
template_id
required
stringTemplate ID
name
optional
string
description
optional
string
format
optional
"json" | "html" | "form"
body
optional
string
example_destination
optional
string
update_zonewrite

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.

7 parameters
ParameterTypeDescription
zone_id
required
stringZone ID
display_name
optional
string
element_selector
optional
string
approved
optional
boolean
priority
optional
number
display_rules
optional
objectLightbox display rules — same shape as create_zone.display_rules (incl. audience.country ISO 3166-1 alpha-2 and schedule {days, hours, tz}). Send the full object to overwrite; omit to leave unchanged. Sanitized at the API — invalid country codes and unresolvable timezones are dropped silently, so read the zone back if the targeting matters.
field_schema
optional
object[]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.

approve_pagewrite

Approve the current revision (preview → approved). Precondition for publish_page; still not public.

1 parameter
ParameterTypeDescription
page_id
required
stringPage ID
approve_page_suggestionwrite

Accept a page suggestion: creates an UNPUBLISHED draft page from the proposed brief. Pass amendments to extend the brief. Generate and publish are separate steps.

2 parameters
ParameterTypeDescription
suggestion_id
required
stringSuggestion (proposal) ID from list_page_suggestions
amendments
optional
stringOperator additions merged into the brief before generation
create_pagewrite

Create a draft page from an operator-stated goal (no suggestion needed). target is the question the page must answer. Returns the draft; call generate_page next.

6 parameters
ParameterTypeDescription
archetype
required
"faq" | "comparison" | "guide" | "landing"Page archetype
target
required
stringThe question/demand signal the page answers
outline
optional
string[]Optional section outline (defaults per archetype)
tone
optional
stringOptional tone override
slug
optional
stringOptional URL slug. May be a nested path like "blog/spring/launch" (max 5 segments) — folders are implicit, derived from the /s.
cta
optional
objectOptional primary CTA: { label, href, fires_event? }
create_routewrite

Route the right visitor to a published axo Page: creates an entry-point variant (copy_swap/hero_swap) whose CTA the server points at the page (<pageUrl>?vt_route=<variantId> — the attribution join key; never supply URL fields yourself). Rides the full variant machinery: campaign flight window + audience AND-composition via campaign_id, eligibility/segment targeting, priority, per-visitor holdout, lift. Called WITHOUT zone_id it returns needs_zone with candidate zones — pick the one whose page_pattern covers where the audience lands (only zones whose schema carries a url field can host a route). An approved-but-unpublished destination is allowed only with active=false (the suggestion-loop shape); publishing the page re-stamps the href.

9 parameters
ParameterTypeDescription
page_id
required
stringDestination axo Page ID (published; or approved when active=false)
zone_id
optional
stringHosting zone — omit to get needs_zone candidates
type
optional
"hero_swap" | "copy_swap"Entry variant type (default hero_swap)
segment_id
optional
stringTarget segment (omit with eligibility for predicate targeting; omit both = everyone)
eligibility
optional
objectSegmentPredicate audience (alternative to segment_id)
campaign_id
optional
stringCampaign umbrella: flight window, campaign audience AND-composition, campaign priority
priority
optional
numberServe priority among competing variants
active
optional
booleanDefault true. false = author the route dark (required for approved-but-unpublished destinations)
payload
optional
objectEntry copy (headline, cta text…) — the CTA URL itself is server-derived
dismiss_page_suggestionwrite

Dismiss a page suggestion. The underlying gap stays quiet for the cool-off window.

1 parameter
ParameterTypeDescription
suggestion_id
required
stringSuggestion (proposal) ID
generate_pagewrite

Render a revision of a page from its brief. SLOW: takes 60-120s or more — wait for it. With feedback, regenerates applying it — feedback accumulates, so every regeneration honors all prior feedback. Returns the preview URL. Costs AI budget. A 409 generation_in_flight means a render is already running: do NOT retry — poll get_page for a new revision; if none appears within 6 minutes the lease has expired and one retry is safe.

2 parameters
ParameterTypeDescription
page_id
required
stringPage ID
feedback
optional
stringNatural-language revision request
get_contentread

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.

1 parameter
ParameterTypeDescription
zone_id
optional
stringIf provided, return only variants for this zone (much smaller response — use this when working on a specific zone)
get_content_historyread

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.

1 parameter
ParameterTypeDescription
variant_id
required
stringVariant ID to inspect
get_pageread

One page in full: brief, revision history, publications, shareable preview URL (pre-publish, noindex) and the public URL when published.

1 parameter
ParameterTypeDescription
page_id
required
stringPage ID
get_route_performanceread

The OBSERVED route funnel per route (shown → routed_sessions via vt_route → destination conversions), descriptive not causal — filter by variant_id or campaign_id (the campaign rollup), days 1-90 (default 30). For the CAUSAL number use get_variant_performance: a route is an ordinary variant to the holdout lift lane.

3 parameters
ParameterTypeDescription
variant_id
optional
stringOne route
campaign_id
optional
stringAll routes under a campaign — the campaign rollup
days
optional
numberWindow in days, 1-90 (default 30)
import-claude-design-from-urlwrite

Import a design into axo from a publicly fetchable URL. The file is a self-contained HTML bundle with all images, fonts, and styles inlined.

3 parameters
ParameterTypeDescription
url
required
stringPublic HTTPS URL to the design file. Valid for ~1 hour. Fetched server-side.
claude_design_project_id
optional
stringStable Claude Design project identifier. Reuse it to update the same imported axo page.
title
optional
stringSuggested title for the imported design.
list_content_sourcesread

List captured content-backlog sources for the blog pipeline. Filter by status (new/used/skipped) and recency.

2 parameters
ParameterTypeDescription
status
optional
"new" | "used" | "skipped"Default: new
days
optional
numberLook-back window in days (default 30)
list_page_suggestionsread

List suggested pages for this site — each an answer-engine visibility gap (a question no engine answers with this brand) with evidence and a proposed archetype + outline. Accepting creates an unpublished draft; nothing publishes itself.

no parameters
list_pagesread

List generated pages for this site with status (draft, preview, approved, published, retired).

1 parameter
ParameterTypeDescription
status
optional
stringOptional status filter
list_routesread

Every route on the site: entry variant, hosting zone, audience, campaign (name/status), destination page, and health — destination_published=false flags a route whose page will 404.

no parameters
log_articlewrite

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.

4 parameters
ParameterTypeDescription
url
optional
stringLink to the article/source (optional if note is given)
title
optional
stringTitle of the article (optional)
note
optional
stringYour angle: why this is interesting, what point it supports (optional if url is given)
tags
optional
string[]Freeform tags, e.g. ["agentic", "segmentation"]
publish_pagewrite

PUBLISH a page — the one action that makes it public and indexable, at /p/<site>/<slug> (axo_hosted), or at https://<custom-domain>/<slug> (custom_subdomain, needs a live page domain).

2 parameters
ParameterTypeDescription
page_id
required
stringPage ID
adapter
optional
"axo_hosted" | "custom_subdomain"Delivery adapter. custom_subdomain serves at https://<your-domain>/<slug> and requires a live page domain (add_page_domain).
rename_pagewrite

Rename/move an UNPUBLISHED page (draft, preview, or approved) to a new slug/path — the recovery for a typo'd folder. May be a nested path like "blog/spring/launch" (max 5 segments). Refused once the page is published or retired: the slug is write-once after publish. 409 slug_taken means another page holds that path — pick a different one. Preview links survive a rename.

2 parameters
ParameterTypeDescription
page_id
required
stringPage ID
slug
required
stringNew slug/path, e.g. "blog/spring/launch"
retire_pagewrite

Retire a page: unpublishes any live publication and ends its lifecycle. History is kept.

1 parameter
ParameterTypeDescription
page_id
required
stringPage ID

Catalog & recommendations

Import products, manage the taxonomy, and configure recommendation zones.

get_catalog_import_statusread

Get the status and list of imported products in the catalog.

no parameters
get_content_mapread

The content-site counterpart of list_products: what the crawl understands about a site, grouped section (first URL path segment) → page type, with 30-day engagement per section. Pass `section` to list that section's pages (title, URL, page type, AI summary, meta description, h1, categories, personalization hooks, curation state). Works for any archetype; most useful on non-ecommerce (B2B, lead-gen, content) sites.

3 parameters
ParameterTypeDescription
section
optional
stringSection name to drill into (optional — omit for the sections rollup)
limit
optional
numberMax pages when drilling into a section (default 100, max 500)
offset
optional
numberPagination offset for the section drill-down (default 0)
get_site_taxonomyread

Retrieve the parsed taxonomy mapping representing the site hierarchy.

no parameters
import_catalogwrite

Import products into the product catalog. `url` must point at the product-detail page — it is the natural key, and rows without one are skipped. `inventory_quantity` is the only real stock number the system holds and is what makes rules like "don't recommend items with 10 or fewer in stock" expressible (see configure_product_reco filters).

1 parameter
ParameterTypeDescription
products
required
object[]Array of products to import
list_catalog_filter_fieldsread

What can recommendations be filtered or weighted on? Returns every product_catalog column an operator may write a predicate against, READ FROM THE LIVE SCHEMA (so a column added by a recent migration is listed the day it exists), plus the operator list, the weight multiplier range, and the missing-value rules for filters and weights (which differ). Call this before configure_product_reco filters or catalog_weights so field names, ops and multipliers are real rather than guessed.

no parameters
list_productsread

Search and list catalog products/items for a site. Allows filtering by category, specific product IDs, or including ignored items.

4 parameters
ParameterTypeDescription
ids
optional
string[]Array of specific product IDs to fetch (optional)
category
optional
stringFilter by category (optional)
include_ignored
optional
booleanIf true, include ignored products in the output (default false)
limit
optional
numberMax results (default 100, max 500)
list_reco_presetsread

Ready-made recommendation rules — exclude out of stock, de-emphasise low stock, exclude discontinued, rating floor, require a product image, and so on. This is the answer to "what can I filter on" for someone who does not already know: a list rather than a schema. Each preset returns the LITERAL filters and catalog_weights it would write, plus an impact preview measured against this site's own catalog — how many items it would drop, how many it would re-rank, and which referenced columns have no data at all (a rule on an unpopulated column changes nothing, which is worth saying before it is applied rather than after). Apply one by passing its filters / catalog_weights verbatim to configure_product_reco; there is no one-word apply on purpose. State the rules and the impact to the operator before applying them. A preset naming a column this catalog does not have comes back with available:false and the reason.

no parameters
list_taxonomy_termsread

List the site's taxonomy terms — the brand/topic/category vocabulary that drives per-visitor interest/affinity scoring. Optionally filter by dimension.

1 parameter
ParameterTypeDescription
dimension
optional
"brand" | "topic" | "category"Filter to one dimension
merge_categorieswrite

Merge and rename product categories (renames a category across all products in sitemap and page profiles).

2 parameters
ParameterTypeDescription
old_category
required
stringCurrent category name to rename
new_category
required
stringNew category name
reclassify_catalog_itemwrite

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.

8 parameters
ParameterTypeDescription
item_id
required
stringCatalog product UUID
category
optional
stringNew category name (optional)
name
optional
stringNew product name (optional)
brand
optional
stringNew brand name (optional)
description
optional
stringNew product description (optional)
sku
optional
stringNew SKU (optional)
price
optional
stringNew price (optional)
ignored
optional
booleanSet to true to ignore the product, false to restore (optional)
reclassify_pagewrite

Curate one content-map page (the page_profiles counterpart of reclassify_catalog_item): override its page type or section (null restores the crawl/derived value), or set ignored to hide it from the content map and reco candidates.

4 parameters
ParameterTypeDescription
page_id
required
stringPage profile ID (from get_content_map's section drill-down)
page_type_override
optional
string | nullNew page type, e.g. pricing, docs, service, article (optional; null clears the override)
section_override
optional
string | nullNew section name (optional; null clears the override)
ignored
optional
booleantrue to hide the page from the content map, false to restore (optional)
rename_sectionwrite

Rename a content-map section across the site's pages (writes a curation override; re-crawls never undo it). Merging two sections is the same operation: rename A to B and A's pages join B's bucket.

2 parameters
ParameterTypeDescription
old_section
required
stringCurrent section name
new_section
required
stringNew section name (lowercased on save)

Assets & brand

Generate images, manage the DAM, and extract brand guidelines.

extract_brand_guidelineswrite

Extract brand colors directly from the live homepage (meta theme-color, CSS custom properties, button styles). Pass persist:true to save the detected colors into the site's brand settings — fills only colors that are currently unset, never overwrites operator-chosen values.

1 parameter
ParameterTypeDescription
persist
optional
booleanSave detected colors to brand settings (fills unset colors only; default false)
generate_imagewrite

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.

11 parameters
ParameterTypeDescription
provider
required
"gemini" | "openai" | "firefly"BYOK provider. The site must have active credentials saved for it.
prompt
required
stringWhat to generate (max 4000 chars).
model
optional
stringOptional provider model id (e.g. "imagen-4.0-generate-001", "gpt-image-1"). Omit for the provider default.
width
optional
integerOptional pixel width.
height
optional
integerOptional pixel height.
negative_prompt
optional
stringOptional — things to avoid in the image.
use_brief
optional
booleanWhen true, prepend brand voice + active campaign brief context. Default false.
zone_key
optional
stringOptional zone hint (e.g. "hero") woven into the prompt.
variant_type
optional
stringOptional variant-type hint (overlay | hero_swap | copy_swap).
reference_images
optional
object[]Optional reference images (subject/style). Requires experimental_creative_enabled.
plan_with_claude
optional
booleanWhen true, Claude drafts a detailed shot prompt before dispatch. Requires experimental_creative_enabled. Default false.
get_assetread

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.

1 parameter
ParameterTypeDescription
asset_id
required
stringAsset id (asset_<uuid> shape).
import_figma_brandwrite

Import and configure site brand definitions from a Figma file URL.

1 parameter
ParameterTypeDescription
figma_url
required
stringURL to the Figma file/component
list_dam_connectionsread

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.

no parameters
list_image_gen_keysread

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.

no parameters
list_text_gen_keysread

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.

no parameters
register_dam_assetwrite

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_<uuid> 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.

7 parameters
ParameterTypeDescription
provider
required
stringVendor id from the search_dam hit ("cloudinary" | "s3_compatible").
dam_asset_id
required
stringVendor-side id from the hit (Cloudinary public_id, S3 key).
external_url
required
stringPublic URL from the hit (Cloudinary secure_url, S3 public URL).
mime_type
optional
stringOptional, defaults to image/png.
width
optional
numberOptional pixel width.
height
optional
numberOptional pixel height.
name
optional
stringOptional display name for the AXO library. Defaults to the asset id.
search_assetsread

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.

6 parameters
ParameterTypeDescription
q
optional
stringText match against name + prompt (ILIKE).
subject
optional
stringExact match on tags.subject (e.g. "kitchen").
theme
optional
stringTag in tags.themes (e.g. "minimalist").
provider
optional
"gemini" | "openai" | "firefly"
include_archived
optional
boolean
limit
optional
integerDefault 20.
search_damread

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.

5 parameters
ParameterTypeDescription
q
optional
stringFree-text query — matched against filename, public_id, and tag values.
folder
optional
stringRestrict to a folder/prefix (e.g. "axo/franken-store-com").
tags
optional
string[]Restrict to assets carrying ALL of these tags (Cloudinary only — S3 ignores).
limit
optional
numberDefault 30, max 100.
provider
optional
stringOptional provider scope ("cloudinary" | "s3_compatible"). When omitted, uses the site's first active DAM connection.
update_assetwrite

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.

4 parameters
ParameterTypeDescription
asset_id
required
stringAsset id (asset_<uuid> shape).
name
optional
stringNew display name (max 200 chars).
tags
optional
objectReplacement tags object. Overwrites the existing tags.
archived
optional
booleantrue to archive (soft-delete / hide from search), false to restore.

Integrations & sync

Connect destinations, test them, and sync CRM/Salesforce data.

create_integrationwrite

Create a new integration (klaviyo, braze, resend, webhook, meta_capi, google_capi, google_ads_ec, …).

4 parameters
ParameterTypeDescription
type
required
stringIntegration type
config
required
objectConfig (API keys, endpoints)
events
optional
string[]Events to fire on
active
optional
booleanEnable immediately
delete_integrationadmin

Delete an integration permanently.

1 parameter
ParameterTypeDescription
integration_id
required
stringIntegration ID
get_integrationread

Get full config for a single integration.

1 parameter
ParameterTypeDescription
integration_id
required
stringIntegration ID
get_integration_logsread

Recent fire log for an integration with success/error stats.

2 parameters
ParameterTypeDescription
integration_id
required
stringIntegration ID
limit
optional
numberMax rows (default 50)
list_integrationsread

List all integrations (Klaviyo, Braze, Resend, webhooks, CAPI) with status.

no parameters
sync_crmwrite

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.

2 parameters
ParameterTypeDescription
records
required
object[]Array of CRM records to sync (max 1000)
source
optional
stringSource label (e.g. "salesforce", "hubspot")
test_integrationwrite

Send a test payload to an integration to verify the connection works.

1 parameter
ParameterTypeDescription
integration_id
required
stringIntegration ID
update_integrationwrite

Update integration config, events, or active status.

4 parameters
ParameterTypeDescription
integration_id
required
stringIntegration ID
config
optional
object
events
optional
string[]
active
optional
boolean

Site & configuration

Site config, verticals, taxonomy, sitemap health, and page configs.

add_page_domainwrite

Start custom-domain onboarding for generated pages: the customer's subdomain (e.g. learn.brand.com) will serve published pages on THEIR domain. Returns DNS instructions: first an ownership TXT record, then a CNAME. Subdomains only (no apex). One domain per site.

1 parameter
ParameterTypeDescription
hostname
required
stringSubdomain to attach, e.g. learn.your-domain.com
analyze_sitemapwrite

Analyze a semantic sitemap structure to optimize category mapping internally.

1 parameter
ParameterTypeDescription
options
optional
objectConfiguration/tuning options for the analysis run
apply_vertical_packwrite

Switch the current site to a vertical pack: seeds any missing segments/zones/variants and RETIRES the previous composition's pack segments (visible=false — out of the tag's scoring rules and dashboard lists; reversible, history kept, re-applying the old pack restores them). Existing customizations and archetype extensions are preserved unless archetype_extensions is passed explicitly (omit to keep, [] to clear). To ADD a pack alongside the current one instead of switching, include it in archetype_extensions rather than changing vertical. Re-applying the site's current vertical is a safe no-op refresh.

2 parameters
ParameterTypeDescription
vertical
required
"ecommerce" | "home_services" | "saas" | "financial" | "healthcare" | "nonprofit" | "affiliate" | "content_media"
archetype_extensions
optional
string[]Secondary archetype ids layered on top of the primary (e.g. ["ecommerce"] on a content site). Omit to keep the site's current extensions; pass [] to clear.
define_affinity_termswrite

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"] }.

1 parameter
ParameterTypeDescription
terms
required
object[]Terms to upsert
detect_tracking_paramswrite

PROPOSE (never apply) site-specific query params for extra_tracking_params, from the site's own recent pageviews. Returns proposals with the evidence behind each — occurrences, share of the sample, distinct-value churn, whether any value ever reached a second session, path spread, redacted sample values — plus every observed param it did NOT propose and the rule that stopped it. Two bases: `known_vendor` (a named product's per-click/session token such as Awin's awc or PHPSESSID, proposed on sight) and `traffic_evidence` (cleared every floor on this site's own traffic). A site with too little traffic reports status "insufficient_evidence" and makes NO evidence-based proposal rather than guessing on thin data. This tool CANNOT change page identity: to apply, call update_site_config with the FULL extra_tracking_params list (existing entries plus the accepted ones). CAUTION before applying: declaring a param that genuinely distinguishes pages merges those pages into one page identity, silently and unrecoverably. The detector deliberately under-proposes, so a param it held back was held back on purpose.

1 parameter
ParameterTypeDescription
window_days
optional
integerTrailing days of pageviews to sample (default 30, capped at 90). Values above the cap are clamped, not rejected.
discover_sitemapwrite

Discover and map semantic URLs from the site, identifying structure automatically.

1 parameter
ParameterTypeDescription
url
optional
stringForce extraction starting from a specific URL
get_page_domainread

The site's custom page-domain status (awaiting_ownership → awaiting_dns → cert_pending → live) with the exact DNS records to add. Calling this re-checks DNS/SSL state, so it doubles as "check again".

no parameters
get_site_configread

Get current site configuration: brand, mode, conversion goal, settings.

no parameters
get_vertical_packread

Get the full contents of a vertical pack (segments, zones, variants) before applying it.

1 parameter
ParameterTypeDescription
vertical
required
"ecommerce" | "home_services" | "saas" | "financial" | "healthcare" | "nonprofit" | "affiliate" | "content_media"
list_aeo_findingsread

List answer-engine visibility findings for this site: blocked AI crawlers, missing structured data, prompts no engine answers with your brand, third-party sources the engines keep citing instead. Ranked worst-first.

4 parameters
ParameterTypeDescription
status
optional
stringComma-separated: open, acknowledged, resolved, wont_fix
category
optional
stringComma-separated finding categories
severity
optional
stringComma-separated: low, medium, high, critical
limit
optional
numberMaximum findings to return (default 100, max 500)
list_verticalsread

List available industry vertical packs (ecommerce, home_services, saas, financial, healthcare, nonprofit, affiliate, content_media). Each pack bundles default segments, zones, and variants tailored to that industry.

no parameters
remove_page_domainwrite

Remove the custom page domain: detaches it from serving (pages published to it stop resolving). The hostname stays reserved so it cannot be hijacked while the CNAME lingers.

no parameters
resolve_aeo_findingwrite

Move a finding: acknowledge it, mark it resolved, mark it won't fix, or reopen it. Won't-fix is sticky - a re-observation will never reopen it, only an explicit reopen will.

2 parameters
ParameterTypeDescription
finding_id
required
stringFinding ID
action
required
"acknowledge" | "resolve" | "wont_fix" | "reopen"What to do with it
run_aeo_auditwrite

Start a read-only audit of this site's own public surface - robots.txt, llms.txt, sitemap and a sample of pages - and derive findings from it. Costs nothing: no answer engines are queried.

no parameters
update_site_configwrite

Update site settings: identity (name/domain), brand, mode, conversion goal(s), zone overlap mode, holdouts, passive_mode, anti-flicker dials, activation-orchestrator rollout. Only the fields you pass are touched. `network_contribution` is an OPT-IN to the cross-site observation graph (the site-blind, PII-free IP→company lane — never fed by profiles/emails/form fills), DEFAULT OFF: pass `true` only with the customer's actual agreement, and `false` to withdraw, which also scrubs already-annotated sessions. Pass `goals` (array) to FULL-REPLACE the typed multi-goal list — primary + optional supporting goals; read the current list via get_site_config first since omitted goals are deleted. `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. Anti-flicker dials: check get_flicker_health first and rule out binding failures (a wrong selector produces the same visible-swap signature); every dial write echoes the holdout-wait tradeoff in the response. `business_brief` records what the operator told you about their business and grounds every AI copy draft — note its facts/beliefs split, which is load-bearing.

27 parameters
ParameterTypeDescription
name
optional
stringSite display name
domain
optional
stringSite domain (empty string clears)
mode
optional
"active" | "backtest"
conversion_goal
optional
string
goals
optional
object[]
brand_primary
optional
string
brand_accent
optional
string
brand_font
optional
string
brand_radius
optional
string
brand_headline_color
optional
string
brand_body_color
optional
string
brand_bg_color
optional
string
brand_backdrop_opacity
optional
stringOverlay backdrop opacity 0-1 (e.g. "0.45")
brand_cta_radius
optional
string
zone_overlap_mode
optional
"all" | "first"
disable_holdout
optional
boolean
holdout_pct
optional
integer
trigger_holdout_pct
optional
integer | nullTrigger-specific holdout 0-90, or null to inherit holdout_pct
passive_mode
optional
boolean
network_contribution
optional
booleanPer-site OPT-IN to the cross-site observation graph. Default OFF — omit to leave unchanged; a missing flag reads as NOT contributing, and only an explicit true opts a site in. Governs ONLY the shared IP-prefix→company-domain lane: a site-blind, PII-free firmographic signal (truncated /24–/48 network prefixes, carrying no site_id, visitor id, full IP, URL, or any form/identity data). Identified profiles, emails, and captured form fills NEVER feed this graph regardless of this flag. Set true ONLY when the customer has actually agreed to pool their observed company traffic — never as a default or a convenience; what they get back today is that companies seen on their site are queued for firmographic enrichment ahead of a lookup, and nothing reads the shared dataset back yet. Turning it on is NOT retroactive: it applies only to traffic collected from that point on. Set false to withdraw; that write also retroactively scrubs already-annotated sessions so a rollup running after the flip cannot harvest pre-flip data. Independent of passive_mode, which suppresses all contribution while it is on regardless of this flag.
antiflicker_strategy
optional
"cookie" | "always" | "never"Anti-flicker pre-hide strategy. Platform default "always" matches Adobe Target / Optimize / VWO.
antiflicker_wait_selectors
optional
string[]CSS selectors the reveal waits for before un-hiding. Pair the zone's own selector with the tag's apply stamp (e.g. '.hero-section[data-axo-applied]' — the tag sets data-axo-applied on every element it personalizes). CAUTION: a selector that never matches holds the page hidden for the full max_hide_ms on every load — verify the base selector exists on the live page first. "*"/"html"/"body" are rejected.
antiflicker_max_hide_ms
optional
number | nullSafety-timer reveal budget in ms (default 3000, hard cap 8000; null resets to default). TRADEOFF: holdout visitors and no-segment-match visitors wait this full budget before the safety reveal.
orchestrator_mode
optional
"off" | "shadow" | "enabled"Activation-orchestrator rollout: off = triggers fire independently, shadow = decisions logged but not enforced, enabled = orchestrator allocates trigger fires
cadence_ceiling_per_24h
optional
integerMax orchestrated trigger fires per visitor per 24h (default 1)
extra_tracking_params
optional
string[]Site-specific query params treated as tracking-only for page identity, ON TOP of the global blocklist (fbclid/gclid/utm_* are always stripped). Declare params this site's stack appends per click/submit without changing page content — e.g. Episerver Forms' __FormGuid/__FormLanguage/__FormSubmissionId, DSP auction ids like cntr_auctionId. Symptom that calls for this: Catalog page counts ballooning with near-duplicate URLs differing only in one param. FULL-REPLACE array, max 50 names (read get_site_config first); [] clears. CAUTION: never list content-bearing params (?page=, ?q=, ?variant=) — their pages would collapse into one Catalog entry.
business_brief
optional
object | nullWhat the operator told us about their business (#1437), used to ground AI-drafted copy. FULL-REPLACE object — read get_site_config first and pass the complete brief, since anything omitted is deleted; null clears it entirely. Caps: each string <=400 chars, each list <=8 entries, whole object <=6KB. The two halves are NOT interchangeable: • facts — things we cannot check and have no business checking: what they sell, who buys, their vocabulary, proof points, phrases legal forbids. Composed into every AI copy generation. • beliefs — falsifiable claims about behaviour ("our best leads visit after 5pm"). STORED AND SHOWN BUT DELIBERATELY WITHHELD FROM EVERY PROMPT until they can be measured. Do not restate a belief as a fact to make it take effect; that is the exact failure this split exists to prevent. When a claim carries a motive we could never verify ("because they are frustrated at work"), put that clause in the belief's not_tested field rather than dropping it.

CRM & pipeline

Manage the customer-facing sales pipeline: opportunities, contacts, tasks.

get_crm_statusread

Get CRM sync history and enrichment statistics. Shows how many profiles have CRM attributes, total enrichment coverage, and recent sync logs.

no parameters
get_salesforce_statusread

Get Salesforce integration status, sync history, and coverage stats. Shows connection state, recent syncs, and how many profiles are enriched from Salesforce.

no parameters
get_target_account_matchesread

Which target accounts VISITED the site: cross-references saved company lists (TALs) against sessions whose visitor IP resolved to a company, returning per-account session counts and last-seen. Defaults to every list over the last 30 days; pass list_id and/or days to narrow. A match means an outbound target is now inbound — surface it, and ratify it into the pipeline with pipeline_create_opportunity.

2 parameters
ParameterTypeDescription
list_id
optional
stringMatch a single list (default: all lists on the site)
days
optional
numberObservation window in days, 1-90 (default 30)
import_target_accountswrite

Import a target-account list (TAL) from an external prospecting tool — e.g. an Apollo accounts export — as a saved company list. Provide domains[] and/or paste raw export text as csv: anything domain-shaped is extracted (website URLs, bare domains, the company domain of corporate emails), free-mail domains are dropped, and everything is deduped. Requires the Company Graph module. After importing, use get_target_account_matches to see which target accounts are visiting the site.

4 parameters
ParameterTypeDescription
name
required
stringName for the list, e.g. "Apollo — Q3 outbound"
domains
optional
string[]Company domains or website URLs, one per target account.
csv
optional
stringRaw pasted export (CSV or newline list). No column mapping needed — domains are extracted from anything domain-shaped.
source
optional
stringProvenance slug recorded on the list, e.g. 'apollo'. Defaults to 'csv' when csv text was parsed, else 'import'.
pipeline_add_contactwrite

Add a contact (name, email, phone, role) to a CRM opportunity. Set is_primary to make them the headline contact.

7 parameters
ParameterTypeDescription
opportunity_id
required
stringThe opportunity id (opp_…)
name
required
stringContact full name
email
optional
stringEmail address
phone
optional
stringPhone number
role
optional
stringRole, e.g. "Owner"
is_primary
optional
booleanMake this the primary contact
site_id
optional
stringRequired on cross-site super-admin sessions: which SITE names the target account (the pipeline is account-scoped; the account is resolved from the site). Discover ids via get_account_status. Ignored on site-scoped sessions, which always work their own account.
pipeline_add_notewrite

Append a note to a CRM opportunity's activity timeline (append-only): call summaries, next steps, observations.

3 parameters
ParameterTypeDescription
opportunity_id
required
stringThe opportunity id (opp_…)
body
required
stringThe note text (max 10k chars)
site_id
optional
stringRequired on cross-site super-admin sessions: which SITE names the target account (the pipeline is account-scoped; the account is resolved from the site). Discover ids via get_account_status. Ignored on site-scoped sessions, which always work their own account.
pipeline_add_taskwrite

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.

5 parameters
ParameterTypeDescription
opportunity_id
required
stringThe opportunity id (opp_…)
title
required
stringWhat needs doing, imperative, ≤200 chars — e.g. "Send revised quote"
due_date
optional
stringYYYY-MM-DD (omit for undated)
body
optional
stringOptional detail / context
site_id
optional
stringRequired on cross-site super-admin sessions: which SITE names the target account (the pipeline is account-scoped; the account is resolved from the site). Discover ids via get_account_status. Ignored on site-scoped sessions, which always work their own account.
pipeline_create_opportunitywrite

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).

11 parameters
ParameterTypeDescription
company
required
stringCompany / customer name
title
optional
stringDeal title (default: "<company> deal")
stage
optional
stringFunnel stage key (default: first open stage)
value_cents
optional
numberDeal value in cents
website
optional
stringCompany website URL
source
optional
stringWhere the deal came from
notes
optional
stringFree-form notes
expected_close_date
optional
stringYYYY-MM-DD
custom
optional
objectCustom-field values keyed by the defs in settings.fields
funnel_key
optional
stringWhich pipeline (accounts can run several funnels with different stage ladders, e.g. sales + recruiting). Omit for the default funnel. The stage (if given) must belong to THAT funnel.
site_id
optional
stringRequired on cross-site super-admin sessions: which SITE names the target account (the pipeline is account-scoped; the account is resolved from the site). Discover ids via get_account_status. Ignored on site-scoped sessions, which always work their own account.
pipeline_get_funnelread

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.

2 parameters
ParameterTypeDescription
funnel_key
optional
stringWhich pipeline (accounts can run several funnels with different stage ladders, e.g. sales + recruiting). Omit for the default funnel.
site_id
optional
stringRequired on cross-site super-admin sessions: which SITE names the target account (the pipeline is account-scoped; the account is resolved from the site). Discover ids via get_account_status. Ignored on site-scoped sessions, which always work their own account.
pipeline_get_opportunityread

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. opportunity.lead_quality carries the suspected-spam verdict ({verdict, score, reasons}) or null for never scored; null is an absence of information, not a clean bill of health.

2 parameters
ParameterTypeDescription
opportunity_id
required
stringThe opportunity id (opp_…)
site_id
optional
stringRequired on cross-site super-admin sessions: which SITE names the target account (the pipeline is account-scoped; the account is resolved from the site). Discover ids via get_account_status. Ignored on site-scoped sessions, which always work their own account.
pipeline_list_deleted_opportunitiesread

Deals in the CRM trash: soft-deleted, still restorable, newest first — with who deleted each one and the date its restore window closes. Deleted deals are invisible to every other pipeline tool, so this is the only way to see them. Use it when someone says a deal has gone missing, and before telling anyone a deal does not exist. Read-only.

1 parameter
ParameterTypeDescription
site_id
optional
stringRequired on cross-site super-admin sessions: which SITE names the target account (the pipeline is account-scoped; the account is resolved from the site). Discover ids via get_account_status. Ignored on site-scoped sessions, which always work their own account.
pipeline_list_opportunitiesread

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. Each deal carries lead_quality: {verdict: ok|suspect|spam, score, reasons} when its originating website lead was scored, or null when it was NEVER SCORED (manual entry, agent-created, CSV import). null does NOT mean clean — never describe an unscored deal as verified or spam-free. A suspect/spam deal is excluded from the hot-lead flag; treat it as unqualified until a human releases it from the review queue.

3 parameters
ParameterTypeDescription
lead_quality
optional
"all" | "flagged" | "unflagged"Filter by lead quality: "flagged" for only suspected-spam deals, "unflagged" for everything else (which includes never-scored deals), "all" (default) for everything.
funnel_key
optional
stringWhich pipeline (accounts can run several funnels with different stage ladders, e.g. sales + recruiting). Omit for the default funnel.
site_id
optional
stringRequired on cross-site super-admin sessions: which SITE names the target account (the pipeline is account-scoped; the account is resolved from the site). Discover ids via get_account_status. Ignored on site-scoped sessions, which always work their own account.
pipeline_list_prospectsread

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.

1 parameter
ParameterTypeDescription
site_id
optional
stringRequired on cross-site super-admin sessions: which SITE names the target account (the pipeline is account-scoped; the account is resolved from the site). Discover ids via get_account_status. Ignored on site-scoped sessions, which always work their own account.
pipeline_list_tasksread

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.

4 parameters
ParameterTypeDescription
status
optional
stringopen|done|skipped|all (default open)
opportunity_id
optional
stringNarrow to one opportunity (opp_…)
due_before
optional
stringYYYY-MM-DD — only tasks due strictly before this date (overdue scan)
site_id
optional
stringRequired on cross-site super-admin sessions: which SITE names the target account (the pipeline is account-scoped; the account is resolved from the site). Discover ids via get_account_status. Ignored on site-scoped sessions, which always work their own account.
pipeline_log_activitywrite

Log a touchpoint (email, call, or meeting) on a CRM opportunity's timeline. Use external_ref (e.g. "gmail:<message-id>", "gcal:<event-id>") 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.

6 parameters
ParameterTypeDescription
opportunity_id
required
stringThe opportunity id (opp_…)
kind
required
stringemail|call|meeting
body
required
stringWhat happened — summary shown on the timeline (max 10k chars)
occurred_at
optional
stringWhen it happened, ISO 8601 (defaults to now; stored in metadata)
external_ref
optional
stringIdempotency key, e.g. "gmail:189ab…" — strongly recommended for swept sources
site_id
optional
stringRequired on cross-site super-admin sessions: which SITE names the target account (the pipeline is account-scoped; the account is resolved from the site). Discover ids via get_account_status. Ignored on site-scoped sessions, which always work their own account.
pipeline_propose_funnelwrite

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).

2 parameters
ParameterTypeDescription
description
required
stringThe user's plain-language description of their sales process (10-4000 chars)
site_id
optional
stringRequired on cross-site super-admin sessions: which SITE names the target account (the pipeline is account-scoped; the account is resolved from the site). Discover ids via get_account_status. Ignored on site-scoped sessions, which always work their own account.
pipeline_restore_opportunitywrite

Bring a deleted CRM opportunity back, with its contacts, tasks and full timeline. Ids come from pipeline_list_deleted_opportunities. If the deal's original stage no longer exists in the funnel it lands in the first open stage instead and the response says so in rehomed_to — say that out loud rather than leaving the user to find the card somewhere unexpected. Fails once the restore window has closed, at which point the deal is genuinely gone.

2 parameters
ParameterTypeDescription
opportunity_id
required
stringThe opportunity id (opp_…), from pipeline_list_deleted_opportunities
site_id
optional
stringRequired on cross-site super-admin sessions: which SITE names the target account (the pipeline is account-scoped; the account is resolved from the site). Discover ids via get_account_status. Ignored on site-scoped sessions, which always work their own account.
pipeline_set_funnelwrite

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.

6 parameters
ParameterTypeDescription
stages
optional
object[]The complete ordered stage list — replaces the existing funnel wholesale; omit to keep the current ladder and only touch settings
auto_create_from_leads
optional
booleanWhen true, captured website leads auto-create/attach opportunities. Omit to leave unchanged.
lost_reasons
optional
string[]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
optional
object[]Custom-field definitions for opportunities (max 10); money = integer cents; options required for select. Omit to leave unchanged.
funnel_key
optional
stringWhich pipeline (accounts can run several funnels with different stage ladders, e.g. sales + recruiting). Omit for the default funnel. Passing a NEW slug (lowercase letters, digits, - or _) together with stages CREATES that funnel — how a second pipeline (e.g. "recruiting") is born.
site_id
optional
stringRequired on cross-site super-admin sessions: which SITE names the target account (the pipeline is account-scoped; the account is resolved from the site). Discover ids via get_account_status. Ignored on site-scoped sessions, which always work their own account.
pipeline_suggest_stage_movewrite

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.

4 parameters
ParameterTypeDescription
opportunity_id
required
stringThe opportunity id (opp_…)
to_stage
required
stringThe proposed funnel stage key
reason
required
stringThe evidence, 1-3 sentences — shown verbatim on the timeline
site_id
optional
stringRequired on cross-site super-admin sessions: which SITE names the target account (the pipeline is account-scoped; the account is resolved from the site). Discover ids via get_account_status. Ignored on site-scoped sessions, which always work their own account.
pipeline_update_opportunitywrite

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.

13 parameters
ParameterTypeDescription
opportunity_id
required
stringThe opportunity id (opp_…)
stage
optional
stringNew funnel stage key
company
optional
stringCompany name
title
optional
stringDeal title
value_cents
optional
numberDeal value in cents
website
optional
stringCompany website URL
source
optional
stringDeal source
notes
optional
stringFree-form notes (replaces existing)
expected_close_date
optional
stringYYYY-MM-DD
lost_reason
optional
stringWhy 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
optional
objectCustom-field values to merge (null deletes a key), keyed by the defs in settings.fields
enrichment_override
optional
objectCorrections to the AXO-observed company facts, merged per key: industry, employee_range (a headcount band; "1-10", "11-50", "51-200", "201-1000", "1000+" are the usual ones but any short band is accepted, since the firmographic dataset uses its own), hq, founded_year (four-digit number), linkedin_url (a linkedin.com/company/… URL), tech_hints (1–3 strings), description (≤200 chars). A key set here overrides AXO and pins that field; setting a key to null removes the correction and hands that field back to automatic enrichment. Company name and website are NOT here — use the `company` and `website` arguments.
site_id
optional
stringRequired on cross-site super-admin sessions: which SITE names the target account (the pipeline is account-scoped; the account is resolved from the site). Discover ids via get_account_status. Ignored on site-scoped sessions, which always work their own account.
pipeline_update_taskwrite

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.

6 parameters
ParameterTypeDescription
task_id
required
stringThe task id (task_…)
status
optional
stringopen|done|skipped
title
optional
stringNew title
body
optional
stringNew detail (empty string clears)
due_date
optional
stringNew due date YYYY-MM-DD (empty string clears)
site_id
optional
stringRequired on cross-site super-admin sessions: which SITE names the target account (the pipeline is account-scoped; the account is resolved from the site). Discover ids via get_account_status. Ignored on site-scoped sessions, which always work their own account.
trigger_salesforce_syncwrite

Trigger a Salesforce sync. Direction can be outbound (push AXO→SF), inbound (pull SF→AXO), or bidirectional.

1 parameter
ParameterTypeDescription
direction
optional
"outbound" | "inbound" | "bidirectional"Sync direction (default: uses configured direction)