Skip to content

MCP tools

Look up the published MCP tool catalog by feature area.

Find a Lepsto MCP tool by feature area, then open its page for arguments and an example prompt. Connect your agent to https://mcp.lepsto.com; MCP clients lists the connection settings.

This is the published catalog. Your agent calls tools/list on the server for the current tools, along with each tool’s argument JSON Schema. Over MCP, every product-scoped tool takes the product as an argument: product_id, or productId where the tool declares it. The tool schema shows which. An injected product_id is not listed on the pages below; with an API key the product argument may be omitted. Use the fields and types in that response to build a call; a tool’s name alone does not specify its arguments.

The product-selection tools listed here are not offered over MCP; pass the product argument instead. User and product scope explains which tools need a product, and Refusals what a refused call returns.

Another way to look up an operation
What it contains
HTTP methods and paths from the same catalog. Each endpoint names its MCP tool.
A smaller, hand-curated selection with example prompts. Use tools/list to discover the tools your agent can call.

Tools

Analytics

19 tools.

  • analytics_catalog_get — Read the analytics semantic catalog: every entity this product may chart, with its declared metrics, dimensions and person-graph identity kinds. Call this FIRST to discover the exact entity, metric and dimension names analytics_metric_query and analytics_funnel_run accept — those names are resolved against this catalog and a name that is not in it is rejected. A metric unit describes raw money scale and its currency dimension; a dimension label link names the related entity and columns used for readable group labels. dropped_metrics, when present, lists metrics left out of entities that cannot be queried: reason is type_unknown (a metric type this analytics build does not support yet), aggregate_unknown (a ratio part with an unsupported aggregate) or column_missing (a count_distinct without a column).
  • analytics_dashboard_create — Save a named dashboard for the current product: up to forty tiles, each either a reference to a saved insight by its uuid (from analytics_insight_list) or a block of markdown, each placed on a twelve-column grid. The slug is the address the dashboard is read by and cannot be changed later. filters (up to 8) are the filters the board offers its viewers: {key, label, dimension, map?}. A filter applies to every series whose entity has a dimension named exactly dimension; for an entity whose field is named differently, map names it ({“googleads_campaign_daily”: “campaign_id”}). Similar names are never matched. On a funnel a filter applies to its FIRST step only — it picks who enters, and later steps follow those people even where their entity has no such field (a signup with no utm_campaign) — so a funnel is filtered when its first step has the dimension and unfiltered otherwise. Values are supplied per run (analytics_dashboard_run). Build in order: headline numbers → pivot by campaign → daily dynamics. Example for guidance, not a template: 4–6 bold_number tiles for spend, clicks, visits, unique visitors, pricing and signups with compare; a pivot with cost by campaign_id and group_label campaign_name, clicks, page_view count and unique_visitors by utm_campaign, and a funnel visit → url starts_with /pricing → signup_completed grouped by utm_campaign, every step labelled; rows_label Кампания and formulas cost per click (f1 = A / B) and cost per signup (f2 = A / E). Then a daily line of visits. Offer filters for country and campaign; map campaign to utm_campaign on events and campaign_id on Google Ads. Returns the stored dashboard plus warnings[] {code, message, path} about the board itself: a hard-coded campaign id (an eq, or an in/not_in of up to 5 ids, on utm_campaign or campaign_id) when another tile groups by that field. It does not re-check the saved insights the tiles reference; their warnings come from analytics_insight_create and analytics_insight_update. Stores the arrangement only; it does not run it. Every insight a tile names must already exist in this product, so a stored dashboard always resolves.
  • analytics_dashboard_delete — Permanently delete one saved dashboard of the current product. The insights its tiles referred to are not deleted.
  • analytics_dashboard_get — Read one saved dashboard of the current product by its slug or its id. Returns the tiles and their layout, not results.
  • analytics_dashboard_list — List the saved dashboards of the current product, newest first. Narrow by an exact tag or by a case-insensitive substring of the name or slug. Returns definitions, not results.
  • analytics_dashboard_run — Run every tile of a saved dashboard of the current product and return one entry per tile, in board order: the tile itself, and what it produced. An insight tile carries exactly what analytics_insight_run answers for that insight; a text tile carries a null result, because its content is the tile. from and to override the window of every insight tile for this call only, changing nothing stored. filters gives values to the board’s filters by key ({“country”: {“op”: “eq”, “value”: “DE”}}); a series the filter cannot reach runs unfiltered and is listed in its tile’s filters_skipped. A funnel series takes a filter on its first step only, so it is filtered exactly when that step’s entity has the dimension; otherwise it is listed with every step (on a pivot, every <key>.<step> column) as not filtered. compare also reads a second range, returned per tile as compare (totals, and points laid over the current buckets; a funnel compares its last step; a pivot compares its totals only), whose compare.window is always the exact range read: “previous_period” is the window right before with as many days as have elapsed of this one (a window running past today counts through today); “previous_week” is the same days one week earlier; {from, to} is any range of up to 366 whole UTC days (YYYY-MM-DD, inclusive, to not before from), clipped to today, starting no later than today, and it may overlap the window (each is read on its own, so shared days count in both). Points pair by position, day 1 with day 1: a compared range of another length leaves the current buckets past its end with value and prev_bucket null, and a longer one’s tail is cut from the points (its total still covers the whole range). A range with no data is totals 0 (null for an average or ratio) and points 0, not a missing compare. To compare yesterday with today: from and to today with compare {from: yesterday, to: yesterday}, or from yesterday to today with “previous_period” (yesterday and today against the two days before). A tile that fails carries an error with an HTTP status and does not stop the rest of the board, so check each tile’s result before reading numbers. The call answers only when every tile is done; a heavy board (many tiles, many series) is better loaded tile by tile with analytics_dashboard_tile-run, after analytics_dashboard_get for the layout.
  • analytics_dashboard_tile-run — Run one tile of a saved dashboard of the current product, by the tile’s id (from analytics_dashboard_get), and return that tile’s entry: the tile itself and what it produced — the same entry analytics_dashboard_run gives that tile for the same body. Takes the same from, to, filters and compare (“previous_period”, “previous_week” or {from, to}; to compare yesterday with today, from and to today with compare {from: yesterday, to: yesterday}) as analytics_dashboard_run, checked against the whole board the same way (a filter key the board does not declare is a 400), and a funnel takes a filter on its first step only, exactly as there. Use it to fill a heavy board in progressively, one call per tile, keeping at most about 6 calls in flight per board (as many as analytics_dashboard_run runs at once). A text tile carries a null result; a tile that fails carries an error with an HTTP status rather than failing the call; a tile id the board does not have is a 404.
  • analytics_dashboard_update — Change fields of a saved dashboard of the current product. Only the fields supplied are changed; the rest keep their stored values. Supplying tiles replaces the whole arrangement, so send the tiles you want to keep along with the new ones; supplying filters replaces them the same way. The slug cannot be changed — create a new dashboard instead. filters (up to 8) are the filters the board offers its viewers: {key, label, dimension, map?}. A filter applies to every series whose entity has a dimension named exactly dimension; for an entity whose field is named differently, map names it ({“googleads_campaign_daily”: “campaign_id”}). Similar names are never matched. On a funnel a filter applies to its FIRST step only — it picks who enters, and later steps follow those people even where their entity has no such field (a signup with no utm_campaign) — so a funnel is filtered when its first step has the dimension and unfiltered otherwise. Values are supplied per run (analytics_dashboard_run). Build in order: headline numbers → pivot by campaign → daily dynamics. Example for guidance, not a template: 4–6 bold_number tiles for spend, clicks, visits, unique visitors, pricing and signups with compare; a pivot with cost by campaign_id and group_label campaign_name, clicks, page_view count and unique_visitors by utm_campaign, and a funnel visit → url starts_with /pricing → signup_completed grouped by utm_campaign, every step labelled; rows_label Кампания and formulas cost per click (f1 = A / B) and cost per signup (f2 = A / E). Then a daily line of visits. Offer filters for country and campaign; map campaign to utm_campaign on events and campaign_id on Google Ads. Returns the stored dashboard plus warnings[] {code, message, path} about the board itself: a hard-coded campaign id (an eq, or an in/not_in of up to 5 ids, on utm_campaign or campaign_id) when another tile groups by that field. It does not re-check the saved insights the tiles reference; their warnings come from analytics_insight_create and analytics_insight_update.
  • analytics_funnel_run — Run an ordered conversion funnel over the analytics semantic layer for the current product. Supply filters on a step to narrow its rows; omit filters to apply no step filters. Each step names a semantic entity and is counted in resolved persons from the identity graph, so a person is counted once per step no matter how many rows or identifiers they produced. Deterministic: entity, dimension and metric names are resolved against the semantic catalog, never generated. A step whose entity has a propertiesColumn in the catalog also accepts filters on props.<key>, compared as a string. Step filters support legacy {dimension, eq} or op eq, neq, in, not_in, starts_with, is_null, is_not_null; in and not_in take 1–100 values of one type; starts_with takes a string and works on text dimensions. neq and not_in retain NULL rows. Give each step a label (1–60 characters, e.g. Дошли до /pricing); every returned step carries label — the declared one, or its entity and filters when it has none. Prefer this over analytics_query_run whenever the question is a conversion between ordered steps.
  • analytics_insight_create — Save a named insight for the current product: one to eight series over the analytics semantic layer, an optional formula combining them by key, a time window and how to display it. Use display bold_number for headline KPIs with dashboard compare, pivot for rows × metrics, line for daily dynamics, and steps for funnels. Give every series a human label when there are several. Filters neq and not_in keep NULL rows. Money stays raw; set the series format {kind: money, scale, currency} so readers see its scale and currency. Each series may have a trimmed display label (1–60 characters). Use series format for display, group_label for a grouped metric’s label dimension, and formula_label with formula_format for a named formula. For several formulas use formulas [{key f1..f4, label 1–60, expr, format}] (up to 4) instead of formula — never both (400); each is evaluated exactly as formula is and its number is total[key] (and a pivot cell keyed by it). A percent value is a fraction (0.128 means 12.8%). display facts draws the first series as the base bar (100%) and each next series as a bar with its value and % of the base — use it for independent facts about the same visitors (e.g. base = visited from ads, then reached /pricing, clicked CTA, signed up), unlike steps which are sequential; it is for kind number only (400 otherwise) and runs like any number insight. Chart displays (display-only; refused with 400 at display, stacked or combo when the series cannot be drawn, saying what fits): pie for shares of a whole — one metric series with group_by, or 2–8 ungrouped metric series of one unit (format kind, and currency and scale for money), no percent, no formula; area for volume over time, kind trend only; stacked: true (bar or area only) stacks 2+ series or one grouped series of one unit, no percent, no formula; bar_horizontal for a ranking — one grouped metric series, or 2–8 ungrouped series of one unit (a funnel under kind number counts as its last step), no formula; combo for two scales over time (e.g. cost as bars, signups as a line) — kind trend, 2–4 ungrouped metric series, combo {line: [keys]} names the line series or formulas (default the last series), at least one series stays a bar; all bars must share one unit and all lines one unit (format kind, currency and scale for money; no format is a number), else 400 — move the odd series to the line or split the insight. A number insight may combine a funnel (its value is its last step over the window, ungrouped) with metrics in a formula, e.g. cost per signup = cost / funnel to signup_completed. A single metric series in a trend or number insight may use group_by with per-series top_n (1–20, default 8); grouped insights cannot have a formula. display steps shows a funnel as its steps (persons and conversion per step) and is the default for kind funnel; every other kind defaults to line, and steps is refused on them. Give every funnel step a label (1–60 characters): it is the step’s column title and steps label; without one it reads as its entity and filters. A funnel series may set hidden_steps [0-based step indexes] — display-only, e.g. hide the entry step that another funnel already shows: hidden steps still count and every number, formula and total is unchanged; at least one step must stay visible. display pivot is a table of rows per group value across series: every series (a metric, or a funnel by a dimension of its first step) may carry its own group_by; rows are joined by the group value as an exact string. A grouped funnel counts a person in EVERY group they entered by, each from their first entry with that value, so a funnel row equals the same funnel with its first step filtered to that value; rows can overlap and its total is the distinct people (the ungrouped funnel), not the sum of rows. Join keys are exact, so the values must match (events.utm_campaign must equal the Google Ads campaign_id); formula runs per row and over the totals, and a formula or sort names a funnel series by its LAST step only (E means E.<last>); sort {by: series key | formula | f1..f4, dir} and top_n (1–50, default 20) order and cap the rows, the rest fold into other; rows_label (1–40) titles the row-header column. Worked example, the ads campaign table: display pivot, rows_label Кампания, series A label Расход = googleads_campaign_daily cost by campaign_id (format money), B label Клики = clicks by campaign_id, E label Путь = funnel by utm_campaign with steps [{label Уникальные, events page_view}, {label Дошли до /pricing, path starts_with /pricing}, {label Регистрации, signup_completed}], formulas [{key f1, label Цена клика, expr A / B, format money}, {key f2, label Цена регистрации, expr A / E, format money}], sort {by A, dir desc}. The slug is the address the insight is read by and cannot be changed later. A save is refused (400, naming the field to fix) for several series without a label, for display pivot without group_by on any series, and for a series whose request does not suit the kind (series.N.request: trend needs metric requests, number metric or funnel requests, funnel needs funnel requests, retention needs retention requests; only display pivot mixes metric and funnel series) — the same insight would fail to run. Otherwise it returns the stored insight plus warnings[] {code, message, path}: advice that does not block the save — series that differ only in one filter value of a dimension other than event_name, with no group_by yet and not combined by one formula (use group_by or pivot), a formula over money without a money formula_format (or a money formulas entry without a money format), a funnel step without a label (it would show as its entity and filters), a money-looking metric without a unit or series format, a window that starts after today (it has no days yet), a daily table longer than 31 rows (use line). A window.to after today is fine: a run clips it to today, so from a fixed date to a later date is the way to say since <date>. Stores the definition only; it does not run it. Series requests are validated with the same schemas analytics_metric_query and analytics_funnel_run accept, so a stored insight always runs.
  • analytics_insight_delete — Permanently delete one saved insight of the current product. Dashboards referring to it will no longer resolve it.
  • analytics_insight_get — Read one saved insight of the current product by its slug or its id. Returns the definition, not results.
  • analytics_insight_list — List the saved insights of the current product, newest first. Narrow by an exact tag or by a case-insensitive substring of the name or slug. Returns definitions, not results.
  • analytics_insight_run — Run a saved insight of the current product and return its numbers: every series executed over the resolved window and aligned onto the same buckets, the formula evaluated bucket by bucket, a total per series, optional series_labels keyed by series key, and whether the target was met. Grouped metric insights return ranked groups (top_n plus other for count/sum), and meta with group_by and group counts. Money stays raw at its scale; series_format tells the app how to convert and display it. When grouped by currency, each value group carries its own format and currency; mixed-currency headlines, formula totals, and the other group are null with a reason in meta. A funnel insight also returns steps: per series key, every step over the whole window with label, persons, conversion_from_first and conversion_from_prev — a step nobody reached is 0, never missing; its series and total remain the last step per bucket. A pivot insight returns pivot: rows {key, label, cells} per group value merged across series by exact string key (a cell is null where that series has no row), other (the rows past top_n), total and total_reasons, sort and meta {rows_total, rows_dropped, top_n}; a funnel series is one cell per step keyed <key>.<stepIndex> with series_steps labels, and step_pct on each row, on other and as total_step_pct gives each step cell over that row’s first step (1 for step 0, null when step 0 is 0), so a cell reads 41 · 13.6 %; rows_label is the row-header title when the insight declares one. An insight with formulas returns formulas (per key, bucket by bucket; absent for a pivot, whose numbers are the cells f1..f4), formula_labels and formula_formats keyed by formula key in definition order, and each formula’s total under total[key]; compare carries formulas and total[key] the same way. Totals are honest: count and sum are summed over all rows; count_distinct, avg and ratio are read ungrouped over the window; a grouped funnel’s rows overlap (a person is in every group they entered by), so its step totals are the ungrouped funnel — distinct people — and its other is read on its own: the distinct people who entered by any group past top_n. Where a total cannot be read it is null with the reason in total_reasons (other follows the same rule), never a wrong number. A pivot has no buckets: series is empty and formula null. Missing count/sum buckets are zero. The window comes from the stored definition — relative windows and the current cycle are resolved at call time — and from and to override it for this call only, changing nothing stored. Use this rather than rebuilding the insight out of analytics_metric_query calls: the alignment and the formula are what make the numbers comparable.
  • analytics_insight_update — Change fields of a saved insight of the current product. Only the fields supplied are changed; the rest keep their stored values. The slug cannot be changed — create a new insight instead. Returns the stored insight plus warnings[] for the row as it now stands. An update is refused only for what it changes: missing labels when it replaces series, pivot without group_by when it changes display or series, a chart display that cannot be drawn when it changes kind, display, series, stacked, combo or a formula; the same findings on an older insight come back as warnings. Switching display drops a stored stacked or combo the new display does not use (the response shows them gone). A series replaced here carries its own hidden_steps (display-only; omit it to show every step).
  • analytics_metric_query — Compute declared metrics from the analytics semantic layer for the current product, bucketed by time. Supply group_by to split each time bucket by one dimension; omit it to aggregate without dimension grouping. Deterministic: entity, metric and dimension names are resolved against the semantic catalog, never generated. Prefer this over analytics_query_run whenever the question is a metric over time — no LLM. Where the catalog gives an entity a propertiesColumn, group_by and a filter dimension also accept props.<key> to read one raw event property; property values always compare as strings. Filters support legacy {dimension, eq} or op eq, neq, in, not_in, starts_with, is_null, is_not_null; in and not_in take 1–100 values of one type; starts_with takes a string and works on text dimensions. neq and not_in retain NULL rows.
  • analytics_person_timeline — Return one resolved person’s profile and their chronological activity across every identity-bearing semantic entity of the current product. Address the person either by person_id or by any single identifier (email, phone, users_id, anonymous_id), which is normalised exactly as the identity graph normalised it. Deterministic: no LLM, and only catalog-declared columns are returned. Prefer this over analytics_query_run whenever the question is about one specific person.
  • analytics_query_run — Answer a natural-language analytics question for the current product. Fallback surface: it routes the question to analytics_metric_query or analytics_funnel_run when it fits one of them and returns that tool’s exact request and response in structured; it generates SQL only when neither fits. Call analytics_metric_query, analytics_funnel_run or analytics_person_timeline directly when you already know the shape of the question — those are deterministic and cheaper.
  • analytics_retention_run — Measure day-N retention over the analytics semantic layer for the current product: of the subjects whose FIRST matching cohort event falls in a bucket, how many produced a return event on day N (within return_window_days after it). The cohort key is subject — an event property (props.<key>, e.g. the customer product id) or identity for the entity’s declared identity columns — and each subject is counted exactly once. Deterministic: entity and dimension names are resolved against the semantic catalog, never generated. A bucket whose day-N horizon has not elapsed yet is still returned, with retained and rate NULL rather than 0 — null means “not measurable yet”, 0 means “measured, nobody came back”, and a caller must not confuse them. total therefore covers the measurable buckets ONLY, so a half-elapsed cohort never drags the headline rate down; meta.unmeasurable_buckets says how many were left out.

Brain

41 tools.

  • brain_backup_create — Request an on-demand point-in-time backup of the current product’s Brain memory. Async (202): records a running snapshot and runs the backup in the background — returns { accepted, snapshotId }; poll brain_backups_list / brain_backup_status for completion. Rejects (409) if a backup is already running for the product.
  • brain_backup_restore — DESTRUCTIVE: full-replace restore of the current product’s Brain from a snapshot (wipe + load). Takes an automatic pre-restore snapshot first (safety net). Requires confirm:true AND confirmProductId echo; refuses on product/snapshot mismatch or embedding-dims mismatch. Async — returns { accepted, restoreId }; poll brain_restore_status.
  • brain_backup_status — Get a backup status by snapshot id, or the latest backup for the current product.
  • brain_backups_list — List the current product’s backups (most recent first).
  • brain_clickup_channels_list — List the chat channels in a ClickUp workspace connection (for selecting channels to ingest)
  • brain_clickup_connections_list — List the ClickUp workspace connections available to the current product
  • brain_clickup_lists_list — List all lists in a ClickUp space, both folderless and within folders. Filters by search when supplied.
  • brain_clickup_spaces_list — List the spaces in a ClickUp connection. Filters by search when supplied.
  • brain_cognition_digest — Queue a System-2 digest over the product shared pool (async); returns { accepted, run_id }. Poll brain_cognition_status for the result.
  • brain_cognition_status — Read the engine-global System-2 queue gauge plus this product’s last digest/sweep run (status, counts, timing).
  • brain_cognition_sweep — Queue a cross-domain sweep over the product shared pool (async); returns { accepted, run_id }. Poll brain_cognition_status for the result.
  • brain_connector_branches_list — List branches for a repository on a GitHub connection
  • brain_connector_connections_list — List the GitHub connections available to the current product
  • brain_connector_repos_list — List repositories accessible to a GitHub connection. Filters by search when supplied.
  • brain_daemon_batch_status — Get batch ingestion status for a daemon (pending count, job, ETA, model, outcome)
  • brain_daemon_create — Create a new ingestion daemon (github, clickup or gdrive)
  • brain_daemon_get — Get a specific ingestion daemon by id
  • brain_daemon_reingest — Force re-ingest of specific document paths for a daemon: clears their stored content hash and triggers a realtime run, so degraded or never-measured documents are re-extracted instead of hash-skipped forever
  • brain_daemon_remove — Remove an ingestion daemon and its connector state (leaves ingested memory)
  • brain_daemon_run — Trigger an immediate run for a daemon and return its current status
  • brain_daemon_run_items — List the per-item ingest ledger for a run (filter by outcome, esp. denied)
  • brain_daemon_runs — Recent run history for a daemon with per-run ingest counts
  • brain_daemon_status — Get the latest run status for a daemon
  • brain_daemon_update — Update an ingestion daemon (config, enabled, name, branch)
  • brain_daemons_list — List configured ingestion daemons for this product
  • brain_gdrive_connections_list — List Google Drive connections for this product with their picked files
  • brain_knowledge_entity_memories — List the memories a knowledge entity was extracted from (its DERIVED_FROM evidence)
  • brain_knowledge_graph — Export the product knowledge graph (entities + typed relations) as nodes and edges; truncation keeps the highest-degree nodes, so a small limit returns the hub concepts
  • brain_knowledge_neighborhood — Expand the neighborhood (related entities + relations) around one knowledge entity
  • brain_knowledge_relations — List typed relations (depends_on, competes_with, …) in the product knowledge graph
  • brain_knowledge_search — Search product knowledge-graph entities (Feature, Decision, Risk, …) for the current product
  • brain_memory_add — Store a memory for the current product. extraction reports what fact extraction made of it. success: false with extraction.status: 'failed' means the raw memory IS stored under memory_id and is searchable, only its facts are missing — do not add the same content again, that stores a duplicate. extraction.status: 'empty' is a success: nothing new came out of it — the content held nothing durable, or it is already in memory.
  • brain_memory_delete — Delete a memory you own (or a shared one)
  • brain_memory_get — Get one memory by id (product+agent scoped)
  • brain_memory_list — List memories (shared + your private by default)
  • brain_memory_search — Search memories for the current product
  • brain_memory_stats — Summary counts for the current product (memories by layer, graph nodes/edges, entities, raw memories left without facts)
  • brain_memory_update — Replace a memory you own (or a shared one)
  • brain_product_shared_memory_reset — DESTRUCTIVE admin op: reset a product’s SHARED Brain memory (vectors + knowledge graph) and clear its connector_state so a re-ingest re-writes. Requires confirm:true AND confirmProductId echo; gated by an env arm flag, an env allowlist, and governance access.
  • brain_restore_status — Read a restore run’s status (pending|wiped|importing|completed|failed) with counts + timing, by restoreId (returned by brain_backup_restore).
  • brain_usage_report — Reported LLM/embedding token usage for this product, next to the platform billing aggregate

15 tools.

  • consent_config_cookie_domain_upsert — Sets an explicit cookie Domain for the consent cookie (lepsto_consent). By default the banner derives the widest owned boundary automatically: the registrable domain (eTLD+1) on customer sites, or the deploy host on Lepsto platform hosts — so consent given on site.com also covers docs.site.com. Set cookieDomain only to NARROW that perimeter, e.g. when several Lepsto products live on subdomains of one domain and each must keep its own consent (cookieDomain: “docs.site.com” on the docs product). The value must be a suffix of the page hostname at runtime, otherwise the banner ignores it and falls back to auto-derivation. Platform deploy suffixes (lessly.dev / lessly.com / lessly.run / lessly.tech, lepsto.dev / lepsto.com / lepsto.run / lepsto.tech / lepsto.app / lepsto.io / lepsto.ai / lepsto-run.dev, v2.*), their parent domains and unknown lessly.* / lepsto.* domains are rejected — a cookie on those would leak consent across tenants. Pass null or an empty string to remove the override.
  • consent_config_customization_upsert — Fine-tunes the banner beyond brand tokens, when the theme alone is not enough. logoUrl / coverUrl — https URLs to images hosted on the client’s side (we store nothing; an empty string removes the asset; an external URL exposes the visitor’s IP to that host); coverUrl is a header strip across the top of the banner. position — where the banner sits on the page (“bottom” / “top” / “bottom-left” / “bottom-right” / “center-modal”); this is the banner’s placement, distinct from the reopen-icon corner in consent_config_floating_icon_upsert. logoAlign — “start” / “center” / “end”; contentAlign — “start” / “center”. All fields are optional and patch-merge onto the previous customization. This layer does not change button equality (“Accept all” / “Reject all”) or the provider list.
  • consent_config_floating_icon_upsert — Configures the always-available “Cookie settings” entry point that lets a visitor reopen their consent preferences after they have made a choice. By default Lepsto renders a floating icon in a page corner; you can move it, or bind the entry point to an element the site already has (for example a “Cookie settings” link in the footer) instead of showing the icon. Fields (under floatingIcon): enabled — whether to render Lepsto’s built-in floating icon; position — which corner the icon sits in (“bottom-right” / “bottom-left” / “top-right” / “top-left”); customSelector — a CSS selector for an existing element on the page (e.g. “#footer-cookie-link”) whose click opens consent settings, or null to rely on the built-in icon only. To hide the built-in icon (enabled: false) you must provide a customSelector, so the visitor always keeps a way to reopen settings.
  • consent_config_theme_upsert — Adapts the consent banner’s appearance to the site’s brand. Pass what you observe on the client’s site: brandColor — the site’s primary brand color (any CSS color); surface — whether the site is “light” or “dark”; corners — button corner shape (“sharp” / “rounded” / “pill”); font — the site’s font, given as a font name, a full CSS font stack, or “inherit” to adopt the host page’s font. If the brand tokens are not enough, fine-tune overrides: backgroundColor, textColor, primaryTextColor, borderColor, focusColor, dangerColor, successColor, warningColor. primaryTextColor sets the text on the primary button; without it that text is derived from primaryColor. Fails when: primaryTextColor contrasts below 3.0:1 against the effective primaryColor — the patch is rejected, naming the computed ratio. All fields are optional and patch-merge onto the previous theme. To identify the site: use a URL from the request; otherwise the latest decision pageUrl; otherwise ask the user once. This layer is cosmetic only — after applying, “Accept all” and “Reject all” stay equally prominent and the provider list is unchanged.
  • consent_dashboard_config_get — Returns consent config for the current product: theme — the editable brand-theme intent previously set via consent_config_theme_upsert; customization — the editable escape-hatch intent (logo/cover URLs, position, alignment) set via consent_config_customization_upsert (empty object if none set yet) — and floatingIcon (trigger settings). When no consent_config row exists, returns defaults; never 404s.
  • consent_dashboard_decisions_list — Returns the latest consent decisions for the current product — each with its HMAC signature (stamp) and a computed accept/deny/custom/withdrawal label. Read-only; useful to confirm decisions are still being signed.
  • consent_dashboard_embed_snippet_get — Returns the consent banner embed <script> tag and public edge URL for the current product. Read-only. Insert script_tag VERBATIM, including its leading HTML comment, as the FIRST script in <head> — before any tracker, tag manager or inline loader. Never add async or defer: banner.js must execute before the parser reaches the first tracker, otherwise trackers run before consent is known.
  • consent_dashboard_stats_get — Returns lightweight dashboard stats for the current product (currently total record count). Read-only.
  • consent_embed_get — Returns the consent banner embed <script> tag for the current product. Insert script_tag VERBATIM, including its leading HTML comment, as the FIRST script in <head> — before any tracker, tag manager or inline loader. Never add async or defer: banner.js must execute before the parser reaches the first tracker, otherwise trackers run before consent is known.
  • consent_providers_create — Create a new consent provider. cookies (optional) is the full set; cookies must have unique names within the provider.
  • consent_providers_delete — Delete a consent provider and all its cookies (cascade).
  • consent_providers_list — List all consent providers (and their cookies) for the current product.
  • consent_providers_update — Update an existing consent provider. cookies: undefined leaves cookies unchanged, [] clears them, […] replaces the whole set. privacyUrl: null clears the field.
  • consent_records_export — Export consent records for the current product as CSV (workspace-scoped). Returns inline CSV up to limit rows; if more rows match the filter, also returns download_url pointing to the streaming HTTP endpoint with the same filters applied. For an Art. 15 (DSAR) access request, pass record_id (the UUID from the visitor’s consent cookie) to filter the export to that visitor’s full decision chain.
  • consent_stats_get — Returns aggregated consent decision stats for the current product over a configurable window (default 30d, max 365d). Returns integer percentages 0..100; due to per-bucket rounding the sum may be 99..101. Read-only.

Content

42 tools.

  • content_channels_bind — Bind a channel to a platform connector by hand. For manual cases only: an account connected on the Integrations page already has its own channel. The connector must be attached to this product, match the channel’s network and have no other channel in this product (connector_not_found, connector_network_mismatch, connector_already_bound otherwise). Clears an existing pause and turns the channel on. Pass deliveryMode “auto” to also switch the channel to automatic publishing; binding alone never does.
  • content_channels_get — Read one channel: its delivery mode and its capability descriptor — the character limit, media rules and cost to check before composing a variant for it.
  • content_channels_list — List the channels this product can publish to, with each one’s limits and per-post cost. A LinkedIn profile, X or YouTube account connected on the Integrations page appears here by itself as an auto channel named after the account (origin integration). The seeded channels, one per network, use reminder delivery: the system prepares the post and notifies a person to publish it. Every channel is returned, on or off: enabled says whether it is in use (integration channels always are; a new product starts with every seeded channel off), and only a channel with enabled true can be scheduled. Label a network with networkName, never with a channel’s displayName.
  • content_channels_resume — Resume a paused channel once its connection works again. Its frozen publications dispatch on the next scheduler tick — late, not cancelled. A channel paused as detached or removed resumes only after its integration is attached to this product again on the Integrations page; otherwise the call is refused with connector_detached. Reconnecting never resumes a channel by itself.
  • content_channels_unbind — Detach a channel from its platform connector, and clear any pause. Delivery mode is left as it is: an auto channel left without a connection fails its publications visibly rather than being silently downgraded to reminders. The account is not brought back as a new channel by itself: bind it again to undo.
  • content_channels_update — Rename a channel, change its delivery mode, turn a manual channel on or off (enabled), or correct its capability descriptor. Turning off is refused with 409 channel_not_toggleable for an integration channel, which is always on, and with 409 channel_has_scheduled while the channel still has publications waiting to go out — cancel them first. Channels are not created with a tool: every product starts with one per network, and each account connected on the Integrations page adds its own.
  • content_folders_create — Create a folder at the root or inside another folder, placing it last among siblings. The parent must belong to this product; use content_folders_list to find its id.
  • content_folders_delete — Delete an empty folder. A folder with posts or subfolders is refused as folder_not_empty; move or delete its contents first.
  • content_folders_list — List this product’s folder tree as a flat array with parentId and sibling position. counts are direct posts; totalCounts include every descendant, grouped by post status.
  • content_folders_update — Rename, re-parent or reorder a folder. beforeFolderId must be a sibling under the target parent. A move into itself or a descendant is refused as folder_cycle; use content_folders_list to inspect the tree first.
  • content_media_create_upload_url — Get a time-limited signed URL to PUT a file straight into the product bucket. Creates a pending asset; call content_media_finalize once the upload finishes.
  • content_media_finalize — Confirm a signed-URL upload. The bucket is asked what was actually stored, and the asset becomes ready. Fails while no object has been uploaded yet.
  • content_media_get — Read one media asset: its storage status, type and size.
  • content_media_list — List media assets, newest first. Supply status to filter by storage status; omit it to include all statuses.
  • content_media_upload — Ingest media from a public http(s) URL: the toolkit fetches it and stores it in the product bucket. Images and video up to 512 MB. A fetch that fails returns the asset with status “failed” and a reason rather than an error.
  • content_metrics_channel_series — Daily snapshots of a channel itself — follower count and channel-level reach over time. Sampled once a day while the channel is publishing; a channel with nothing published in the last 30 days stops being sampled, and one whose network reports no analytics is never sampled at all.
  • content_metrics_post_series — Metric snapshots of one published post on one channel, over time — how reach and engagement grew, not a single current number. Sampled hourly for the first day, then daily, then weekly, then never: a post stops growing and the polling stops with it. Empty until the first snapshot, and always empty where analytics is “none”.
  • content_posts_approve — Approve a post awaiting approval. The approval binds to the current version — a later edit revokes it.
  • content_posts_attach_media — Attach stored media assets to a post, appended in the given order. Only assets that are ready can be attached. This counts as an edit: the post gets a new version and an approved post returns to pending_approval.
  • content_posts_create — Create a content plan item. Write the text into each output (targets[].text): networks differ, and the base text is only optional source text for outputs that have none. A title with no text anywhere starts as an idea; text in any output or as base text starts as a draft. Optionally place it in a folder and add private notes, media and outputs (targets): a network and a variant each, several per network allowed, each with optional own media. Use content_posts_to_draft for an idea, then content_posts_submit when every output has publishable text.
  • content_posts_delete — Delete an idea or draft only if it has no publication history. Cancelled and failed publications also block deletion. This deletes its content versions and emits content/post.deleted; other statuses return post_not_deletable.
  • content_posts_detach_media — Remove media assets from a post, keeping the order of the rest. Like any edit, it produces a new version and returns an approved post to pending_approval. Removing the only video an output with a cover inherits is refused with 400 cover_without_video: clear that output’s cover with content_posts_update first.
  • content_posts_get — Read one post: its current text, status, version numbers and outputs — one entry per output with its state (none, open, uncertain, failed, published, skipped) and the publication that decides it. The way to re-read a post mid-run — after a wait, after an approval, after a publication settled.
  • content_posts_list — List posts, including ideas, each with its outputs and their states. Filter by status (partially_published for posts with some outputs out and others not) or folderId (null for unfiled posts). With a folder filter, posts appear in plan order; otherwise newest first.
  • content_posts_move — Move a post in any status into a folder, before another post there, or out to the unfiled plan. This changes only plan order, never approval or content version. The destination must belong to this product.
  • content_posts_skip_output — Mark one output of an approved post as “won’t publish”: it counts as closed, so a post whose other outputs are all published becomes published. It is not a content edit — no new version, the approval stands — and content_posts_unskip_output undoes it. Only past approval (409 post_not_approved otherwise). Refused with 409 output_has_live_publication while the output has a queued or in-flight publication (cancel it first), 409 already_published once it is out, 409 may_already_be_live while a finished publication of it may be live, 409 variant_not_found for an unknown output. Schedule, publish and record of a skipped output answer 409 output_skipped.
  • content_posts_submit — Submit a draft for approval. Only a draft can be submitted, and only once it has at least one output and every output has non-empty text and its required variant fields filled.
  • content_posts_to_draft — Move an idea to draft, or take a post awaiting approval back to draft, keeping its title, text and version (no new version; the submission is withdrawn). Only an idea or a pending_approval post can make this transition. Add text or output texts before content_posts_submit.
  • content_posts_to_idea — Move a draft back to idea without changing its content version. Only a draft can make this transition; use content_posts_to_draft when it is ready for approval.
  • content_posts_unskip_output — Undo content_posts_skip_output: the output can be scheduled, published or recorded again, and the post status is recomputed. Always allowed past approval; unskipping an output that is not skipped changes nothing.
  • content_posts_update — Edit plan title or notes in any status without changing approval or version. Keep each output’s own text in targets[].text — networks differ; the base text is optional source text. Editing text, media or targets creates a new immutable version; an approved post returns to pending_approval. A post that is scheduled, partially_published, published or failed cannot be edited — create a new post.
  • content_posts_versions — List every version of a post, oldest first — the audit trail of what was written and by whom.
  • content_publications_cancel — Cancel a publication that has not finished. A publication whose reminder already went out can still be cancelled — until someone confirms it. An auto publication that is being sent to the network right now is refused with 409 publication_in_flight: wait for its outcome. A finished publication that may still be live (its output is uncertain) blocks the output until a person settles it: confirm it if the post is on the network, or cancel it with checkedNotLive: true after checking that it is not.
  • content_publications_confirm — Confirm that a person published the post by hand. Supply externalUrl to record its URL; omit it to store no URL. This closes the publication. Confirmation remains available after publication when the person did not confirm at the time, and for a finished publication that may be live (its output is uncertain) once the person has seen the post on the network. An auto publication that is being sent to the network right now is refused with 409 publication_in_flight.
  • content_publications_get — Read one publication: its state, its slot, and where it ended up.
  • content_publications_list — List publications — the queue and the timeline — newest slot first.
  • content_publications_publish — Publish NOW: the same queue, scheduled for this instant, publishing one output of the post’s approved version to the channel (there is no text parameter: per-output text lives in targets[].text, set with content_posts_update). variantId picks the output; it is inferred when the channel’s network has exactly one, and refused with 409 variant_required (listing the outputs) when it has several and none is named. There is no separate synchronous path — a fast path would differ exactly where it matters, on failure. The same one-publication-per-output-per-channel rule as content_publications_schedule: if that output already has a pending, publishing or published publication on the channel, this is refused with 409 already_scheduled naming it. An idempotencyKey already spent on a cancelled or failed publication is refused with 409 idempotency_key_spent.
  • content_publications_record — Record that a person already published one OUTPUT of an approved post by hand — no scheduling needed. This never publishes anything: it stores the fact, and the post’s status follows (one of two outputs recorded → partially_published; every output published or skipped → published). When the output has a publication on its network that is queued, reminded or may already be live, THAT publication is confirmed (as content_publications_confirm would); otherwise a publication is stored already published, which nothing ever sends or reminds. An output goes to a network once: one already out on any channel of the network is refused with 409 already_published naming it, one being sent by the automatic publisher right now with 409 publication_in_flight (wait for its outcome), a skipped one with 409 output_skipped (content_posts_unskip_output first). Only for a post past approval (409 post_not_approved). A queued automatic publication the publisher has claimed but not started sending is confirmed too, and then never sent. Repeating the same call (same post, output and channel) returns the same publication; a record is stored once, so a repeat naming a different publishedAt or externalUrl is refused with 409 record_mismatch listing the stored values.
  • content_publications_remind — Send the publish reminder AGAIN. Repeat reminders are never automatic: the system cannot double-publish, but a person can, so a second nudge only ever happens because someone asked for it. Only for a reminder channel whose first reminder went out: an auto channel is refused with 409 not_a_reminder_channel, and an auto publication being sent right now with 409 publication_in_flight.
  • content_publications_reschedule — Move a publication to a new time. It returns to the queue, and the reminder for the old slot is spent — a new one goes out at the new time. An auto publication that is being sent to the network right now is refused with 409 publication_in_flight; one whose channel has been turned off is refused with 409 channel_disabled.
  • content_publications_schedule — Queue one OUTPUT of an approved post for publication to one channel at a given time. A post’s outputs are its targets (content_posts_get: targets[].id) — a network and a variant each, several per network allowed, e.g. a YouTube video and two Shorts. What goes out is that output of the post’s APPROVED version: its text, post type, fields and media (its own list, or the post’s when it inherits); there is no text parameter: per-output text lives in targets[].text, set with content_posts_update. variantId picks the output; omit it when the channel’s network has exactly one output and it is inferred. When the network has several outputs and none is named, the call is refused with 409 variant_required and the list of outputs — pick one and call again. An output of another network is 409 network_not_targeted; an unknown id is 409 variant_not_found. On a reminder channel this does not call the network: at the scheduled time a person is notified to publish by hand, and confirms afterwards with content_publications_confirm. The channel must be on (enabled true in content_channels_list); a channel that is off is refused with 409 channel_disabled — turn it on with content_channels_update or pick another channel. An output goes to a channel once: while it has a publication there that is pending, publishing or published, a second one is refused with 409 already_scheduled naming that publication and output — move it with content_publications_reschedule, or cancel it with content_publications_cancel and schedule again; the post’s OTHER outputs may still be scheduled to the same channel. A cancelled or failed publication does not count. Repeating a call with the same idempotency key (by default derived from post, channel, output and time) returns its publication, not a conflict — unless that publication was cancelled or failed: then nothing is queued and the call is refused with 409 idempotency_key_spent; pick a different time or pass a new idempotencyKey.
  • content_publications_validate — Dry run: check one output of a post per channel WITHOUT scheduling anything. Per channel entry, variantId names the output (targets[].id); omit it when the channel’s network has one output and it is inferred — with several and none named the entry reports variant_required and the outputs to pick from. Returns everything that would go wrong — a network the post has no output for, a required variant field left empty, a post type that needs a video, text too long, the output’s media not stored yet, a link a network will not linkify — and what publishing would cost. On X a post carrying a link costs $0.20 against $0.015 for a plain one, so call this before you schedule.

Deployment

115 tools.

  • deployment_alert_create — Create a threshold alert rule for a service or managed service
  • deployment_alert_delete — Delete an alert rule
  • deployment_alert_events_list — List recent alert firing/resolved events in an environment
  • deployment_alert_list — List alert rules in an environment
  • deployment_alert_update — Update an alert rule (threshold, comparator, enabled)
  • deployment_analytics_query — Ask a natural-language question about THIS product’s deployment data (deployments, deploy events, environments, services, domains, managed services) and get a computed answer. Returns the generated SQL, the result rows, and a natural-language answer. Read-only; scoped to the current product.
  • deployment_build_get — Get a single build by deployment id
  • deployment_build_list — List builds for a service, newest first
  • deployment_build_logs — Snapshot build logs for a deployment (Cloud Logging proxy)
  • deployment_canvas_get — Get canvas state (nodes + services) for an environment
  • deployment_canvas_move_node — Update position/size of a canvas node
  • deployment_cloud_sql_backfill_log_flags — Apply this product’s managed Postgres (Cloud SQL) log flags to existing instance(s), idempotently (safe to re-run; zero downtime). Targets one instance when instanceId is supplied.
  • deployment_cloud_sql_database_attach — Attach a managed Postgres database to a service in an environment; injects DATABASE_URL (and PG* vars) as a secret.
  • deployment_cloud_sql_database_create — Create a logical database (with its own role) on the managed Postgres instance.
  • deployment_cloud_sql_database_delete — Delete a logical managed Postgres database (detaches from all services first).
  • deployment_cloud_sql_database_detach — Detach a managed Postgres database from a service; removes the injected connection secrets. Does not delete the database.
  • deployment_cloud_sql_database_get — Get a logical managed Postgres database by id.
  • deployment_cloud_sql_database_list — List the logical managed Postgres databases on an instance.
  • deployment_cloud_sql_instance_backup — Take an on-demand backup of the managed Postgres (Cloud SQL) instance.
  • deployment_cloud_sql_instance_backup_list — List backup runs for the managed Postgres (Cloud SQL) instance.
  • deployment_cloud_sql_instance_create — Provision the product’s managed Postgres instance on Google Cloud SQL — fully managed by Google Cloud, with automated backups and point-in-time recovery, a dedicated instance, and easy resize.
  • deployment_cloud_sql_instance_delete — Delete the managed Postgres (Cloud SQL) instance (must have no databases).
  • deployment_cloud_sql_instance_get — Get the product’s managed Postgres (Cloud SQL) instance and its status.
  • deployment_cloud_sql_instance_list — List the product’s managed Postgres (Cloud SQL) instance(s).
  • deployment_cloud_sql_instance_resize — Resize the managed Postgres (Cloud SQL) instance to a different tier (CPU/RAM).
  • deployment_cloud_sql_instance_restore — Restore the managed Postgres (Cloud SQL) instance IN-PLACE from a backup run (destructive — overwrites current data).
  • deployment_cloud_sql_logs — Snapshot the last N Postgres log lines for a managed Postgres (Cloud SQL) instance.
  • deployment_deployment_cancel — Cancel a non-terminal deployment, releasing the in-progress lock so the service can deploy again
  • deployment_deployment_get — Get a single deployment by id
  • deployment_deployment_list — List deployments for a service (newest first)
  • deployment_domain_add — Register a custom domain for an environment; returns CNAME+TXT DNS instructions. When the governance domain is in external mode the result also carries managedDns, a hint to switch it to managed mode with organization_domains_set-mode (needs a Cloudflare connector) so the records are published for you
  • deployment_domain_allowed_list — List Governance-approved base domains the product may add subdomains of
  • deployment_domain_get — Get a domain by id (includes DNS instructions for custom domains awaiting verification)
  • deployment_domain_list — List domains for an environment (auto + custom)
  • deployment_domain_list_by_service — List domains routed to a service (backward-compat)
  • deployment_domain_redirect_set — Put a domain into Redirect mode — answer a 301/302 to another domain of the same service, path and query preserved. Pass a null target to clear it and go back to serving.
  • deployment_domain_redirect_www — Toggle the www→apex 301 redirect for an apex custom domain
  • deployment_domain_remove — Remove a custom domain (auto-domains are removed via service.delete)
  • deployment_domain_routes_add — Add a path-route to a custom domain
  • deployment_domain_routes_list — List path-routes for a domain
  • deployment_domain_routes_remove — Remove a path-route (default route cannot be removed)
  • deployment_domain_routes_update — Update a path-route
  • deployment_domain_verify — Force an out-of-band DNS verification check for a custom domain
  • deployment_environment_create — Create a new environment
  • deployment_environment_delete — Delete an environment (production cannot be deleted)
  • deployment_environment_fork — Fork an environment: deep-clone services, variables (not secrets), domains, and volumes from a base environment
  • deployment_environment_get — Get a single environment by id
  • deployment_environment_list — List environments for the current product. Filters by type (persistent or pr-preview) when supplied.
  • deployment_environment_reconcile — Re-emit the provision or deprovision workflow for an environment, with optional force-finalizer-strip on deprovision
  • deployment_environment_update — Update an environment (name is the only updatable field)
  • deployment_events_list_by_environment — List deploy events for an environment, newest first
  • deployment_events_list_by_service — List deploy events for a service, newest first
  • deployment_job_run — Run a scheduled service (job) now, regardless of its schedule or concurrency; returns the run
  • deployment_job_run_cancel — Stop one running job run by deleting its Job and pods. The service, CronJob and schedule stay unchanged. Returns the Cancelled run.
  • deployment_job_run_logs — Read the output of one job run: the stored tail (up to 256 KiB) once the run has finished, or a live tail while it is still running. live says which one you got — a caller that polls should stop once it turns false.
  • deployment_job_runs_list — List the runs of a scheduled service (job), newest first. Returns a page of runs plus nextCursor; pass that back as cursor for the next page. A run with status “Skipped” is a tick that never fired — concurrency held it back — and has no logs or exit code.
  • deployment_managed_service_backup — Create a backup snapshot of a managed service
  • deployment_managed_service_backup_list — List backup snapshots for a managed service
  • deployment_managed_service_connect_info — Get connection info and variable reference syntax for a managed service
  • deployment_managed_service_delete — Delete a managed service (soft-delete, triggers deprovisioning)
  • deployment_managed_service_get — Get a managed service by id
  • deployment_managed_service_list — List managed services in an environment
  • deployment_managed_service_logs — Get pod logs for a managed service
  • deployment_managed_service_provision — Provision a managed service (e.g. Postgres, Redis) inside an environment
  • deployment_managed_service_reconcile — Retry provisioning of a managed service that failed or is stuck in provisioning. Also releases one stuck in backing_up for over 15 min: sets it back to ready and does not re-run the backup. Refused while the backup is younger than 15 min or its snapshot is still in progress.
  • deployment_managed_service_resize — Increase storage size of a managed service (cannot shrink)
  • deployment_managed_service_restore — Restore a managed service from a backup snapshot
  • deployment_managed_service_start — Start a stopped managed service
  • deployment_managed_service_stop — Stop a running managed service
  • deployment_managed_service_types — List available managed service engines and versions
  • deployment_metrics_get — Get metric time series for a service or managed service over a fixed window (15m/1h/6h/24h/7d). Services return resource metrics (cpu, memory, net_in, net_out) plus HTTP metrics (rps, p50, p95, p99, error_rate); managed services return cpu, memory, net_in, net_out, disk.
  • deployment_preview_environment_create — Create a preview environment from an open PR
  • deployment_preview_environment_delete — Delete a preview environment immediately
  • deployment_preview_environment_list — List all preview environments
  • deployment_preview_policy_get — Get preview policy for a base environment (returns defaults if none configured)
  • deployment_preview_policy_set — Configure preview policy for a base environment (enabled, maxPreviews, ttlHours)
  • deployment_resource_presets_list — List the resource presets a service can pick for resources.limits (XS…2XL, 1:2 vCPU:RAM). A preset sets the CPU and memory limit — the ceiling the service may use and is billed by usage under; any other valid limit is allowed too.
  • deployment_service_create — Create a service inside an environment. mode:‘persistent’ (the default) is a container kept running; mode:‘scheduled’ is a job that runs a command and exits. A scheduled service takes schedule (a five-field UTC cron expression — minute hour day-of-month month day-of-week — or null for a job that only ever runs on demand), command (the shell command one run executes), jobTimeoutSec, and jobConcurrency (‘forbid’ | ‘allow’ | ‘replace’), and accepts no containerPort, replicas or scaleToZero. mode is immutable after create. publicDomain defaults to true; pass false for a service that must not face the internet (minio, pgadmin, a worker) and it is created with no auto-domain and no route. For a git source only, source.build.secrets selects existing secret variables by name from the effective product → environment → service variable set. Image and static sources cannot use this field. Each deploy re-checks the selection and gives the values to the Docker build as BuildKit secrets: in the Dockerfile use RUN —mount=type=secret,id=<key> and read /run/secrets/<key> (env= is not supported). Omit build or use build: { secrets: [] } to select none.
  • deployment_service_delete — Delete a service
  • deployment_service_exec — Run a command against a service. mode:“exec” (default) execs non-interactively into the first running pod (debugging); mode:“job” runs a one-off Job of the service’s current image with its env (migrations). Returns stdout/stderr + exit code as text. command is run via /bin/sh -c.
  • deployment_service_get — Get a single service by id. A scheduled service (mode:‘scheduled’) also reports nextRunAt and lastRun — when it fires next and how its most recent run ended. publicDomain says whether this service holds its public auto-domain; false means it is reachable only through a custom domain or from inside the environment. A git or static source with a GitHub connector also carries sourceConnection.state: ‘connected’ (the connection is working), ‘unavailable’ (removed, detached, replaced by a reconnect, or not working — call deployment_vcs_connection_list with repoFullName to see which connections can read the repo, then deployment_service_update with the new connectorId) or ‘unknown’ (the connection list could not be fetched; the read still succeeds). Reading never contacts GitHub and never changes the source; source.autoDeploy sits next to it. A git source may report source.build.secrets: names only; variable values are never returned. appliedProbes are the probes of the version running now; pendingProbes are what the next deploy applies; probesPendingRedeploy is true when they differ. To apply them now, deploy the service, or roll back to its current Active deployment (same image, fresh render). appliedProbes is null when nothing runs, or with appliedProbesUnknown when they could not be read.
  • deployment_service_list — List services within an environment. Each entry carries publicDomain — false for a service that holds no public auto-domain. A git or static source with a GitHub connector also carries sourceConnection.state: ‘connected’ (the connection is working), ‘unavailable’ (removed, detached, replaced by a reconnect, or not working — call deployment_vcs_connection_list with repoFullName to see which connections can read the repo, then deployment_service_update with the new connectorId) or ‘unknown’ (the connection list could not be fetched; the read still succeeds). Reading never contacts GitHub and never changes the source; source.autoDeploy sits next to it. A git source may report source.build.secrets: names only; variable values are never returned. appliedProbes are the probes of the version running now; pendingProbes are what the next deploy applies; probesPendingRedeploy is true when they differ. To apply them now, deploy the service, or roll back to its current Active deployment (same image, fresh render). appliedProbes is null when nothing runs, or with appliedProbesUnknown when they could not be read.
  • deployment_service_logs — Snapshot the last N runtime log lines for a service
  • deployment_service_redeploy — Roll out a new deployment for a service from its current source and variables (runs asynchronously; poll the deployment for status). A static site published from an uploaded archive cannot be redeployed: upload again with deployment_static_upload_create, then deployment_static_deploy
  • deployment_service_restart — Trigger a rolling restart of a service without changing the deployed image
  • deployment_service_rollback — Roll back a service to a previous deployment by re-deploying its imageRef
  • deployment_service_scale — Scale a service to N replicas without redeploy (min 0 = stop)
  • deployment_service_update — Update service fields. mode is immutable. On a scheduled service (mode:‘scheduled’) you may change schedule (five-field UTC cron, or null to leave it on demand only), command, jobTimeoutSec, jobConcurrency (‘forbid’ | ‘allow’ | ‘replace’), and scheduleSuspended, which pauses or resumes the schedule without losing it. publicDomain false removes the auto-domain and its route; true re-creates them under the same hostname. Custom domains are untouched either way. Switching the GitHub connection: send the source with a new connectorId (source.repo.connectorId for a static site; build, spa and markdown you leave out keep their values). The new connection must be working and able to read repoFullName, otherwise the update is refused with 409 source_connection_unavailable and a candidates list (the other connections that can read it; pick one, the platform never picks), or 503 source_connection_check_failed when the check could not finish (try again). A successful switch records service.source.reconnected with reason ‘manual’. Editing branch or path with the same connectorId is never checked, even when the connection is unavailable. For a git source only, source.build.secrets selects existing secret variables by name from the effective product → environment → service variable set. Image and static sources cannot use this field. Each deploy re-checks the selection and gives the values to the Docker build as BuildKit secrets: in the Dockerfile use RUN —mount=type=secret,id=<key> and read /run/secrets/<key> (env= is not supported). If you omit build when updating the same git repo, the current selection is preserved. Use build: { secrets: [] } to clear it.
  • deployment_service_wake — Wake a sleeping (scale-to-zero) service
  • deployment_ssh_bastion_get — Get the SSH bastion host this workspace connects to
  • deployment_ssh_command — Get the ssh command string to connect to a service
  • deployment_ssh_key_delete — Delete a registered SSH public key
  • deployment_ssh_key_list — List SSH public keys registered in the current workspace
  • deployment_ssh_key_register — Register an SSH public key for the current workspace
  • deployment_static_deploy — Deploy an uploaded static-site archive (call after the PUT to the uploadUrl from deployment_static_upload_create succeeded). Runs asynchronously: returns the deployment, then poll deployment_deployment_get with its id. A deployId can be deployed once; a second call is a 409. Publish a pre-built static site (no git repo): 1) deployment_service_create with source: { type: ‘static’ } (no repo) — once per site; 2) deployment_static_upload_create with the serviceId and format (‘tgz’ default, or ‘zip’) — returns uploadUrl, deployId, contentType, expiresAt; 3) within 15 min, curl -X PUT -H ‘Content-Type: <contentType>’ —upload-file <file> ‘<uploadUrl>’ (the header must be exactly contentType or the PUT is refused); 4) deployment_static_deploy with serviceId and deployId; 5) poll deployment_deployment_get with the deployId until status is Active (or Failed — read lastErrorMessage). The archive root is published as-is; if it has no index.html and holds only one directory (e.g. dist/, macOS __MACOSX/ and .DS_Store ignored), that directory is published instead. Each upload deploys once; for a new version start again from step 2.
  • deployment_static_upload_create — Start a static-site upload: mint a signed PUT URL (valid 15 min) for a site archive and reserve the deployment it will become. Only for a static service. If the upload fails or you abandon it, call deployment_deployment_cancel with this deployId — the service cannot deploy again until you do. Publish a pre-built static site (no git repo): 1) deployment_service_create with source: { type: ‘static’ } (no repo) — once per site; 2) deployment_static_upload_create with the serviceId and format (‘tgz’ default, or ‘zip’) — returns uploadUrl, deployId, contentType, expiresAt; 3) within 15 min, curl -X PUT -H ‘Content-Type: <contentType>’ —upload-file <file> ‘<uploadUrl>’ (the header must be exactly contentType or the PUT is refused); 4) deployment_static_deploy with serviceId and deployId; 5) poll deployment_deployment_get with the deployId until status is Active (or Failed — read lastErrorMessage). The archive root is published as-is; if it has no index.html and holds only one directory (e.g. dist/, macOS __MACOSX/ and .DS_Store ignored), that directory is published instead. Each upload deploys once; for a new version start again from step 2.
  • deployment_suspension_get — Get the product’s billing-suspension state (stage, reason, grace deadline) and whether enforcement is active
  • deployment_variable_list — List variables for a service (secret values are returned as null)
  • deployment_variable_list_env — List environment-scope (shared) variables
  • deployment_variable_list_product — List product-scope (global) variables
  • deployment_variable_set — Create or update a variable on a service. Pass isSecret: true to encrypt the value via KMS — this transition is irreversible (a row that is already secret cannot be downgraded to plain).
  • deployment_variable_set_env — Create or update an environment-scope shared variable
  • deployment_variable_set_product — Create or update a product-scope global variable
  • deployment_variable_unset — Delete a variable from a service by key
  • deployment_variable_unset_env — Delete an environment-scope variable by key
  • deployment_variable_unset_product — Delete a product-scope variable by key
  • deployment_vcs_branch_list — List branches for a repository on a GitHub connection
  • deployment_vcs_connection_list — List the GitHub connections available to the current product: their kind (provider github = GitHub App, github-token = GitHub key), account, status and needsReauth. A connection is working when status is active and needsReauth is false. Pass repoFullName (“owner/repo”) to also learn, per connection, whether it can read that repo (repoAccess) — use it to choose the connection for deployment_service_update after a deploy failed with source_connection_unavailable. repoAccess is false for a connection that is not working or cannot read the repo, and absent when the check failed transiently; without repoFullName it is never set.
  • deployment_vcs_repo_list — List repositories accessible to a GitHub connection. Filters by search when supplied.
  • deployment_volume_create — Create a volume
  • deployment_volume_delete — Permanently delete a detached volume
  • deployment_volume_detach — Detach a volume from its service (data preserved)
  • deployment_volume_get — Get a volume
  • deployment_volume_list — List volumes in environment
  • deployment_volume_resize — Increase a volume size

Mail

58 tools.

Observe

35 tools.

  • observe_alerts_create — Create an alert rule for this product. error_rate counts error events in the window; log_match counts log lines matching a Lucene expression, the same one observe_logs_search takes. The rule fires when the count reaches the threshold and resolves when it drops back below it; throttleMinutes is how long it stays quiet after firing. An expression that cannot be parsed is rejected here rather than failing silently on every evaluation.
  • observe_alerts_delete — Remove an alert rule and its firing history. To stop being alerted while keeping the history, set the rule disabled instead.
  • observe_alerts_events_list — List past and current firings for this product, newest first. A row with a null resolvedAt is an alert that is happening now. Each carries what the measure was and the condition as it stood at that moment.
  • observe_alerts_get — Read one alert rule of this product, with its current state and last firing.
  • observe_alerts_list — List the alert rules of this product, newest first, with what each one measures and whether it is firing right now.
  • observe_alerts_update — Edit an alert rule: its name, its condition, its throttle, or whether it is enabled. What the rule measures — its kind — is not editable; create a second rule instead. Omit a field to leave it alone.
  • observe_artifacts_delete — Delete one stored artifact and the bytes behind it. An artifact belonging to another product is reported as not found.
  • observe_artifacts_list — List the source map artifacts stored for the current product, newest first. Filter by debug ID to see what is available for one build output.
  • observe_artifacts_resolve — Resolve the stack trace of an issue’s latest event against the stored source maps, turning minified frames into original file, function, line and column. Frames with no matching debug ID are returned unchanged: a partially resolved trace is the normal result.
  • observe_issues_archive — Archive an issue: it stops being reported and stays archived even when new events keep landing on it.
  • observe_issues_assign — Assign an issue to someone, or pass a null assignee to clear the assignment.
  • observe_issues_event — Read one event of an error tracking issue in full — the most recent one by default, or a specific one by id. Returns where and in what it happened: service, environment, release, trace, tags, and for OTel events the span with its HTTP method, route, status and target address. An issue whose events are no longer stored still comes back, with a null event.
  • observe_issues_events — List the events of an error tracking issue, newest first. Each row identifies one event; pass its eventId to observe_issues_event to open it. Page with nextCursor.
  • observe_issues_get — Read one error tracking issue by id, together with the resolved stack of its most recent event. Frames with no matching source map are returned unchanged, and an issue whose stack cannot be read still comes back — with a null stack.
  • observe_issues_histogram — Count the events of an error tracking issue per bucket over a window, so a reader can see when it started and whether it is still going. Bucket width is derived from the window; quiet buckets come back as zeros, never as gaps.
  • observe_issues_list — List error tracking issues of the current product, most recently seen first. Filter by status or assignee.
  • observe_issues_resolve — Mark an issue resolved. A later event flips it back to unresolved and emits observe/issue.regressed.
  • observe_keys_create — Create an ingest credential for one environment: a Bearer OTLP token (kind “ingest”) or a public Sentry DSN (kind “dsn”). The credential is returned once and cannot be retrieved again.
  • observe_keys_list — List the OTLP ingest keys of the current product. Tokens are never returned.
  • observe_keys_revoke — Revoke an OTLP ingest key. Telemetry sent with it is rejected immediately.
  • observe_logs_facets — Count the environments, services and severities present in the logs of the current product over a window, so a filter can offer the values that actually exist. Counts are cached for up to a minute.
  • observe_logs_search — Search the log lines of the current product, newest first. Reads the last 24 hours unless from/to say otherwise, and answers windows of up to 7 days — wider when a traceId or a single-word search pins the read to an index. Filters are structured; there is no SQL surface. Page with nextCursor.
  • observe_logs_tail — Follow the log lines of the current product. The first call returns the last 50 lines of the past 15 minutes, oldest-first; pass the returned cursor back to get only what arrived since.
  • observe_metrics_list — Catalogue the metrics of the current product: what exists, whether it is a counter or a histogram, its unit, which services report it and which attribute keys its series carry. Read this before observe_metrics_query — it is where a name, a type and a groupBy key come from.
  • observe_metrics_query — Read one metric of the current product as a time series. Cumulative counters are differenced at read time, so a process restart reads as its own increase rather than as a negative spike; histogram percentiles are interpolated across the emitter’s buckets. Up to 100 series and 500 points each, over at most 31 days; truncated says when a ceiling was reached.
  • observe_traces_get — Read every span of one trace of the current product, oldest first, as a flat list carrying parentSpanId and depth — enough to draw a waterfall without a second call. Span events are returned exactly as the emitter sent them. Up to 5000 spans.
  • observe_traces_search — Search the traces of the current product, newest first. Reads the last hour unless from/to say otherwise, and answers windows of up to 24 hours unless traceId pins the read. One row per trace: its root span, how long the whole trace took, how many spans it has and whether any of them failed. Filters are structured; there is no SQL surface. Page with nextCursor.
  • observe_webhooks_create — Register an HTTPS endpoint to receive this product’s observe issue events, and mint its signing secret. The secret is returned here and NOWHERE ELSE — store it now: it cannot be read back and can only be replaced by rotating it. Plain http:// endpoints are rejected.
  • observe_webhooks_delete — Remove a webhook endpoint and its delivery log. Delivery stops immediately. To stop delivery while keeping the history, set the endpoint inactive instead.
  • observe_webhooks_deliveries_list — List webhook delivery attempts for this product, newest first. Filter by endpoint or by state (pending, success, failed). Each row carries the event data that was sent, the last HTTP status and why the last attempt failed.
  • observe_webhooks_get — Read one registered webhook endpoint of this product. Its signing secret is never returned.
  • observe_webhooks_list — List the webhook endpoints registered for this product. Signing secrets are never returned.
  • observe_webhooks_redeliver — Send a past delivery to its endpoint again, with the original payload and the original idempotency key — a receiver that already processed it can recognise and ignore the repeat. The original delivery is kept as history and a new one is opened for this attempt. If the endpoint has since been disabled, nothing is delivered.
  • observe_webhooks_rotate_secret — Replace the signing secret of an endpoint and return the new one, exactly once. The old secret stops verifying immediately — there is no grace window, so update the receiver before rotating.
  • observe_webhooks_update — Edit a registered endpoint: its url, its description, or whether it is active. Setting active to false keeps the registration and stops delivery. Omit a field to leave it alone; pass null to clear the description. The signing secret is not editable here — rotate it instead.

Organization

98 tools.

  • organization_auth_me — Returns the current identity: identity ID, email, and identity type (e.g. “service” for a service token, which has no email)
  • organization_billing_budget_clear — Removes the monthly limit for extra charges of the organization that owns the product in product_id. An open pause stays until organization_billing_budget_resume; nothing restarts on its own. Returns: the budget view, as organization_billing_budgets_get. Fails when: the caller does not own the organization.
  • organization_billing_budget_resume — Ends the open budget pause of the organization that owns the product in product_id, so paused services restart and new chargeable work is allowed again. Possible only when pause.resumable is true in organization_billing_budgets_get. Returns: the budget view, as organization_billing_budgets_get. Typical sequence: organization_billing_budgets_get → organization_billing_budget_set → organization_billing_budget_resume. Fails when: the caller does not own the organization, no pause is open (409 not_paused), or the pause is still blocked (409 resume_blocked, blocked_by: budget_reached | billing_paused | measure_unavailable).
  • organization_billing_budget_set — Sets the monthly limit for extra charges of the organization that owns the product in product_id, in integer minor units, and what happens at 100%. Replaces any existing limit. Does not end an open pause; organization_billing_budget_resume does. Returns: the budget view, as organization_billing_budgets_get. Typical sequence: organization_billing_budget_set → organization_billing_budget_resume. Fails when: the caller does not own the organization, or no currency is pinned for it yet (currency_not_pinned).
  • organization_billing_budgets_get — Reads the monthly limit for extra charges of the organization that owns the product in product_id, this UTC month’s counted extra charges, the 50/80/100% thresholds reached, and any open budget pause. To change the limit use organization_billing_budget_set; to remove it, organization_billing_budget_clear; to end a pause, organization_billing_budget_resume. Returns: { currency, budget: { amount_minor, action, updated_at } | null, month: { period, start, end }, counted_minor, lines: { resource, amount_minor }[], thresholds: { percent, reached_at }[], pause: { paused_at, period, amount_minor, counted_minor, resumable, blocked_by } | null, suspension, projection } suspension.reason “unusual_charges” means extra charges this month are unusually high: report it in those words, never as a limit and never with an amount; the remedy is organization_billing_budget_set or contacting support. Any other unknown reason is a billing restriction. Fails when: the caller does not own the organization.
  • organization_bindings_list — Lists the extension bindings attached to a domain in a product
  • organization_clickup_install — Starts the ClickUp OAuth connect flow for a product and returns the install URL
  • organization_clickup_list-installations — Lists the ClickUp installations connected to a product
  • organization_cloudflare_install — Starts the Cloudflare OAuth connect flow for a product and returns the consent URL
  • organization_connectors_approve-request — Approves a connector access request, attaching the product (org owner/admin)
  • organization_connectors_attach — Attaches products to a connector (batch, idempotent; org owner/admin)
  • organization_connectors_delete — Deletes a connector org-wide: soft-delete, remove all attachments, tear down routing (org owner/admin)
  • organization_connectors_deny-request — Denies a connector access request (org owner/admin)
  • organization_connectors_detach — Detaches one product from a connector (org owner/admin). Last detach → dormant.
  • organization_connectors_list — Lists active connectors in a product. A github-token row is a fine-grained GitHub token the product connected in the console: config carries repos, tokenLast4, expiresAt, permissions and autoDeploy; lastUsedAt and reauthReason (expiring, expired, revoked) are on the row. The token itself is never returned, and it is added or replaced in the console only.
  • organization_connectors_list-attachments — Lists the products a connector is attached to (org owner/admin)
  • organization_connectors_list-available — Lists org connectors not yet attached to a product, with this product’s request status
  • organization_connectors_list-org — Lists an organization’s connectors with their product attachments (org owner/admin)
  • organization_connectors_list-requests — Lists connector access requests for an organization (org owner/admin)
  • organization_connectors_remove — Detaches the product in product_id from a connector. For a github-token connector this revokes it (product owner or admin): the stored token and webhook secret are deleted and the revocation is audited.
  • organization_connectors_request — Requests access to an org connector for a product (any product member)
  • organization_create — Creates a new organization owned by the current user and sets it as the active organization for the session.
  • organization_domains_add — Adds a custom domain to a product. The domain always starts in external (self-managed DNS) mode; when the product has an active Cloudflare connector that can write DNS, the response carries a managedDns hint naming the connector and the tool that switches the domain to managed mode.
  • organization_domains_get — Gets a single custom domain in a product by id
  • organization_domains_list — Lists the custom domains configured in a product
  • organization_domains_remove — Removes a custom domain from a product
  • organization_domains_set-mode — Switches a custom domain between external (self-managed DNS) and managed mode. Managed mode requires providerConnectorId — the id of an active Cloudflare connector attached to the product — and hands the domain’s records to the platform reconciler.
  • organization_extensions_list-installed — Lists extensions available to the given product
  • organization_feedback_submit — Submit product feedback — opens a GitHub issue in the Lessly feedback repo. Use when the user wants to report a bug, request a feature, or leave feedback about the platform.
  • organization_gdrive_install — Starts the Google Drive OAuth connect flow for a product and returns the consent URL
  • organization_github_install — Starts the GitHub app installation flow for a product. When the product’s organization already has GitHub connections, returns them so one can be reused (attached) instead of dead-ending on GitHub’s already-installed settings page. url is always returned — connecting an additional, different GitHub org stays possible.
  • organization_github_list-installations — Lists the GitHub app installations connected to a product
  • organization_googleads_install — Starts the Google Ads OAuth connect flow for an organization and returns the consent URL
  • organization_groups_create — Creates an organization group (owner/admin)
  • organization_groups_delete — Deletes an organization group; the access it carried is withdrawn (owner/admin)
  • organization_groups_get — Gets a single organization group with its members and product grants
  • organization_groups_grant-remove — Removes a group’s grant on a product (owner/admin)
  • organization_groups_grant-set — Grants a product to every member of a group at an organization role (owner/admin)
  • organization_groups_list — Lists the groups of an organization with their members and product grants
  • organization_groups_member-add — Adds an organization member to a group (owner/admin)
  • organization_groups_member-remove — Removes a member from a group; the access the group carried is withdrawn (owner/admin)
  • organization_groups_update — Renames an organization group or changes its description (owner/admin)
  • organization_linkedin_member_install — Starts the LinkedIn member (personal profile) OAuth connect flow for a product and returns the consent URL
  • organization_list — Lists the organizations the current user belongs to (owned or via membership).
  • organization_member_accept-invite — Accepts an organization invitation using the invitation token
  • organization_member_invite — Invite a user to an organization by email. Share the products listed in productShares when supplied.
  • organization_member_list — Lists the stored members of an organization with their roles and product grants. email is filled for org owners and admins only; it is null for plain members and when Identity has none.
  • organization_member_list-invitations — Lists invitations for an organization
  • organization_member_list-product-access — Lists the products in an organization a member can access, with role, grant source, and expiry (management view; expired grants are shown with expiresAt).
  • organization_member_remove — Removes a member from an organization
  • organization_member_revoke-invitation — Revokes a pending organization invitation
  • organization_member_set-role — Changes an organization member’s role (owner only)
  • organization_member_share-product — Grants an organization member explicit access to a product
  • organization_member_unshare-product — Revokes an explicit product share from an organization member
  • organization_members_assign-role — Assigns a role to a member of a product
  • organization_permission_catalog — Lists the full permission catalog (key, display_name, group, level, scope) derived from @McpTool handlers. Only scope=“product” entries are grantable in role/point-rights pickers; scope=“user” entries are informational.
  • organization_principal-grants_approve — Sponsors tools for a delegated principal; the approver becomes the sponsor and may only approve what their own role covers, the rest come back in notSponsorable (product owner/admin)
  • organization_principal-grants_list — Lists the delegated principals of a product with the tools they hold, are waiting on, and have lost a sponsor for (product owner/admin)
  • organization_principal-grants_revoke — Takes tools away from a delegated principal; omit tools to take away everything it holds (product owner/admin)
  • organization_product_create — Creates a new product with the given name. Returns the new product; pass its id as product_id to product-scoped tools.
  • organization_product_erasure_get — Read one erasure request raised for this product’s own end users, with the acknowledgement each participating service has filed. organization_product_erasure_list enumerates them. Returns: { id, subjectType, subjectId, controller, productId, subjectRefs, requestedBy, requestedAt, dueAt, status, startedAt, finishedAt, acks }. Fails when: the request id is unknown or belongs to another product — both answer 404.
  • organization_product_erasure_list — List the erasure requests raised for this product’s own end users, newest first. organization_product_erasure_get reads one by id. Returns: { requests: [{ id, subjectId, status, requestedAt, dueAt, acks }], next }. Page with after set to the previous answer’s next; next is null on the last page. Requests raised by another product are never listed. Fails when: the caller is not a member of the product.
  • organization_product_erasure_request — Erase one end user of this product, named by email address, phone number, your own user id and display name. Identifiers are hashed on arrival and no tool on this surface returns one. organization_product_erasure_list reads the requests back. Returns: { id, subjectType, subjectId, controller, productId, subjectRefs, requestedBy, requestedAt, dueAt, status, acks }. Typical sequence: organization_product_erasure_request → organization_product_erasure_get. Fails when: no email, phone and external id is given, or the caller does not hold owner or admin on the product. Irreversible.
  • organization_product_list — Lists all products the current user has access to
  • organization_product_list-access — Lists who can work in a product: the explicit grants and their roles, the organization owners and admins who inherit full access (read-only here), the organization members holding no access yet, and the organization’s named roles a grant can be handed at. canManage states whether the caller may change any of it.
  • organization_product_list-members — Lists all active members of a product with their roles
  • organization_product_list-roles — Lists the roles assignable to a product member (system templates + product custom roles)
  • organization_product_me — Returns the caller’s own role on a product and the allow/deny grants it carries
  • organization_product_revoke-access — Revokes a product grant from an organization member. Access inherited from an organization role is lifted in the organization, and the product owner is removed by transferring ownership.
  • organization_product_select — Sets the active product of the Workspace console session and reconciles the active organization to that product’s organization. Console only: agents do not need it. Product-scoped tools take product_id; list products with organization_product_list.
  • organization_product_set-access — Grants an organization member access to a product, or changes the role they already hold, at a standard role (admin, member, viewer) or one of the organization’s named roles. The target must already be an active member of the product’s organization; owner is transfer-only, and access inherited from an organization role is changed in the organization.
  • organization_product_update — Updates an existing product’s name and/or description
  • organization_public-keys_create — Creates a public key for a product. The plaintext key is returned only in this response and cannot be retrieved again.
  • organization_public-keys_list — Lists a product’s public keys. Never returns key material.
  • organization_public-keys_revoke — Revokes a public key. Idempotent; revocation is permanent.
  • organization_public-keys_update-scope — Replaces the scope of an active public key.
  • organization_public-routes_list — Lists the public routes declared by the product’s toolkits, with each route’s access mode and public URL.
  • organization_reddit_install — Starts the Reddit OAuth connect flow for a product and returns the consent URL
  • organization_roles_create — Creates a reusable organization role with allow/deny permission patterns (owner/admin)
  • organization_roles_delete — Deletes an organization role (owner/admin). Already-materialized product grants are unaffected.
  • organization_roles_get — Gets a single organization role by id
  • organization_roles_list — Lists the reusable custom roles defined in an organization
  • organization_roles_update — Updates an organization role’s name or allow/deny patterns (owner/admin)
  • organization_security_mfa_enable — Turns ON organization-wide multi-factor authentication (2FA) enforcement for an organization. Owner-only: only the owner of the organization may call it. This is deliberately one-way — disabling MFA enforcement is not available over MCP; use the organization security settings in the Product App instead. The policy is strictest-wins across all of a member’s organizations, so enabling it here forces MFA enrollment for every member of this organization at their next sign-in or token refresh.
  • organization_select — Sets the active organization for the current session. Product-scoped tools are not affected: they take product_id; list products with organization_product_list. An archived organization cannot be selected: 409 organization_archived, and nothing changes.
  • organization_support_thread_create — Open a support thread owned by the caller’s organization — the body becomes the first message, authored by the caller. Every colleague can then read and answer it. Use when the user wants to contact Lessly support. Attach screenshots or logs by passing them in attachments as base64 — up to 10 files, each up to 25 MiB decoded; they travel in this same call and need no upload step of their own. If any file is refused the thread is opened but the message is not written, and the error names the file. A first message of files and no text is legal — omit body entirely; the title is always required.
  • organization_support_thread_get — Read one support thread of the caller’s organization with its full conversation, each message named after its own author. A thread of another organization — or another person’s legacy personal thread — is reported as not found.
  • organization_support_thread_reply — Reply in any support thread of the caller’s organization, as the caller. A thread of another organization is reported as not found. Attach screenshots or logs by passing them in attachments as base64 — up to 10 files, each up to 25 MiB decoded; they travel in this same call and need no upload step of their own. If any file is refused the reply is not posted at all, and the error names the file and what went wrong with it. A reply of files and no text is legal — omit body entirely.
  • organization_support_threads_list — List the support threads of the caller’s organization, most recently updated first — every member sees every one of them. Threads the caller opened personally before support became organization-wide are included and flagged legacy. Use when the user asks about their organization’s support requests or tickets.
  • organization_x_install — Starts the X (Twitter) OAuth connect flow for a product and returns the consent URL
  • organization_youtube_install — Starts the YouTube OAuth connect flow for a product and returns the consent URL
  • platform_auth_me — DEPRECATED — use organization_auth_me. Returns the current identity: identity ID, email, and identity type (e.g. “service” for a service token, which has no email)
  • platform_connectors_list — DEPRECATED — use organization_connectors_list. Lists active connectors in a product. A github-token row is a fine-grained GitHub token the product connected in the console: config carries repos, tokenLast4, expiresAt, permissions and autoDeploy; lastUsedAt and reauthReason (expiring, expired, revoked) are on the row. The token itself is never returned, and it is added or replaced in the console only.
  • platform_extensions_list-installed — DEPRECATED — use organization_extensions_list-installed. Lists extensions available to the given product
  • platform_product_create — DEPRECATED — use organization_product_create. Creates a new product with the given name. Returns the new product; pass its id as product_id to product-scoped tools.
  • platform_product_list — DEPRECATED — use organization_product_list. Lists all products the current user has access to
  • platform_product_list-members — DEPRECATED — use organization_product_list-members. Lists all active members of a product with their roles
  • platform_product_select — DEPRECATED — use organization_product_select. Sets the active product of the Workspace console session and reconciles the active organization to that product’s organization. Console only: agents do not need it. Product-scoped tools take product_id; list products with organization_product_list.

Realtime

28 tools.

  • realtime_archive_export — Start an async NDJSON export of a channel’s archived history to the product bucket. Returns an export id; poll realtime_archive_export_status until done.
  • realtime_archive_export_status — Check an archive export: status, and the NDJSON blob reference once done
  • realtime_archive_get — Read a channel’s durably archived history from Postgres (survives the Redis hot window). Offset-paginated: pass the returned next_offset as after_offset for the next page.
  • realtime_grant_create — Grant a subject (identity id or ”*” for all identities) operations on channels matching a pattern; ”*” in a pattern matches exactly one segment
  • realtime_grant_list — List realtime channel grants for this product. A non-empty subject restricts results to that subject; omit it to list all subjects.
  • realtime_grant_revoke — Revoke a realtime channel grant by id
  • realtime_history_get — Read message history of a realtime channel: either a cursor (offset + epoch, replays strictly after the offset; recovered:false on epoch mismatch or aged-out entries) or a window (last_n / last_ms). Conceptually requires the history capability; in Phase 1 this surface is Identity-authenticated management access.
  • realtime_messages_publish — Publish a JSON message to a realtime channel of the current product
  • realtime_namespace_create — Register a realtime namespace (the part of a channel name before the first colon) with its policy: visibility, presence, client events, history, encryption, identified-only
  • realtime_namespace_delete — Delete a realtime namespace by name (grants on it stop resolving)
  • realtime_namespace_get — Get a realtime namespace and its policy by name
  • realtime_namespace_list — List all realtime namespaces registered for this product
  • realtime_namespace_update — Update the policy of a realtime namespace
  • realtime_presence_enter — Enter presence on a realtime channel; upserts the caller (or member_id) into the roster
  • realtime_presence_get — Get the current presence roster for a channel. Roster is deduplicated by identity (connections counts live sockets); a per-connection view is deferred — the store is identity-keyed.
  • realtime_presence_leave — Leave presence on a realtime channel, removing the caller (or member_id) from the roster
  • realtime_presence_stats — Get the presence member count for a channel
  • realtime_presence_update — Update a presence member’s info and/or refresh its TTL
  • realtime_public_access_status — Check whether this product has a public key configured — an onboarding hint for the portal, never an authorization decision
  • realtime_status_get — Get realtime service status: Redis fan-out connectivity, token signing key presence, gateway URL
  • realtime_tokens_create — Mint a short-lived capability token (JWT) from namespace policy and grants, and return the gateway WebSocket URL. A non-empty channels list filters capabilities to matching channels; omit it to skip that filter. Namespaces with a subscription proxy still require concrete requested channels approved by the proxy.
  • realtime_webhook_create — Register a client webhook: lifecycle notifications (channel occupied/vacated, presence member added/removed) are POSTed to the URL signed with HMAC-SHA256. Returns the full signing secret ONCE.
  • realtime_webhook_delete — Delete a client webhook (its secrets and delivery log go with it)
  • realtime_webhook_deliveries_list — List recent delivery attempts of a webhook (status, attempts, response code)
  • realtime_webhook_get — Get a client webhook by id (secret metadata only, never the secret)
  • realtime_webhook_list — List all client webhooks registered for this product (secret metadata only)
  • realtime_webhook_secret_rotate — Rotate the webhook signing secret with an overlap window: the new secret signs immediately (returned ONCE), the previous one keeps verifying until its grace expiry
  • realtime_webhook_update — Update a client webhook: url, event filter, description, active flag

Support

53 tools.

  • support_agent_create — Create a support agent profile for this product. Binding a Lepsto identity is optional and the value is stored verbatim — nothing resolves it or checks that the user exists. An unbound profile is a bot or the client’s own backend, and it replies exactly like a human agent does
  • support_agent_get — Get one support agent by id, deactivated ones included. An agent belonging to another product is reported as not found. Through the public edge the profile comes back without lesslyUserId — the binding never leaves the authenticated plane
  • support_agent_list — List this product support agents by display name. Deactivated agents are hidden unless asked for: they keep every message they wrote but cannot take new threads. Through the public edge the profiles come back without lesslyUserId — the binding never leaves the authenticated plane
  • support_agent_update — Edit an agent profile. Pass null to clear the title, the avatar or the Lepsto binding; omit a field to leave it alone. Setting isActive to false deactivates the agent: it keeps every message it wrote and every thread it already sits on, but cannot be assigned to another one
  • support_attachment_create — Reserve a file on a support thread and get a short-lived signed URL to upload it to. The bytes never pass through this API: PUT them to the returned uploadUrl with the same Content-Type AND the header “x-goog-content-length-range: 0,26214400”, both of which the signature covers — omit either and storage refuses the PUT. Then call support_attachment_finalize, which checks that the first bytes really are the type you declared. Only the content types listed on the contentType field are accepted. A thread may hold at most 20 attachments waiting for their bytes at once; past that the call is refused with 429 and a message beginning “too_many_pending_attachments”. Until finalized the attachment is pending — it cannot be attached to a message and is invisible in message output. A thread belonging to another product is reported as not found
  • support_attachment_delete — Delete one attachment that no message carries — pending, uploaded or rejected — and its file in storage. The file is removed at once: a download URL issued before the delete stops working. Use it when a user removes a file from a message they have not sent, or to erase personal data. An attachment a message carries is refused with 409 and a message beginning “attachment_claimed”: delete the message instead with support_message_delete (your own) or support_message_delete_any (admin), which removes its files with it. If storage fails the call answers 503 with a message beginning “attachment_cleanup_failed”, nothing is lost, and repeating it is safe. Deleting the same attachment again answers not found. An attachment belonging to another product is reported as not found
  • support_attachment_finalize — Confirm that an upload landed. Storage is asked whether the object exists and how large it is; if it is not there the call is refused and the attachment stays pending. Its first 4 KiB are then read and checked against the content type the attachment was created with: if the bytes are something else — an svg uploaded as a png, html uploaded as text — the object is DELETED, the attachment becomes rejected, and the call answers 400 with a message beginning “attachment_rejected” and naming the reason. That state is terminal: calling finalize again returns the same 400, and the file must be created and uploaded afresh. On success the attachment becomes uploaded — it can now be named in support_message_create and carries a download URL served under the verified type. Calling it again on an uploaded attachment is safe and simply returns a fresh download URL
  • support_attachment_purge — Delete every attachment of a thread that no message carries — pending, uploaded and rejected alike — and their files in storage, for example to erase an end user’s data. Attachments carried by messages are left alone and counted in skippedClaimed; remove them by deleting their messages with support_message_delete or support_message_delete_any, then purge. On a thread that is still in use this can also remove a file a user is attaching right now — that is intended for erasure, and there is no “older than” option; the user’s message then fails to attach it and the file must be uploaded again. If storage fails part of the way the call answers 503 with a message beginning “attachment_cleanup_failed”: files already deleted stay deleted, and repeating the call finishes the rest. A repeat after success answers zeros. A thread belonging to another product is reported as not found
  • support_label_create — Add a label to this product label dictionary. A label is a free-form tag: nothing automates off it and a thread may carry any number of them. Names are unique per product
  • support_label_get — Get one label of this product label dictionary by id, in the same shape a list element has. A label belonging to another product is reported as not found
  • support_label_list — List this product label dictionary by name. A product that has invented no tags yet gets an empty list — unlike statuses, there is nothing to seed
  • support_message_create — Post a message into a support thread. A message has exactly one author: either an opaque external identifier from the client’s own user base, or a support agent — never both and never neither. Direction, authorship and visibility are independent: an internal note may be inbound or outbound. Posting a message moves the parent thread’s last reply timestamp. A message may carry files: create and finalize them first, then name them in attachmentIds. A message that names at least one attachment may leave body out entirely — a screenshot posted with nothing to say. Without attachments the body is required, and an empty body is refused either way. Through the public edge an agent author is accepted only if that agent carries no Lepsto binding — a bot or the calling backend; an agent bound to a Lepsto identity may author only from a signed-in session
  • support_message_delete — Delete a message you posted yourself. The message stays in the thread as a placeholder: its body becomes empty, it carries no attachments, deletedAt is set and its edit history is destroyed. Its attachment files are removed from storage immediately, and download URLs issued before the delete stop working. If removing a file fails, the delete answers an error and is safe to retry. Deleting an already deleted message succeeds again, removes any file still left and changes nothing else. Deleting a public message recomputes the thread last reply timestamp from the messages left; the thread status does not change. A message posted by someone else is refused as forbidden — an admin uses support_message_delete_any. A message belonging to another product is reported as not found
  • support_message_delete_any — Delete any message of this product as an admin — including an inbound message from the end user and a message nobody owns. Same soft delete as support_message_delete: the message stays as a placeholder with an empty body and no attachments, its edit history is destroyed, its attachment files are removed from storage immediately and download URLs issued before the delete stop working. If removing a file fails, the delete answers an error and is safe to retry; a repeated delete removes any file still left and changes nothing else. A message belonging to another product is reported as not found
  • support_message_get — Get one message by id, in the same shape a list element has — the files it carries included, each with a freshly signed download URL. An internal note is returned like any other message: visibility narrows the list, it does not hide a message from this tool. A message belonging to another product is reported as not found
  • support_message_list — List messages oldest first — the conversation reads forward. Name a threadId to read one thread, or omit it to read every thread of this product, which is how a client catches up on what it missed: pass since with the timestamp of the last message it has, then follow nextCursor until it comes back null. Paging is stable across messages that share a timestamp, so a walk neither skips nor repeats one. Filter by direction and by visibility; omit visibility to get public messages and internal notes together. A thread belonging to another product is reported as not found
  • support_message_revisions_list — List the earlier bodies of one message, newest first — one entry per edit, each with the body as it read before that edit and who made the edit. Empty for a message never edited, and empty for a deleted one: deleting a message destroys its history with it. A message belonging to another product is reported as not found
  • support_message_update — Edit the body of a message you posted yourself. Only the identity that created the message may edit it; a message posted by someone else, from the public edge or before authorship was recorded is refused as forbidden. The previous body is kept as a revision and editedAt is set. A deleted message cannot be edited (conflict). Sending the same body changes nothing. An edit does not move the thread’s last reply timestamp. A message belonging to another product is reported as not found
  • support_response_escalate — Turn a survey response into a feedback thread so a person can follow up. The thread opens on the product’s default open status, titled with the survey’s name, authored by the same external respondent, carrying the response metadata plus surveyResponseId, and rated with the response score when it fits 0..10. No message is written — the answers stay on the response, and neither the end user nor an agent typed anything. A response that was already escalated is refused with a conflict naming the thread it went to
  • support_response_get — Get one survey response by id, with its answers exactly as they were submitted. A response belonging to another product is reported as not found
  • support_response_list — List the responses of ONE survey, newest first — surveyId is required, because a page mixing two surveys would carry answers keyed by two different question sets. Filters: score range (scoreMin/scoreMax, inclusive — a response with no score matches neither bound), a creation window (from/to), completed, plus pagination
  • support_rule_create — Write a delivery rule: where a survey should be shown (a URL match), on which devices, when (immediately, after a delay, or on the client’s own event) and how often. Nothing here runs on this side — the rule is configuration a client’s own runtime reads back through the public edge and acts on. A rule reaches that edge only while its survey is published, so a rule may be written against a draft and simply waits
  • support_rule_delete — Delete a delivery rule for good. Unlike a survey, a rule is not archived — it has no responses behind it and nothing outlives it, so the row is removed and cannot be recovered. The survey it targeted is untouched. To stop delivery reversibly, set enabled to false instead
  • support_rule_get — Get one delivery rule by id, with its whole configuration. A rule belonging to another product is reported as not found
  • support_rule_list — List this product’s delivery rules, newest first. Supply surveyId or enabled to filter by survey or live state; omit both to include all surveys and both states. Supply url to match a page and device to match its device type. With url but no device, only rules targeting any device match; omit both to skip page and device matching. The client runtime reads the public edge, which requires url and returns only live rules on published surveys.
  • support_rule_update — Edit a delivery rule: its URL match, device, trigger, frequency, conditions, or whether it is live at all. Every value replaces the old one whole rather than merging into it. The survey is not editable — a rule is the targeting OF one survey, and retargeting it silently would change what every matching page shows; delete it and write the one you meant. Switching a rule off is the quiet way to stop delivering without touching the survey
  • support_status_archive — Retire a status. There is no way to delete one: every thread on it moves to the target status in the same transaction, so no thread is ever left on an archived status. The target must be a different, live status of this product
  • support_status_create — Add a status to this product status dictionary. The name is what people see; the category is what automation and reporting read, and it cannot change once threads sit on the status
  • support_status_get — Get one status of this product status dictionary by id, in the same shape a list element has. An archived status is returned like any other — hiding it is the list job, not this one. A status belonging to another product is reported as not found
  • support_status_list — List this product status dictionary in display order. A product that never opened settings gets the four defaults seeded on the first call. Archived statuses are hidden unless asked for
  • support_status_update — Rename, recolour or reorder a status. The category may only change while no thread references the status: changing it later would rewrite the history of every metric derived from it. A status belonging to another product is reported as not found
  • support_survey_archive — Switch a survey off for good, from either draft or published. Archiving is terminal — there is no way back in v2 — and it deletes nothing: every response already collected stays readable
  • support_survey_create — Open a new survey. It starts as a draft — editable and not yet answerable — whatever questions travel with it. There is no way to create one already published: publishing runs the structure validator, and a create that skipped it would be a second way in
  • support_survey_get — Get one survey by id, with its whole question set. A survey belonging to another product is reported as not found. Through the public edge only a PUBLISHED survey is readable — a draft or an archived one is reported as not found there
  • support_survey_list — List this product’s surveys, newest first, with pagination. Supply status to return only draft, published or archived surveys; omit status to include all three states.
  • support_survey_publish — Publish a draft survey, which is what makes it answerable and what freezes its structure. Publishing validates the whole question set: it must be non-empty, question ids must be unique, radio and checkbox questions must offer options, a statement may not be required, and every skip must target a later question or the literal “end”. A survey that is already published or archived is refused
  • support_survey_stats — Aggregate one survey’s responses over a time window: how many came in and how many reached the end, then per question — option counts for radio and checkbox, mean and distribution for rating and nps, an answered count for the rest. For the FIRST nps question it also returns promoters (9-10), passives (7-8), detractors (0-6) and the NPS score: percentage of promoters minus percentage of detractors over everyone who answered, rounded once. The window defaults to the last 30 days — omitting from does not mean “since the beginning”
  • support_survey_unpublish — Return a published survey to draft so it can be edited. It stops accepting responses immediately; the responses already collected are untouched. A survey that is not published is refused
  • support_survey_update — Edit a survey’s name or question set. Only a draft is editable — publishing freezes the structure, because answers are keyed by question id and rewriting the questions under them would change what every collected response was answering. To edit a live survey, unpublish it first. questions replaces the whole set; pass an empty array to clear it
  • support_thread_assign — Put a support agent on a thread, or pass null to return it to the unassigned queue — clearing an assignment is an ordinary operation, not an error. An agent belonging to another product is reported as not found
  • support_thread_create — Open a support thread on behalf of an external end user. The author is an opaque identifier from the client’s own user base and is stored verbatim. The thread opens on the product’s default open status; there is no status argument. An optional rating — an integer 0..10, both ends inclusive — may travel with it and is stored verbatim too; omit it for an unrated thread, because 0 is a real score at the bottom of the scale
  • support_thread_get — Get one support thread by id, with its status joined in. A thread belonging to another product is reported as not found
  • support_thread_list — List support threads for this product, newest first — by creation time by default, or by last modification with sort=‘updated’. Every filter lives here: type, status, status category, assignee, external author, creation window, rating range (ratingMin/ratingMax, inclusive — a thread nobody rated matches neither bound), plus pagination
  • support_thread_status_set — Move a thread to a status. Any status may follow any other — there are no transition rules. The category is never a parameter: it comes from the status the thread lands on. A status belonging to another product is reported as not found, and an archived status is refused
  • support_thread_update — Edit a thread: its title, its priority, its labels and its client-owned metadata. Moving a thread between statuses and putting an agent on it have their own tools and are not possible here. labelIds replaces the entire label set — pass an empty array to clear it, and a label belonging to another product is reported as not found
  • support_webhook_create — Register an HTTPS endpoint to receive Support events for this product, and mint its signing secret. The secret is returned here in clear and NOWHERE ELSE — exactly once, so store it now: it cannot be read back and can only be replaced by rotating it. Plain http:// endpoints are rejected
  • support_webhook_delete — Remove a registered endpoint and the delivery history that points at it. To stop delivery without losing the registration, set its status to disabled instead
  • support_webhook_deliveries_list — List webhook delivery attempts for this product, newest first. Filter by endpoint, by state (pending, delivered, failed), by event type or by the time the delivery was opened. Each row carries the exact JSON body that was sent, the last HTTP status and, while attempts remain, when the next one is due
  • support_webhook_get — Get one registered endpoint by id. The signing secret is not part of the answer. An endpoint belonging to another product is reported as not found
  • support_webhook_list — List the endpoints this product has registered, oldest first. Signing secrets are never included — only the short prefix that tells two endpoints apart
  • support_webhook_redeliver — Send a past delivery to its endpoint again, with the original payload and the original idempotencyKey — a receiver that already processed it can recognise and ignore the repeat. The original delivery row is kept as history and a new one is opened for this attempt. If the endpoint has since been disabled or unsubscribed from the event, nothing is delivered
  • support_webhook_rotate_secret — Replace the signing secret of an endpoint and return the new one in clear, exactly once. The old secret stops verifying immediately — there is no grace window, so update the receiver before rotating
  • support_webhook_update — Edit a registered endpoint: its url, the event types it subscribes to, its description or its status. Setting status to disabled keeps the registration and stops delivery. Omit a field to leave it alone; pass null to clear the description. The signing secret is not editable here — rotate it instead

Tracking

45 tools.

  • tracking_domains_create — Claim a first-party tracking host under a product domain
  • tracking_domains_delete — Release a tracking-host binding
  • tracking_domains_get — Get one tracking-host binding and its status
  • tracking_domains_list — List the product’s custom domains and tracking-host bindings
  • tracking_domains_verify — Run an immediate liveness check for a pending binding
  • tracking_entitlement-drops_get — Report the /collect events and session recordings this product lost this UTC month because billing refused to store them (trial monthly limit reached, billing paused). Counts events that were never stored; tracking_reports_event_volume counts the events that were. Returns: { month, drops: { droppedEvents, droppedBatches, droppedRecordings, firstDroppedAt, lastDroppedAt, lastReason, upgradeUrl, plan } | null }. Fails when: the call carries no product.
  • tracking_event-names_archive — Archive an event name (hides it from dashboards only; ingestion and counts continue unchanged).
  • tracking_event-names_list — List the event-name catalog for the current product with counts, first/last seen, sampled prop keys, and status.
  • tracking_event-names_set-conversion — Mark an event name as a conversion, or unmark it. A marked name publishes tracking/conversion.recorded every time that event is recorded, which a workflow can trigger on; an unmarked one publishes nothing. Ingestion, counts and dashboards are unchanged either way.
  • tracking_event-names_unarchive — Unarchive an event name (restores its visibility in dashboards).
  • tracking_googleads_connection_status — Google Ads connection status for the current product: whether a Google Ads account is connected and which account (loginCustomerId / customerId), or whether it still needs account selection or re-auth.
  • tracking_googleads_conversion_actions — List the connected Google Ads account’s conversion actions (resource, name, category, status) so you can map a tracked event to a Google conversion action with a per-rule value (net revenue or a fixed amount).
  • tracking_googleads_feedback_config_get — Get the Google Ads conversion-feedback config for the current product (enabled, mode, lookbackDays, event→conversion-action rules, accountCurrency — the connected account’s currency, best-effort, null if unavailable — useful for defaulting a fixed-value rule’s currency, and dynamicValueEvents — the revenue-eligible event-names that may use the Dynamic value source).
  • tracking_googleads_feedback_config_set — Set the Google Ads conversion-feedback config (enable/disable, mode, lookback, rules, enhancedConversions). enhancedConversions adds hashed email/phone as additive match keys alongside gclid. Returns the config plus safety guidance. Rules are validated against the account’s conversion actions.
  • tracking_googleads_feedback_run — Manually run one conversion-feedback upload pass for the current product now (uploads newly-attributed conversions across all enabled rules since the last run). Useful for testing; the daily cron runs this automatically.
  • tracking_googleads_feedback_status — Google Ads conversion-feedback status for the current product: enabled/mode, rule count, cumulative uploaded/failed counts, last-run coverage (selected vs matched vs uploaded, plus noGclid so gclid-match coverage is visible), safety guidance, accountCurrency (the connected account’s currency, best-effort, null if unavailable), and dynamicValueEvents (the revenue-eligible event-names that may use the Dynamic value source).
  • tracking_googleads_feedback_uploads — List the most recent Google Ads offline-conversion uploads for the current product (per-row ledger: conversionKey, gclid, conversionAction, conversionDatetime, valueMicros, currency, orderId, status, error, uploadedAt). Newest first. Query: limit (default 100, max 500).
  • tracking_googleads_roas_report — Reads what each Google Ads campaign cost and what it earned back, with ad groups and ads nested underneath. Return on ad spend and cost per customer are worked out at campaign level from the revenue we traced ourselves; spend, impressions, clicks and Google’s own conversion counts are there at every level. Each account currency is reported separately and never added to another. Covers the last 30 days unless a window is given.
  • tracking_googleads_sync_now — Pull the current product’s Google Ads campaign/ad-group/ad structure and daily spend/metrics into the reporting tables now (backfill window). Returns per-table row counts. Skips gracefully if the account is pending selection or needs re-auth.
  • tracking_googleads_tracking_health — Google Ads URL-tracking health for the current product over a date range: how many Google paid clicks arrived, how many carried our ValueTrack URL parameters (marker _lt_campaign) vs how many were UNTAGGED (template not installed / broken), the breakage rate, whether the template is verified live, first/last untagged times, sample offending landing URLs. Read-only; computed on the fly from stored events (no Google Ads API call). dataQuality describes how complete the figures above are and holds no metric of its own: dataQuality.cookielessPaidClicks is how many of the paid clicks arrived cookieless (the visitor declined consent) — counted INSIDE paidClicks, never added to it, because a cookieless paid click is a real click and belongs in the breakage denominator. It is broken out so breakageRate is not read as one homogeneous population. Clicks from sites running no consent banner at all are NOT counted as cookieless: nobody was ever asked there, which is not the same as being told no.
  • tracking_googleads_us_vs_platform — Puts our own revenue and customer counts beside the conversions Google reports, one row per campaign, so the gap between the two is visible. Both sides stay in the account currency and are never converted. Use it to decide which number to trust before acting on either. Covers the last 30 days unless a window is given.
  • tracking_heatmaps_get — Get the heatmap of one page for one device: where visitors clicked (per element, on a 50x50 grid inside it), how far they scrolled, and which recording to draw the page from. sessions counts the recordings of the period and filters with a click or a scroll sample on the page — the same recordings tracking_recordings_list returns with the same device, campaign, source and conversion filters. scroll.reached[i] is a share of the sessions that reported a scroll depth on the page (a click-only session reports none), reaching (i+1)*5% of its height. Below 10 sessions the map is withheld: belowThreshold is true, clicks and scroll.reached are empty. Returns: { sessions, belowThreshold, clicks, scroll, background }. Fails when: the period is longer than 30 days; the call carries no product.
  • tracking_heatmaps_pages — List the pages of the current product that have heatmap data (clicks, scroll depth) from session recordings, most sessions first. A page is host + normalized path (no query, no hash, ids replaced by *). Filter by period (required, at most 30 days), device, campaign, source, conversion and page text; cursor-paged. sessions counts the recordings with a click or a scroll sample on the page, selected like tracking_recordings_list with the same filters. Returns: { pages, nextCursor }. Fails when: the period is longer than 30 days; cursor is not one this tool issued; the call carries no product.
  • tracking_identity_health — Identity match-rate metric: share of identified profiles and share with an ad touchpoint (proxy = has >=1 click_id identifier).
  • tracking_install-domains_create — Register a domain in the install-verification checklist for the current product
  • tracking_install-domains_delete — Remove a domain from the install-verification checklist for the current product
  • tracking_install-domains_list — List install-verification domains for the current product with per-domain “script seen” status, plus auto-discovered domains sending events
  • tracking_link-domains_create — Add a root domain to the cross-domain linking group for the current product
  • tracking_link-domains_delete — Remove a root domain from the cross-domain linking group for the current product
  • tracking_link-domains_list — List the cross-domain linking group (domains whose links the tracking script decorates with the visitor id) for the current product
  • tracking_live-events_list — List recent tracking events for the current product, cursor-paged for incremental polling. From the rollout, a d: anonymous id marks a cookieless one-day visitor rotating every UTC midnight, never a toolkit profile; these events appear as separate people each day in funnels, person counts and retention. Filter consent_statistics = true for consented-only figures and always for retention.
  • tracking_profiles_delete — GDPR erasure: permanently delete a person and their events from Postgres and record an erasure request. Archived events are flagged as a deletion gap.
  • tracking_profiles_export — Export a person as JSON: profile + identity signals + full journey (capped at 50k events; truncated flag set if exceeded).
  • tracking_profiles_get — Get one person: profile, identity signals, and their chronological journey (query-time join over the person’s anonymous ids).
  • tracking_profiles_list — List/search people (profiles) for the product; filter by email and status, cursor-paged.
  • tracking_recording-settings_get — Get the session recording setting of the current product: whether recording is on, the percent of sessions recorded, the hosts whose pages are recorded, and candidate hosts to choose from. Off at 0% with no hosts until it is set; on with no hosts records nothing. Returns: { enabled, sampleRate, hosts, candidateHosts }. Fails when: the call carries no product.
  • tracking_recording-settings_set — Turn session recording on or off for the current product, choose the hosts whose pages are recorded, and set the percent of sessions recorded (1 to 100 when on). Turning it on requires at least one host: list only the sites meant to be recorded (e.g. the marketing site, not an app or console showing customer data — page text is recorded as shown). tracking_recording-settings_get returns candidate hosts. Browsers pick the change up within about 10 minutes; the server applies it to new data within a minute. Returns: { enabled, sampleRate, hosts }. Fails when: enabled is true and hosts is missing or empty (“choose at least one host to record”); a host is not a bare hostname; more than 20 hosts; sampleRate is outside 1..100 while enabled; the call carries no product.
  • tracking_recordings_chunks_get — Get the rrweb events of one segment of a recording for playback, one page at a time (about 2 MiB of events by default); follow nextSeq until it is null. Lost or undecodable stretches are reported in gaps, never as an error. Returns: { events, gaps, nextSeq }. Fails when: the recording is not visible in this product or has no such segment.
  • tracking_recordings_get — Get one session recording: its summary, its segments (page loads, in play order) and the tracker events of the recording itself (its hosts, its time span) with their offset on the player clock, for a timeline, and the first conversion of the session after the recording. Returns: the summary plus { clockOffsetMs, segments, events, eventsTruncated, laterConversion }. Fails when: no recording with that id is visible in this product.
  • tracking_recordings_list — List session recordings of the current product, newest first: who (profile), how they arrived (entry page, utm, ad click), device, length, and whether the session converted. Filter by period (default the last 30 days), person, visitor, device, campaign, source, entry page, conversion and minimum length; cursor-paged. Device, campaign, source and conversion select the same recordings as tracking_heatmaps_get with the same filters. Returns: { items, nextCursor }. Fails when: cursor is not one this tool issued; the call carries no product.
  • tracking_reports_attributed_journey — One person’s journey with, for their originating conversion, the attribution decision explained (winning touchpoint + why) under the requested model and lookback window. Attribution is never locked in — changing model/window re-reads the same history.
  • tracking_reports_event_volume — Traffic for a date range as TWO headline figures plus a data-quality block. totalEvents counts events. visitorsDeduplicatedPerUtcDay counts PEOPLE, over both populations at once: consenting and no-banner visitors by anonymous_id, cookieless visitors by server-derived daily_visitor_key. It is one COUNT DISTINCT, not a sum of two figures, and there is no second set of numbers to add to it. READ THE FIELD NAME LITERALLY — the daily key rotates every UTC midnight, so a returning cookieless visitor is counted again. From the rollout, that key also appears as anonymous_id = d:<daily key> on the event: a one-day graph person, never a toolkit profile. These visitors enter funnels, person counts and retention as separate people each day. Weekly and monthly uniques are OVERSTATED for this traffic; filter consent_statistics = true for consented-only figures and always for retention, returning-visitor, frequency and loyalty analysis. dataQuality.visitorsOverstated tells you whether the over-count applies to this window, and dataQuality.utcDaysInRange gives its UTC-day span. dataQuality describes how COMPLETE the two headline figures are and contains no metric of its own — never present anything inside it as a headline number and never add it to anything. cookielessShare and noBannerShare are the fractions of events from cookieless visitors and from sites with no banner. consentGrantedEvents + cookielessEvents + noBannerEvents = totalEvents. noBannerEvents (nobody was ever asked) stays distinct from cookielessEvents (denied or undecided). identifiedEvents counts only non-cookieless events carrying an anonymous_id, excluding d: rows; never add it to the consent buckets.
  • tracking_reports_revenue_by_source — Revenue attributed by channel + UTM breakdown for a date range, under a chosen attribution model and lookback window. Includes a distinct unattributed row, totals, and a count-based match rate. Revenue is per-currency (never summed across currencies); refunds are netted explicitly.
  • tracking_reports_source_people — List the people (profiles) behind one channel / UTM row from the revenue-by-source report, under the same model + window. Keyset-paginated; each person carries their attributed lifetime revenue per currency.
  • tracking_snippets_get — Get the tracking snippet for the caller’s current product. Install it unconditionally. Do NOT wrap it in a consent gate and do NOT load it only after consent is granted: the tracker reads the visitor consent decision itself and switches to a cookieless mode that writes no cookies and sends no identifiers when statistics consent is declined or not yet given. Gating this tag makes declining and undecided visitors invisible entirely — the failure this behaviour exists to prevent. Set consentBanner: true when the page runs the Lepsto consent banner. Without it, a tracker that loads before the banner sees no consent API yet and can write cookies before the visitor decides. Do NOT set it on a page without the banner: the tracker would then wait for a decision that never comes and stay cookieless for every visitor.

Users

49 tools.

  • users_apikeys_create — Issue an API key for this product. type=‘publishable’ mints a non-secret browser key (upk_…) that only names this product and stays readable afterwards. It is the only type: the secret server key (usk_…) is retired — the one route it authorized is now checked by the public edge against the product’s platform public key.
  • users_apikeys_get — Read ONE of this product’s API keys by id — its label, type, visible prefix, when it was issued and whether it has been revoked. The same shape users_apikeys_list returns per row. A server key’s SECRET is not here and never will be: that value existed in exactly one response, ever, and what is stored is a hash. An unknown id, a malformed id and a key belonging to another product all answer alike.
  • users_apikeys_list — List this product’s API keys, newest first — id, label, type, visible prefix and revocation state. A server key’s secret is never here; a publishable key’s full value is, because it is not a secret.
  • users_apikeys_revoke — Revoke an API key immediately. A revoked server key stops authenticating code exchanges on the next request; there is no grace period and no un-revoke.
  • users_audit_list — Read this product’s audit log, newest first. Every management-plane mutation writes one entry (user.created, user.updated, user.deleted, user.banned, user.unbanned) with the actor, target and timestamp. Filter by action, target and time range; paginate with the opaque nextCursor.
  • users_config_get — Read this product’s end-user auth configuration (signup mode, password policy, session lifetime). Returns the defaults when nothing has been configured yet.
  • users_config_upsert — Create or update this product’s end-user auth configuration. Only the fields you pass change; the rest keep their current values. Rejected while the product is paused (archived or blocked by the platform). email.templates sends an auth email from a PUBLISHED template in this product’s mail toolkit instead of the built-in one ({ “<purpose>”: “<template id>” }, null unbinds). The template is not checked by this server: if mail cannot render it at send time, the built-in email is sent instead and the fallback is audited. Variables Users passes, per purpose (* = required: the template must use it; ? = sent only sometimes, so the template must not require it; the rest are always sent): sign_in: code*, expires_in_minutes, link_url? verify: code*, expires_in_minutes, link_url? password_reset: link_url*, expires_in_minutes invite: link_url*, expires_in_minutes email_change_confirm: link_url*, expires_in_minutes email_change_approve: link_url*, expires_in_minutes, new_address email_change_revert: link_url*, expires_in_minutes, new_address email_change_override_cancel: link_url*, expires_in_minutes, new_address, takes_effect_in password_changed: none new_device: browser? email_change_completed: none email_change_reverted: none mfa_reset_scheduled: link_url*, expires_in_minutes, takes_effect_in mfa_reset: none impersonation: reason waitlist_confirm: link_url*, expires_in_minutes waitlist_joined: link_url*, expires_in_minutes
  • users_factors_list — List the MFA factors an end user has enrolled: totp (an authenticator app) and backup_codes (single-use recovery codes), each with its status (unverified until enrollment was confirmed — an unverified factor gates NOTHING), when it was created and confirmed, and when it was last used. Backup codes also report remaining, the number still unspent; a user at 0 can no longer use that factor and should regenerate. NO SECRET IS EVER RETURNED — not the TOTP secret, not a backup code, not a digest of one. A user with no factors returns an empty list, which also means their sign-in completes at aal1.
  • users_factors_reset — OPERATOR RESET of an end user’s MFA, for the case the normal recovery cannot serve: the user lost their authenticator AND their backup codes. This does NOT remove anything now. It SCHEDULES the removal behind this product’s mandatory delay (config mfa.resetDelayHours, default 72) and immediately emails the user’s primary address an abort link; if that mailbox is alive and its owner clicks, nothing happens. When the delay elapses, EVERY factor is deleted, every backup code with it, and EVERY SESSION of that user is revoked (a session that reached aal2 must not outlive the factor that earned it) — after which the user signs in with their first factor alone and enrolls again. Every step is audited (factor.reset_scheduled / _cancelled / _applied) with the reason you pass, so do the identity proofing FIRST and write down what it was: this tool is a supervised account takeover, and the trail is what makes it reviewable.
  • users_keys_list — List this product’s JWT signing keys, newest first: the key id (the kid a token header carries), its lifecycle state, and when it was created, retired and revoked. current signs; retired no longer signs but is STILL published in JWKS until overlapExpiresAt, so tokens it signed keep verifying; standby is the pre-generated successor and is not published; revoked was evicted from JWKS immediately. Key material — public or private — is never returned here.
  • users_keys_revoke — THE KEY-COMPROMISE DRILL. Evict a signing key from the published JWKS IMMEDIATELY — no overlap, no grace — so every token it ever signed stops verifying at once, mint or promote a fresh signing key in its place, and (by default) sign every end user of this product out, because a token the attacker forged with the stolen key is indistinguishable from a real one. Pass revokeSessions: false only when you are certain no forged token was issued. Give a reason: it is the only account of the incident the audit log will keep. This is disruptive and irreversible — for routine rotation use users_keys_rotate.
  • users_keys_rotate — Rotate this product’s JWT signing key with ZERO verifier downtime. The standby key (generated now if there is none) becomes the signing key, and the old one is retired into an overlap window — BOTH key ids stay in the published JWKS until overlapExpiresAt, so every token signed before the rotation keeps verifying for the rest of its life and no verifier has to re-fetch anything to keep working. The overlap is the product’s access-token TTL plus five minutes. After it elapses the old key is revoked automatically and stops verifying. Use users_keys_revoke instead if the key is COMPROMISED and must die now.
  • users_ops_retention_get — What this product keeps and for how long. Returns the EFFECTIVE retention windows (spent one-time tokens, expired flow attempts, expired sessions and their refresh tokens) next to the documented defaults, the separate waitlist-entry window, the single cron that performs every sweep, and — deliberately — the list of what is NEVER swept and why. For the waitlist it also answers the two questions a published retention promise raises: whether this product’s window is WIDER than the 180 days Lepsto published (waitlistWiderThanPromised, a flag rather than a refusal), and whether the job that honours it is actually running — lastSweep carries the last pass this replica performed, counting THIS product’s erasures only, and is NULL when it has observed none — which is not the same as a pass that erased zero. The windows are GRACE PERIODS ON TOP OF EXPIRY, never lifetimes: every live read carries its own expiry predicate, so an unswept expired row is inert and a window of 0 shortens nothing. Change them with users_config_upsert retention.
  • users_ops_slo_get — This product’s service-level objectives and how it is doing against them RIGHT NOW: sign-in success rate, refresh error rate and mail-send failure rate, each with the objective, the evaluation window, the sample floor below which it is not judged, and the users/alert.raised kind a breach fires. Also returns the raw current window (sign-ins, refreshes, detected token reuse, mail sends) and the product’s own trailing sign-in failure baseline — the number the per-product anomaly signal compares a spike against. A status of insufficient_data is NOT health: it means the window is too quiet to judge. The numbers come from ONE replica’s in-process window, so treat them as a spot check rather than a fleet-wide error budget.
  • users_passkeys_get — Read ONE passkey of an end user by id — the name they gave it, its transports, the authenticator model’s aaguid, whether it is backedUp, its sign counter and when it was last used. The same shape users_passkeys_list returns per row. NO KEY MATERIAL IS EVER RETURNED: the public key is deliberately absent here as it is there. A credential id that belongs to another user answers 404 exactly like one that never existed.
  • users_passkeys_list — List the passkeys (WebAuthn credentials) an end user has registered: the credential’s id, the name the user gave it, its transports (internal is a platform passkey on the device itself, usb/nfc/ble a security key, hybrid a phone used from another device), the authenticator model’s aaguid, whether the credential is backedUp (synced by the platform, so it survives losing the device), its sign counter and when it was last used. NO KEY MATERIAL IS EVER RETURNED — the public key is deliberately absent: nothing on this plane needs it, and it is a stable cross-site fingerprint for the device holding it. A user with passkeys signs in without a password, and reaches aal2 in one gesture whenever their authenticator verified them.
  • users_passkeys_revoke — REVOKE ONE passkey — the support path for a lost or stolen device. It takes effect IMMEDIATELY and permanently: that credential can never sign in again, and the user re-registers from a device they still hold. It is REFUSED (status: 'failed', code passkey_last_way_in) when this credential is the account’s only remaining way in — no other identity and no verified identifier — because removing it would strand the account forever; add another way in first. It cannot CREATE a passkey: there is no admin-side registration in this toolkit at all, since a credential an operator could enroll is one they could keep. Every revoke is audited (passkey.deleted) with the reason you pass, so do the identity proofing FIRST and write down what it was.
  • users_sessions_get — Read one end-user session in full: its status, device metadata, both expiries, the assurance level and factors it was established with, why it was revoked if it was, and the operator behind it if it is an impersonated session.
  • users_sessions_impersonate — Start an impersonated session as one user of this product — support access, hard-capped. Returns an access token that expires within 30 minutes and CANNOT be refreshed; there is no refresh token. While it is in use, every credential, factor, identifier and session mutation is refused, the user is emailed (unless the product turned that notice off), and the whole thing is recorded in the audit trail against you. Give a real reason: it goes into the audit row and into that email.
  • users_sessions_list — List the end-user sessions of one user of this product, newest first — one row per device, with its status, device metadata and both expiries (the sliding inactivity window and the hard time-box). Revoked and expired sessions are included so an operator can see what happened, not only what is live.
  • users_sessions_revoke — Revoke end-user sessions: pass sessionId to sign out one device, or userId to sign out every device of that user. Revocation is immediate in this toolkit’s own checked verification; an access token already issued keeps verifying locally until it expires (≤10 minutes by default). Returns how many sessions this call actually revoked — a second call on the same target returns 0.
  • users_stats_get — One snapshot of this product’s auth deployment: directory users split by DERIVED status (active, contacts, waitlisted, banned, soft-deleted, GDPR-erased), sessions that are live right now, verified second factors, the sign-in success rate over window, and an abuse block — lockouts (with the MFA subset), failed sign-ins, detected refresh-token reuse and breached-password sightings. The populations are point-in-time; only the sign-in and abuse numbers honour window. A rising abuse block against a falling success rate is what credential stuffing looks like from here. successRate is null, not 0, when nothing was attempted.
  • users_touches_create — Log an interaction with a person — a message, a call, a meeting, a note, or an email sent OUTSIDE the platform. Email this toolkit sent is NOT logged here; read those from the mail toolkit. occurredAt is when it HAPPENED and may be backdated; omit it to mean now. A ‘note’ or a ‘meeting’ takes direction ‘none’. Who logged it is taken from your identity and can never be set from the body.
  • users_touches_discard — Discard a touch you logged. A touch somebody ELSE logged answers 404, exactly as a touch that does not exist does. Pass force: true to remove it anyway, which is recorded in the audit trail along with the original author. There is no undo.
  • users_touches_list — List a person’s logged interactions, newest first — by when they were LOGGED, so a backdated touch still appears on the first page. Filter by channel. Paginate with the opaque nextCursor.
  • users_touches_update — Correct a touch you logged — its text, when it happened, or both. A touch somebody ELSE logged answers 404, exactly as a touch that does not exist does: the refusal must not tell you the row is there. Pass force: true to edit it anyway, which is recorded in the audit trail along with the original author.
  • users_users_ban — Ban an end user by stamping bannedAt and revoking their live sessions. Banned users are refused at sign-in. Banning an already-banned user refreshes the stamp.
  • users_users_create — Create an end user of this product with at least one email identifier. Supply password to store a password hash; omit it to create the user without a password identity. Supply only hashes in password fields; do not send plaintext passwords. Only one verified copy of an email is allowed per product; unverified duplicates are allowed. Pass kind: "contact" to record somebody the Product knows who cannot sign in: a contact may not carry password, waitlisted or requiresReset (refused with contact_cannot_hold_credentials), is hidden from the default users_users_list view, and is never counted as a retained user. stage and tags set the relationship state; tags are stored trimmed, lowercased and de-duplicated. Besides email, an identifier may be a CONTACT CHANNEL — phone, telegram, linkedin or x. A channel is how to REACH somebody, not how they sign in: it is always stored unverified (a verified: true on one is ignored), it can never start a sign-in, carry a one-time code or be verified, and it is canonicalised by its own rule — phone to E.164 (+7 (999) 123-45-67 is stored +79991234567), telegram and x lowercased without a leading @, linkedin to the public-profile slug, so a full linkedin.com/in/<slug> URL and the bare slug are one value. A value that does not fit its type is refused with invalid_identifier. One record may not carry the same channel twice (duplicate_identifier), but two different people MAY share one — a company phone is not a conflict. A contact may carry a channel and no address at all.
  • users_users_delete — Soft-delete an end user: the record is retained with deletedAt set and disappears from the default list. This is NOT GDPR erasure — no data is purged, and the user can still be fetched by id.
  • users_users_export — Export the end users of this product as pages of full records (profile, identifiers, metadata bags), using the same filters as users_users_list. Password hashes are NEVER included — neither a PHC hash nor an imported foreign one. Exporting credentials is deferred to a later phase, behind explicit elevated approval; until that gating exists, a hash cannot leave this toolkit. Every call is AUDITED (action users.export, with the filter and the row count), so this is not a silent read: use it for migrations, backups and subject-access requests, not as a listing shortcut. Filter by kind, or pass includeContacts: true, to export accounts and contacts in one pass — contacts are excluded by default, the same rule this export already applies to waitlist signups and test users. Page through with nextCursor. Identifiers include contact channels (phone, telegram, linkedin, x) alongside emails; a channel is always unverified.
  • users_users_get — Fetch one end user of this product by id, including their identifiers and metadata bags. Soft-deleted users are still returned (with deletedAt set). Identifiers include contact channels (phone, telegram, linkedin, x) alongside emails; a channel is always unverified.
  • users_users_import — Bulk-import end users into this product, up to 500 rows per call — batch client-side beyond that. Hashes only: pass password.phcHash for an argon2id PHC string, or password.foreignHash + foreignHashAlgo (bcrypt/argon2/pbkdf2/scrypt) for a hash from the system you are migrating off. A foreign hash is stored INERT — nothing verifies it until sign-in, when it is checked once and rehashed — so set requiresReset: true on rows whose source hash you do not trust. IDEMPOTENT by canonical identifier: a row whose email already exists VERIFIED in this product is skipped, not duplicated, so re-running the same file is safe. Imported identifiers default to verified (unlike users_users_create) — pass verified: false per identifier for addresses the source system never confirmed. Returns a PER-ROW report ({row, status, userId, reason}) plus counts: one malformed row never fails the batch. Emits ONE batch event (users/user.imported, with counts) rather than a per-user created event, and writes ONE audit row. Rows may be CONTACTS (kind: "contact" — known to the Product, no credential, never signed in); a contact row carrying password, waitlisted or requiresReset comes back as a FAILED ROW with contact_cannot_hold_credentials, never as a rejected batch. The result and the users/user.imported event carry a contacts count of the rows actually created. Contact channels (phone, telegram, linkedin, x) import as UNVERIFIED regardless of this tool’s verified: true default — nothing here can prove a phone or a handle, so there is no confirmation to carry over. A row whose channel value does not fit its type comes back as a FAILED ROW with invalid_identifier, never as a rejected batch.
  • users_users_invite — Invite somebody to this product by email. Creates the user immediately with an UNVERIFIED identifier and NO credential — they appear in users_users_list straight away but cannot sign in until they accept — then mails a one-time invite link. Accepting the link sets their first password and verifies the address; no session comes from the link itself. IDEMPOTENT by address: re-inviting returns the SAME user (created: false), and whether it re-mails is a cooldown decision, so pressing the button twice cannot flood a mailbox (mailed: false means the invite is live but no email went out this time). Refuses an address that already belongs to a signed-up user. Requires a verified sender in this product’s mail toolkit (config email.from); without one nothing is sent and mailed is false.
  • users_users_list — List the end users of this product, newest first. Filter by an identifier/name substring and by status. Soft-deleted users are hidden unless includeDeleted is true. CONTACTS — people the Product knows who have no credential and have never signed in — are hidden by default, exactly as waitlist signups and test users are; pass kind: "contact" to list only them, or includeContacts: true to see both. Filter further by stage (new, contacted, replied, engaged, converted, lost) and by a single tag, both ANDed with everything else. query matches a substring of the display name or of ANY identifier’s canonical value — an address, a phone in E.164, a handle. Paginate with the opaque nextCursor.
  • users_users_set_primary_identifier — OPERATOR OVERRIDE of a user’s primary email address, for the case the normal flow cannot serve: the old address is unreachable (dead mailbox, imported user), so the user cannot approve the change themselves. This does NOT swap the address now. It SCHEDULES the swap behind this product’s mandatory delay (config emailChange.overrideDelayHours, default 72) and immediately emails the OLD address an abort link; if that mailbox is alive and its owner clicks, nothing happens. When the delay elapses the address is swapped, verified, and EVERY SESSION of that user is revoked. Every step is audited (email_change.override_scheduled / _cancelled / _applied) with the reason you pass, so do the identity proofing first and write down what it was. Use users_users_update for profile fields; this tool is only for the identity a user signs in with.
  • users_users_unban — Lift a ban by clearing bannedAt. This removes the sign-in ban set by users_users_ban; previously revoked sessions stay revoked. Idempotent.
  • users_users_update — Update an end user’s profile, status flags and metadata bags. Only the fields you pass change. A metadata field REPLACES that whole bag — send the full object you want stored. Write matrix in this phase: the management plane writes all three bags (public: end-user readable and may flow into the JWT; private: management plane only; unsafe: end-user writable later and never authoritative for authorization). stage moves the person along the funnel and publishes users/user.stage-changed; a patch that changes ONLY the stage deliberately does not also publish users/user.updated, so a workflow that writes stages does not wake itself. tags REPLACES the whole list. kind is NOT editable here and is refused with kind_not_updatable: a contact becomes an account only by proving an address.
  • users_waitlist_funnel — Count this product’s waitlist by funnel stage. pending is people waiting, unconfirmed is double-opt-in signups whose address never confirmed (they are NEVER invited), invited have a live invite, registered accepted it and are now full users, withdrawn asked to be removed. One consistent snapshot, not five separate reads.
  • users_waitlist_get — Read ONE waitlist entry by user id — its funnel status, the address it joined with, where the signup came from (referrer/UTM), the consent proof recorded for it, and the timestamp of every stage it passed. The same shape users_waitlist_list returns per row. A user who is not on this product’s waitlist answers 404.
  • users_waitlist_import — Import a LEGACY waitlist into this product. Each row becomes a directory user in state waitlisted (no credential — a waitlist signup has nothing to sign in with) plus a WaitlistEntry whose consent proof is stored VERBATIM: the policy version, the timestamp and the source the OLD system recorded, never the import time. Rides the Phase 1 bulk import, so it is IDEMPOTENT by canonical identifier — re-running the same file skips instead of duplicating — and reports PER ROW ({row, status, userId, reason}) so one bad row never fails the batch. Addresses that already have an entry are skipped already_on_list; addresses on the suppression list (they withdrew) are skipped suppressed and are NOT resurrected. SENDS NO EMAIL: an import is a migration, not a signup gesture. Imported addresses land UNVERIFIED, and by default confirmed — pass confirmed: false for rows the source system never reached, which then count as unconfirmed and are never invited. Up to 500 rows per call.
  • users_waitlist_invite — Promote waitlisted users by sending them the STANDARD invite email — the same one-time invite link users_users_invite sends, so accepting it sets their first password, verifies their address and turns the entry into registered. Batched: pass up to 100 user ids. Entries that already registered, that belong to another product, or whose address is on the suppression list (they withdrew) are SKIPPED with a reason rather than mailed. Requires a verified sender in this product’s mail toolkit (config email.from).
  • users_waitlist_list — List this product’s waitlist entries, newest first. Each row is a directory user in state waitlisted PLUS the feature-local funnel state: where the signup came from (referrer/UTM), the consent proof recorded for it, and its status. Filter by status to work one stage of the funnel, or by confirmed: false to find double-opt-in signups whose address never confirmed. Paginate with cursor.
  • users_webhooks_create — Register an outbound webhook endpoint for this product. Deliveries are signed with the Standard Webhooks wire format (webhook-id / webhook-timestamp / webhook-signature). The signing secret is returned EXACTLY ONCE — it is derived, never stored, so a lost secret is rotated with users_webhooks_rotate_secret, never recovered.
  • users_webhooks_delete — Delete a webhook endpoint, its signing secrets and its delivery log. Immediate and final; deliveries already in flight stop.
  • users_webhooks_deliveries_list — This endpoint’s recent deliveries, newest first: event type and id, status (pending / succeeded / failed), attempt count, the last response status and the last error. This is where ‘my webhook never arrived’ is answered.
  • users_webhooks_get — One webhook endpoint. Another product’s endpoint and one that never existed answer identically.
  • users_webhooks_list — List this product’s webhook endpoints, newest first — url, subscribed events, paused state and the visible prefix of the current signing secret. The secret itself is never here.
  • users_webhooks_rotate_secret — Mint a NEW signing secret for this endpoint and return it exactly once. The previous secret keeps verifying for 24 hours — both signatures ride the webhook-signature header — so a receiver can swap its copy without dropping a delivery.
  • users_webhooks_update — Change a webhook endpoint: its url, its subscribed events, its description, or active to pause and resume delivery without losing the endpoint or its secret.

Workflow

41 tools.

  • workflow_cap_list — Every cap key on the Product: what it budgets, how much of the running window is spent, and which workflows share it. A cap key is Product-wide — two workflows naming the same key share ONE budget — so conflicting says when they disagree about what that budget is, and window/limit are null rather than picking between them. Live versions only; a draft is not spending anything yet.
  • workflow_capability_get — Get one capability by key — an action by tool name, or a trigger by event name (“schedule” and “manual” for the built-in triggers).
  • workflow_capability_list — List the triggers a workflow can start on and the actions it can call as a step, as declared by the toolkits registered on the platform.
  • workflow_config_delete — Delete a config key of this product.
  • workflow_config_list — List the config keys of this product. Values are never returned — a secret is only ever read by the workflow executor.
  • workflow_config_set — Create or replace a config value for this product. Set secret: true for credentials — the value is encrypted at rest and can never be read back. A key marked deprecated by workflow_config_list is refused.
  • workflow_definition_create — Create a workflow from a definition. It lands as a draft with version 0; the validator runs and its issues come back, so a draft with issues is still saved — including one with no trigger and no nodes yet, which is refused at publish rather than here. The definition’s id, product_id, name, description, status, version and dependencies are server-owned: send them or not, they are overwritten. grants, config_refs and owner are yours.
  • workflow_definition_disable — Disable a workflow. Runs already in flight finish; no new run starts.
  • workflow_definition_dryrun — Walk the graph with a sample payload and mocked action outputs, calling nothing. Returns the path taken, every resolved input and a reason for each node not visited.
  • workflow_definition_enable — Enable a workflow. It needs a published version.
  • workflow_definition_estimate — Size a batch trigger’s audience before enabling it: walks the source tool by cursor, applies the trigger filter and calls nothing else. skip_if_served_within is not applied — this is the audience, not one tick. exact: false means count is a floor.
  • workflow_definition_export — The definition of one version as JSON, with any secret-typed literal redacted. Feed it to workflow_definition_import in another product.
  • workflow_definition_get — One workflow: the draft, a summary of the live version, and the validation issues the draft has right now.
  • workflow_definition_import — Create a draft from an exported definition. id, product_id, owner, grants and the version history are dropped: grants are requested again in this product.
  • workflow_definition_list — List the workflows of this product, newest first.
  • workflow_definition_publish — Publish the draft as the next immutable version and make it live. Refused with 422 and the issues while validation reports any error. First publish enables the workflow; one an operator disabled stays disabled.
  • workflow_definition_update — Edit a workflow draft. Published versions are immutable — this only ever writes version 0. The definition’s id, product_id, name, description, status, version and dependencies are server-owned: send them or not, they are overwritten. grants, config_refs and owner are yours.
  • workflow_definition_validate — Validate a stored draft or an inline definition. Returns the documented issue codes; publish is refused while any issue has severity “error”.
  • workflow_dependency_list — The workflows of THIS product whose published versions depend on a toolkit — what a deregistration or a schema change would break. It answers for the calling product only; the cross-product “which Products depend on this toolkit” view is an operator question and is not served here.
  • workflow_grant_list — The grants of one workflow’s principal: what it may call, what is waiting on a sponsor, and what lost the sponsor it had.
  • workflow_grant_request — Ask Governance again for every tool the workflow’s live version calls. Use it after a grant was revoked: Governance does not resurrect a revoked grant when a human approves it, so it has to be requested again first — this puts it back to pending, where an Owner or Admin can sponsor it. Idempotent; grants nothing by itself.
  • workflow_health_list — One workflow’s health timeline, newest first: when it broke, what broke it, what fixes it, and when it recovered.
  • workflow_health_ping — Check that the Workflow toolkit is reachable for this product.
  • workflow_killswitch_get — Whether this Product’s kill-switch is on, who threw it and when. forced means the platform holds it on for everyone.
  • workflow_killswitch_set — Stop or resume every workflow of this Product. Turning it on holds the runs that are running, waiting or queued and expires their waits — nothing is lost, and workflow_run_replay_all restarts them afterwards.
  • workflow_run_cancel — Stop a run that has not finished and expire its waits. A run that already succeeded, failed or was cancelled is refused.
  • workflow_run_get — One run with its step ledger, its append-only event trace and its waits. Step payloads are as stored — redacted per the tool schema (INV-058). history.status is deleted once the run-history retention policy has taken the steps and events of a finished run; the run row and its waits remain.
  • workflow_run_list — Runs of this Product, newest first. Filter by workflow, status or subject — status=held is what an agent reads to find what broke, subject_key is every run about one person.
  • workflow_run_replay — Re-run a held or failed run from the step that stopped it, on the run’s own version and over its existing trace. Any other status is refused, and so is a run whose trace the run-history retention policy deleted (RUN_HISTORY_DELETED).
  • workflow_run_replay_all — Re-run every held or failed run of one workflow, oldest first — what an operator reaches for after turning the kill-switch off or granting a tool. Runs that cannot be replayed — a run whose history the retention policy deleted among them — are reported with their reason instead of stopping the rest.
  • workflow_run_start — Start a run of an enabled workflow that declares a manual trigger. The idempotency key makes a repeated start return the first one instead of a second run.
  • workflow_run_stats — Run aggregates over a time window: one row per workflow, or — with workflow_id — that workflow’s per-node and per-edge counts as well. waiting is what is parked right now, not what was parked during the window. done is the synthetic end; a workflow whose node is literally named done is ambiguous in edges. Runs whose history the retention policy deleted are left out of nodes and edges and counted in history_deleted_runs.
  • workflow_run_test — Start a test run of a workflow’s draft — the live version when there is no draft. It executes for real under the same grants, rate limit and kill-switch as any run, and is flagged test so it is not read as the Product’s own traffic. Any trigger kind can be tested: trigger_payload becomes trigger.data as given, neither checked against a manual trigger’s input_schema nor filtered by an event trigger’s conditions — a test run is unconditional.
  • workflow_template_apply — Create a workflow from a template. It lands exactly as workflow_definition_create leaves one: a draft at version 0, with the validator’s issues on it — including, on a Product that has not set the config keys the template references, the issue that names workflow_config_set. Edit it, then publish it. An inapplicable template applies too: the draft records what it needs rather than being refused with nothing to look at.
  • workflow_template_list — The workflow templates, with whether this Product can run each one. A template whose toolkit is not registered here is still listed, marked inapplicable, with what is missing and why — turning that toolkit on is what makes it work. There is no cursor: templates ship in code and there are few of them.
  • workflow_version_get — One version of a workflow, with its stored definition.
  • workflow_version_list — The published versions of a workflow, newest first. The draft is not one.
  • workflow_wait_get — One wait: which workflow and run it belongs to, what it asks, when it gives up, and — for an input — the form its answer is checked against.
  • workflow_wait_list — Approvals and inputs waiting on YOU in this Product — assigned to you by name, to your role, or to your agent principal. Defaults to what is still pending.
  • workflow_wait_list_all — Every approval and input of this Product, whoever it was assigned to — the operator’s view of what the Product’s workflows are waiting on. Seeing them all does not resolve them: workflow_wait_resolve still answers only what is assigned to you, or a signed link.
  • workflow_wait_resolve — Answer an approval (decision) or an input (payload, checked against the node’s form) and let the run continue. Authorised for the assignee, or for the holder of the signed link_token the notification carried — not for whoever merely holds write. A wait that was already answered or has expired is refused.
Was this page helpful?
Esc

Start typing to search the docs.

↑↓navigate↵select