> ## Documentation Index
> Fetch the complete documentation index at: https://docs.roofkit.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Analytics and attribution

> The RoofKit MCP tools for Analytics and attribution, with their access, kind, and arguments.

This page lists 28 tools. Each tool shows only to members whose role grants its access. The descriptions are the text that the MCP server sends to AI clients.

## Get analytics metric

Read one dashboard metric for a period, computed as the RoofKit dashboards compute it, so the number matches the widgets. Use it for totals, comparisons, and breakdowns instead of paging leads or records. Returns total, previous\_total for the same number of days just before, percent\_change, unit, a breakdown when you send dimension, and daily values when you send include\_series. Metrics: new\_leads = Opportunities created, imports included (the dashboard Leads card). first\_conversions = website conversions that created a contact; repeat\_conversions = later conversions of a contact. appointments and sales = Opportunities that first entered the Appointment or Won stage. sales\_value and quote\_value = cents. spend = monthly spend in cents, prorated by day, with the month carry-over. cpl = spend / new\_leads, cpa = spend / appointments, cost\_per\_acquisition = spend / sales (cents). conversion\_rate = website sessions that became a lead / visits, in percent. appt\_rate and sales\_rate = appointments or sales / new\_leads, in percent. roas and roi are ratios. Financial metrics need financial access.

| Tool name | Access | Kind |
| - | - | - |
| `roofkit.analytics.metric.get` | `analytics.read` | Read |

**Arguments**

**metric** `string` *required*

Allowed values: `visitors`, `new_leads`, `first_conversions`, `repeat_conversions`, `conversion_rate`, `time_to_lead`, `sessions`, `step_completions`, `image_uploads`, `visualization_completes`, `shares`, `downloads`, `calls`, `answered_calls`, `missed_calls`, `answer_rate`, `missed_call_rate`, `avg_talk_time`, `first_time_callers`, `first_time_caller_rate`, `booked_calls`, `booked_call_rate`, `spend`, `cpl`, `cpa`, `appointments`, `appt_rate`, `avg_appt_cycle`, `avg_appt_made_cycle`, `appt_to_sale_rate`, `estimates_sent`, `estimate_sent_rate`, `sales`, `sales_rate`, `avg_sales_cycle`, `sales_value`, `nsli`, `users_opportunities`, `users_appointments`, `users_estimates_sent`, `users_quote_value`, `users_sales`, `users_sales_value`, `users_est_profit`, `users_nsli`, `active_sales_reps`, `demo_rate`, `assignment_coverage`, `average_sale_price`, `est_profit`, `quote_value`, `cost_per_appointment`, `cost_per_acquisition`, `profit_per_acquisition`, `roas`, `roi`, `reps_total_attempts`, `reps_active_reps`, `reps_included_attempts`, `reps_credit_attempts`, `ai_runs`, `ai_settlements`, `ai_tokens`, `ai_credits`, `ai_tokens_per_run`, `ai_feedback_positive_rate`.

**dimension** `string`

Splits the total. user splits the users\_\* rep metrics by owner. Allowed values: `source`, `medium`, `campaign`, `user`.

**include\_series** `boolean`

Adds one value per calendar day.

**range** `string`

A dashboard period. Default 30d (30 calendar days through today). Leave it out when you send from and to. Allowed values: `today`, `yesterday`, `7d`, `30d`, `90d`, `12m`, `this_month`, `last_month`.

**from** `string`

First calendar day, YYYY-MM-DD. Send it with to.

**to** `string`

Last calendar day, YYYY-MM-DD, included. Send it with from.

**timezone** `string`

IANA zone of the calendar days. Default: the workspace reporting zone, as the dashboards use.

## List lead sources

List lead sources for a period with the figures of the dashboard Sources table: leads, conversions, calls, SMS, stage counts, prorated spend, CPL, CPA, and the Opportunity figures (created, appointments, won, revenue\_cents, roas). lead\_count = contacts with a form, call, or SMS conversion in the period, counted for their first-touch source (the dashboard Sources table). conversion\_count and form\_count = form conversions. conversion\_rate = contacts in a conversion stage / lead\_count, in percent (not the website conversion\_rate metric). stage\_counts are keyed by stage id; stages lists the labels. trend and trends = percent change against the same number of days just before.

| Tool name | Access | Kind |
| - | - | - |
| `roofkit.lead_sources.list` | `analytics.read` | Read |

**Arguments**

**range** `string`

A dashboard period. Default 30d (30 calendar days through today). Leave it out when you send from and to. Allowed values: `today`, `yesterday`, `7d`, `30d`, `90d`, `12m`, `this_month`, `last_month`.

**from** `string`

First calendar day, YYYY-MM-DD. Send it with to.

**to** `string`

Last calendar day, YYYY-MM-DD, included. Send it with from.

**timezone** `string`

IANA zone of the calendar days. Default: the workspace reporting zone, as the dashboards use.

## List campaigns

List marketing campaigns for a period with the same figures as roofkit.lead\_sources.list, grouped by campaign. Campaign rows have no spend or Opportunity figures, so their money fields stay null. lead\_count = contacts with a form, call, or SMS conversion in the period, counted for their first-touch source (the dashboard Sources table). conversion\_count and form\_count = form conversions. conversion\_rate = contacts in a conversion stage / lead\_count, in percent (not the website conversion\_rate metric). stage\_counts are keyed by stage id; stages lists the labels. trend and trends = percent change against the same number of days just before.

| Tool name | Access | Kind |
| - | - | - |
| `roofkit.campaigns.list` | `analytics.read` | Read |

**Arguments**

**range** `string`

A dashboard period. Default 30d (30 calendar days through today). Leave it out when you send from and to. Allowed values: `today`, `yesterday`, `7d`, `30d`, `90d`, `12m`, `this_month`, `last_month`.

**from** `string`

First calendar day, YYYY-MM-DD. Send it with to.

**to** `string`

Last calendar day, YYYY-MM-DD, included. Send it with from.

**timezone** `string`

IANA zone of the calendar days. Default: the workspace reporting zone, as the dashboards use.

## List analytics reports

List the live dashboards the member can open, in the order of the app list: id, name, slug, kind, updated\_at, and the in-app url. Read their numbers with roofkit.analytics.metric.get. A manager edits one with the roofkit.analytics.dashboards tools, which need its id and updated\_at.

| Tool name | Access | Kind |
| - | - | - |
| `roofkit.analytics.reports.list` | `analytics.read` | Read |

**Arguments**

This tool takes no arguments.

## List analytics spend

List marketing spend per month and per source, as the dashboards read it: a month with no saved amount inherits the latest saved one (spend\_carried\_from names that month). Amounts are cents. month\_totals sums each month. For spend in a date period, call roofkit.analytics.metric.get with metric spend. Save changes with roofkit.analytics.spend.save.

| Tool name | Access | Kind |
| - | - | - |
| `roofkit.analytics.spend.list` | `analytics.read` | Read |

**Arguments**

**from\_month** `string`

First month, YYYY-MM. Default: two months before the current month.

**to\_month** `string`

Last month, YYYY-MM, included. Default: the current month. At most 12 months.

## Save marketing spend

Save monthly marketing spend and other costs per source and medium, as the RoofKit Marketing spend table saves them. Confirm the amounts with the user first: a saved month also changes every later month that inherits it. Amounts are whole cents. An amount you leave out stays as it is. null clears the month, so it inherits the latest earlier amount again. Read the source\_key and medium\_key values with roofkit.analytics.spend.list. A source with no saved spend needs channel\_label. Ads connector spend cannot change, but its other costs can. One call saves at most 100 rows within 12 months, and saves all rows or none. Returns the effective spend of the saved sources from the earliest saved month through the current month, in the spend.list row shape.

| Tool name | Access | Kind |
| - | - | - |
| `roofkit.analytics.spend.save` | `analytics.manage` | Destructive write |

**Arguments**

**rows** `object[]` *required*

**properties**

**month** `string` *required*

YYYY-MM.

**source\_key** `string` *required*

**medium\_key** `string`

Leave it out for a source without a medium.

**spend\_cents** `integer | null`

Monthly spend in cents. null clears it. Minimum 0.

**other\_costs\_cents** `integer | null`

Other costs in cents. null clears them. Minimum 0.

**channel\_label** `string`

The channel name the Marketing spend table shows.

## Record page view

Ingest a page view event. Requires an idempotency key.

| Tool name | Access | Kind |
| - | - | - |
| `roofkit.events.page_view` | `analytics.manage` | Write |

**Arguments**

**idempotency\_key** `string` *required*

**external\_event\_id** `string` *required*

**session\_id** `string` *required*

**page\_url** `string`

## Create dashboard

Create a custom dashboard as the member. It is live at once, and every member who can open dashboards sees it (workspace access). Send name, an optional description and default\_range (default 30d), and the widgets: presets, widgets, or both. Presets come first. With presets, the rowIndex of each widget counts from the first row below them. A dashboard holds at most 24 widgets. An invalid widget or an unknown metric answers VALIDATION\_ERROR with the path of the problem. The plan dashboard limit and the plan widget gates answer FORBIDDEN. Returns the dashboard id, slug, in-app url, updated\_at, and the saved widgets with their ids. To share it outside RoofKit, call roofkit.analytics.dashboards.share\_link. Requires an idempotency key.

| Tool name | Access | Kind |
| - | - | - |
| `roofkit.analytics.dashboards.create` | `analytics.manage` | Write |

**Arguments**

**name** `string` *required*

At most 80 characters.

**description** `string`

At most 240 characters.

**default\_range** `string`

The period the dashboard opens with. Allowed values: `today`, `yesterday`, `7d`, `30d`, `90d`, `12m`, `this_month`, `last_month`.

**presets** `string[]`

Named widgets the server builds and lays out, in order, five KPIs or two charts to a row. KPIs: new\_leads\_kpi, visitors\_kpi, conversion\_rate\_kpi, appointments\_kpi, estimates\_sent\_kpi, sales\_kpi. Trends: leads\_trend (daily leads), appointment\_rate\_trend, visitors\_by\_week, first\_conversions\_by\_week. Breakdowns: leads\_by\_source, leads\_by\_entry\_point, leads\_by\_medium, leads\_by\_campaign, top\_campaigns\_by\_sales. Full width: sales\_funnel, source\_table.

**widgets** `object[]`

**properties**

**rowIndex** `integer` *required*

Minimum 0.

**columnIndex** `integer` *required*

Minimum 0. Maximum 4.

**widgetKind** `string` *required*

Allowed values: `bar_vertical`, `bar_horizontal`, `pie`, `breakdown`, `podium`, `metric_grid`, `metric_list`, `line`, `map`, `funnel`, `heatmap`, `dimension_table`, `comparison`, `table`, `lead_chart`, `insight_summary`, `sankey`.

**widthSpan** `integer`

Minimum 10. Maximum 60.

**stackIndex** `integer`

Stacks up to three line widgets without a group-by in one cell. Minimum 0. Maximum 2.

**config** `object` *required*

The widget config. kind equals widgetKind. Other fields follow the RoofKit agent widget contract.

**idempotency\_key** `string` *required*

## Get dashboard share link

Return the public link of a dashboard, or create one when it has none. Anyone with the URL can view the dashboard and its current figures without signing in, so confirm with the user before you create or share it. The link is the full /share/analytics/\<token> URL of the app Share panel, and it stays live until it is revoked. A new link names the member as its creator, so its financial figures follow that member's financial access. financial\_withheld true means the link hides the financial figures. A restricted dashboard, a dashboard whose public links are blocked, and a dashboard with financial data for a member without financial access answer FORBIDDEN. Requires an idempotency key.

| Tool name | Access | Kind |
| - | - | - |
| `roofkit.analytics.dashboards.share_link` | `analytics.manage` | Write |

**Arguments**

**dashboard\_id** `string` *required*

Dashboard id from roofkit.analytics.reports.list.

**idempotency\_key** `string` *required*

## Revoke dashboard share link

Revoke the public link of a dashboard. The URL stops working at once for everyone. A later share\_link call creates a new URL. A dashboard without a public link answers revoked false. Requires an idempotency key.

| Tool name | Access | Kind |
| - | - | - |
| `roofkit.analytics.dashboards.share_link.revoke` | `analytics.manage` | Destructive write |

**Arguments**

**dashboard\_id** `string` *required*

Dashboard id from roofkit.analytics.reports.list.

**idempotency\_key** `string` *required*

## Get dashboard

Read one dashboard with its widgets and filters: name, description, kind, default\_range, updated\_at, the in-app url, the widgets in the app widget draft shape with their ids, and the saved filters. Send its updated\_at as expected\_updated\_at to the edit tools. Read its numbers with roofkit.analytics.metric.get.

| Tool name | Access | Kind |
| - | - | - |
| `roofkit.analytics.dashboards.get` | `analytics.read` | Read |

**Arguments**

**dashboard\_id** `string` *required*

Dashboard id from roofkit.analytics.reports.list.

## Update dashboard

Change the name, description, or default period of a dashboard. The change is live at once for everyone who opens it. Send at least one of name, description, and default\_range. An empty description clears it. A newer save answers CONFLICT with the current updated\_at. The write records a version that roofkit.analytics.dashboards.versions.restore can undo. Returns the dashboard url and its new updated\_at. Requires an idempotency key.

| Tool name | Access | Kind |
| - | - | - |
| `roofkit.analytics.dashboards.update` | `analytics.manage` | Write |

**Arguments**

**dashboard\_id** `string` *required*

Dashboard id from roofkit.analytics.reports.list.

**expected\_updated\_at** `string` *required*

updated\_at of the dashboard as you last read it, from roofkit.analytics.dashboards.get or roofkit.analytics.reports.list.

**name** `string`

At most 80 characters.

**description** `string`

At most 240 characters.

**default\_range** `string`

The period the dashboard opens with. Allowed values: `today`, `yesterday`, `7d`, `30d`, `90d`, `12m`, `this_month`, `last_month`.

**idempotency\_key** `string` *required*

## Update dashboard widgets

Remove, edit, and add the widgets of a dashboard in one write. The steps run in this order: remove\_widget\_ids, update\_widgets, add\_presets, add\_widgets. Read the widget ids and configs with roofkit.analytics.dashboards.get first. Widgets the call does not name stay as they are. New widgets go below the kept ones, and the rowIndex of an added widget counts from the first new row. A dashboard holds at most 24 widgets. An invalid widget or an unknown metric answers VALIDATION\_ERROR with its path. The change is live at once for everyone who opens the dashboard and on its public link. A newer save answers CONFLICT with the current updated\_at. The write records a version that roofkit.analytics.dashboards.versions.restore can undo. Returns the dashboard url and its new updated\_at. Requires an idempotency key.

| Tool name | Access | Kind |
| - | - | - |
| `roofkit.analytics.dashboards.widgets.update` | `analytics.manage` | Write |

**Arguments**

**dashboard\_id** `string` *required*

Dashboard id from roofkit.analytics.reports.list.

**expected\_updated\_at** `string` *required*

updated\_at of the dashboard as you last read it, from roofkit.analytics.dashboards.get or roofkit.analytics.reports.list.

**remove\_widget\_ids** `string[]`

**update\_widgets** `object[]`

**properties**

**id** `string` *required*

Widget id from roofkit.analytics.dashboards.get.

**rowIndex** `integer`

Minimum 0.

**columnIndex** `integer`

Minimum 0. Maximum 4.

**widgetKind** `string`

Allowed values: `bar_vertical`, `bar_horizontal`, `pie`, `breakdown`, `podium`, `metric_grid`, `metric_list`, `line`, `map`, `funnel`, `heatmap`, `dimension_table`, `comparison`, `table`, `lead_chart`, `insight_summary`, `sankey`.

**widthSpan** `integer | null`

Minimum 10. Maximum 60.

**stackIndex** `integer | null`

Minimum 0. Maximum 2.

**config** `object`

The widget config. kind equals widgetKind. Other fields follow the RoofKit agent widget contract.

**add\_presets** `string[]`

Named widgets to add below the kept ones. KPIs: new\_leads\_kpi, visitors\_kpi, conversion\_rate\_kpi, appointments\_kpi, estimates\_sent\_kpi, sales\_kpi. Trends: leads\_trend (daily leads), appointment\_rate\_trend, visitors\_by\_week, first\_conversions\_by\_week. Breakdowns: leads\_by\_source, leads\_by\_entry\_point, leads\_by\_medium, leads\_by\_campaign, top\_campaigns\_by\_sales. Full width: sales\_funnel, source\_table.

**add\_widgets** `object[]`

**properties**

**rowIndex** `integer` *required*

Minimum 0.

**columnIndex** `integer` *required*

Minimum 0. Maximum 4.

**widgetKind** `string` *required*

Allowed values: `bar_vertical`, `bar_horizontal`, `pie`, `breakdown`, `podium`, `metric_grid`, `metric_list`, `line`, `map`, `funnel`, `heatmap`, `dimension_table`, `comparison`, `table`, `lead_chart`, `insight_summary`, `sankey`.

**widthSpan** `integer`

Minimum 10. Maximum 60.

**stackIndex** `integer`

Stacks up to three line widgets without a group-by in one cell. Minimum 0. Maximum 2.

**config** `object` *required*

The widget config. kind equals widgetKind. Other fields follow the RoofKit agent widget contract.

**idempotency\_key** `string` *required*

## Set dashboard filters

Replace the saved filters of a dashboard. They apply to every widget, for everyone who opens the dashboard, and on its public link. Each filter has field\_key (source, medium, campaign, landing, stage), value, and an optional operator: equals (default) or within\_range with value\_to. Values of one field match any of them. Filters of different fields must all match. At most 10 filters. An empty list clears them. A filter the dashboard cannot use answers VALIDATION\_ERROR with its index. A newer save answers CONFLICT with the current updated\_at. The write records a version that roofkit.analytics.dashboards.versions.restore can undo. Returns the dashboard url and its new updated\_at. Requires an idempotency key.

| Tool name | Access | Kind |
| - | - | - |
| `roofkit.analytics.dashboards.filters.set` | `analytics.manage` | Write |

**Arguments**

**dashboard\_id** `string` *required*

Dashboard id from roofkit.analytics.reports.list.

**expected\_updated\_at** `string` *required*

updated\_at of the dashboard as you last read it, from roofkit.analytics.dashboards.get or roofkit.analytics.reports.list.

**filters** `object[]` *required*

**properties**

**field\_key** `string` *required*

Allowed values: `source`, `medium`, `campaign`, `landing`, `stage`.

**operator** `string`

Default equals. within\_range needs value\_to. Allowed values: `equals`, `within_range`.

**value** `string` *required*

At most 500 characters.

**value\_to** `string`

At most 500 characters.

**idempotency\_key** `string` *required*

## Archive dashboard

Archive a dashboard, as Archive dashboard in the app does. It leaves the dashboard list at once for everyone, and its public link stops serving. The widgets, access, and history stay. A manager can bring it back from Settings, Archive in the app. Confirm with the user first. A newer save answers CONFLICT with the current updated\_at. The archive records a version. Requires an idempotency key.

| Tool name | Access | Kind |
| - | - | - |
| `roofkit.analytics.dashboards.archive` | `analytics.manage` | Destructive write |

**Arguments**

**dashboard\_id** `string` *required*

Dashboard id from roofkit.analytics.reports.list.

**expected\_updated\_at** `string` *required*

updated\_at of the dashboard as you last read it, from roofkit.analytics.dashboards.get or roofkit.analytics.reports.list.

**idempotency\_key** `string` *required*

## List dashboard versions

List the saved versions of one dashboard, newest first. Every write records one: the app, the RoofKit agent, MCP clients, templates, and automations. Each version names its kind (created, edited, restored, archived, unarchived), its source, the member, and for MCP the client. fields and the widget counts say what the change touched. restorable true means the version keeps the dashboard as it was before that change. The history keeps the newest 50 versions. Returns dashboard.updated\_at, which roofkit.analytics.dashboards.versions.restore needs.

| Tool name | Access | Kind |
| - | - | - |
| `roofkit.analytics.dashboards.versions.list` | `analytics.manage` | Read |

**Arguments**

**dashboard\_id** `string` *required*

Dashboard id from roofkit.analytics.reports.list.

**limit** `integer`

At most 50. Default: all kept versions. Minimum 1. Maximum 50.

## Restore dashboard version

Restore a dashboard as it was before the change of one version: name, description, icon, default period, filters, and widgets. Access and share links do not change. The change is live at once for everyone who opens the dashboard, and it can replace newer edits, so confirm with the user first. Send expected\_updated\_at as dashboard.updated\_at from roofkit.analytics.dashboards.versions.list. A newer save refuses the call with CONFLICT. Only versions with restorable true can go back. The restore records its own version, so it can be restored away again. Requires an idempotency key.

| Tool name | Access | Kind |
| - | - | - |
| `roofkit.analytics.dashboards.versions.restore` | `analytics.manage` | Destructive write |

**Arguments**

**dashboard\_id** `string` *required*

Dashboard id from roofkit.analytics.reports.list.

**version\_id** `string` *required*

Version id from roofkit.analytics.dashboards.versions.list.

**expected\_updated\_at** `string` *required*

dashboard.updated\_at as you last read it.

**idempotency\_key** `string` *required*

## List analytics objectives

List the campaign objectives: the workspace default CPL, CPA, and ROAS targets, and each campaign that overrides them. effective is the target that applies to a campaign, and its source says workspace\_default or campaign. CPL and CPA targets are cents, and ROAS is a ratio. A member without financial access gets null CPL and CPA amounts and restricted: financial. plan\_allows\_new\_objectives is false when the plan lacks custom\_kpis or goals. A campaign key is the utm\_campaign value with its case, as roofkit.campaigns.list shows it in campaign. A campaign without an override uses the workspace default.

| Tool name | Access | Kind |
| - | - | - |
| `roofkit.analytics.objectives.list` | `analytics.read` | Read |

**Arguments**

This tool takes no arguments.

## Set default campaign objectives

Set or clear the workspace default objectives, which every campaign without its own override uses. CPL and CPA targets are whole cents and need financial access. ROAS is a ratio. A new type needs the custom\_kpis and goals plan features. Objectives the workspace already holds stay editable and removable on any plan. The change is live on the dashboards and Settings at once. Confirm the targets with the user first. Send expected to refuse the write when someone changed a target since you read it.

| Tool name | Access | Kind |
| - | - | - |
| `roofkit.analytics.objectives.defaults.set` | `analytics.manage` | Write |

**Arguments**

**objectives** `object` *required*

Only the types you send change. A type you leave out keeps its target.

**properties**

**cpl** `object | null`

Cost per lead target. null clears it. Needs financial access.

**cpa** `object | null`

Cost per appointment target. null clears it. Needs financial access.

**roas** `object | null`

Return on ad spend target. null clears it.

**expected** `object`

The current target of each type you change, as roofkit.analytics.objectives.list returned it, or null when the scope holds none. The write changes nothing and answers CONFLICT when a stored target differs.

**properties**

**cpl** `object | null`

**cpa** `object | null`

**roas** `object | null`

## Set campaign objectives

Set or clear the objectives of one campaign. They override the workspace default for that campaign only. Clearing an override makes the campaign use the workspace default again. CPL and CPA targets are whole cents and need financial access. ROAS is a ratio. A new type needs the custom\_kpis and goals plan features. Objectives the workspace already holds stay editable and removable on any plan. The change is live on the dashboards and Settings at once. Confirm the targets with the user first. expected is required: it is the compare-and-set check against the overrides you read. The first objective of a campaign also adds the campaign to the workspace campaign list.

| Tool name | Access | Kind |
| - | - | - |
| `roofkit.analytics.objectives.campaign.set` | `analytics.manage` | Write |

**Arguments**

**campaign\_key** `string` *required*

The utm\_campaign value, with its case. (none) names traffic without a campaign. At most 200 characters.

**campaign\_label** `string`

Display name. Default: the stored label, else the key. At most 200 characters.

**objectives** `object` *required*

Only the types you send change. A type you leave out keeps its target.

**properties**

**cpl** `object | null`

Cost per lead target. null clears it. Needs financial access.

**cpa** `object | null`

Cost per appointment target. null clears it. Needs financial access.

**roas** `object | null`

Return on ad spend target. null clears it.

**expected** `object` *required*

The current target of each type you change, as roofkit.analytics.objectives.list returned it, or null when the scope holds none. The write changes nothing and answers CONFLICT when a stored target differs.

**properties**

**cpl** `object | null`

**cpa** `object | null`

**roas** `object | null`

## List attribution keys

List the source, medium, or campaign keys of the Attribution Manager catalog, most leads first, 25 per page. Each row has the canonical key, the raw aliases that resolve to it, and lead\_count: the contacts whose first touch carries the key. Campaign rows are per source and medium. Use the keys with roofkit.attribution.keys.remap and roofkit.attribution.keys.merge.

| Tool name | Access | Kind |
| - | - | - |
| `roofkit.attribution.keys.list` | `analytics.read` | Read |

**Arguments**

**dimension** `string` *required*

Allowed values: `source`, `medium`, `campaign`.

**search** `string`

Every word must match the key, an alias, the source, or the medium.

**page** `integer`

Zero-based page. Default: 0. Minimum 0.

## Remap attribution keys

Rename or remap source, medium, or campaign keys: each key in from\_keys becomes an alias of to\_key, and reports show to\_key. Use it to rename a key, or to point a typo at the key it meant. Leads keep their raw UTM values. Reports and Contacts show the new key, and RoofKit rebuilds the stored day summaries in the background. A source or medium change also moves the monthly spend rows onto the new key, and sums them when both keys have spend in a month. A campaign change also moves its objectives onto the new key. aliases replaces the alias list of the keys with the list you send. Leave it out to keep the current aliases. A source remap can also set to\_medium\_key. The answer has change\_id. roofkit.attribution.changes.revert puts every touched row back while no later write changed them. revertible is false for a change too large to keep.

| Tool name | Access | Kind |
| - | - | - |
| `roofkit.attribution.keys.remap` | `analytics.manage` | Write |

**Arguments**

**dimension** `string` *required*

Allowed values: `source`, `medium`, `campaign`.

**from\_keys** `string[]` *required*

The keys to remap. A key equal to to\_key only takes the alias list.

**to\_key** `string` *required*

The key reports show. At most 200 characters.

**to\_medium\_key** `string`

Source only: the medium the remapped sources take. At most 200 characters.

**aliases** `string[]`

## Merge attribution keys

Merge source, medium, or campaign keys into one survivor key. Every merged key becomes an alias of survivor\_key, and its leads count under the survivor. Read lead\_count with roofkit.attribution.keys.list and confirm the merge with the user first. Leads keep their raw UTM values. Reports and Contacts show the new key, and RoofKit rebuilds the stored day summaries in the background. A source or medium change also moves the monthly spend rows onto the new key, and sums them when both keys have spend in a month. A campaign change also moves its objectives onto the new key. The answer has affected\_lead\_count, the leads of the merged keys measured before the merge, and survivor\_lead\_count. The answer has change\_id. roofkit.attribution.changes.revert puts every touched row back while no later write changed them. revertible is false for a change too large to keep. Requires an idempotency key.

| Tool name | Access | Kind |
| - | - | - |
| `roofkit.attribution.keys.merge` | `analytics.manage` | Destructive write |

**Arguments**

**dimension** `string` *required*

Allowed values: `source`, `medium`, `campaign`.

**from\_keys** `string[]` *required*

The keys to merge into survivor\_key. A key equal to survivor\_key is left out.

**survivor\_key** `string` *required*

At most 200 characters.

**survivor\_medium\_key** `string`

Source only: the medium the merged sources take. At most 200 characters.

**idempotency\_key** `string` *required*

## List attribution changes

List the last 25 key remaps and merges made through MCP, newest first, with change\_id, the keys, and whether the change can still be reverted.

| Tool name | Access | Kind |
| - | - | - |
| `roofkit.attribution.changes.list` | `analytics.read` | Read |

**Arguments**

This tool takes no arguments.

## Revert attribution change

Revert one key remap or merge made through MCP. Every alias, spend, objective, and campaign row it touched goes back to its earlier state, live at once. The revert is a compare-and-set: when any of those rows changed after the change, it answers CONFLICT and changes nothing. A campaign the change created stays when leads or objectives now use it. Requires an idempotency key.

| Tool name | Access | Kind |
| - | - | - |
| `roofkit.attribution.changes.revert` | `analytics.manage` | Destructive write |

**Arguments**

**change\_id** `string` *required*

**idempotency\_key** `string` *required*

## List attribution links

List the tracked links of the Attribution Manager Links inventory, newest activity first, with link\_id, the UTM values, and conversion\_count. Send dismissed true to list dismissed links with their dismissed\_at for a restore. Filters match the UTM values without case.

| Tool name | Access | Kind |
| - | - | - |
| `roofkit.attribution.links.list` | `analytics.read` | Read |

**Arguments**

**source** `string`

**medium** `string`

**campaign** `string`

**dismissed** `boolean`

true lists dismissed links instead of visible ones.

## Dismiss attribution link

Dismiss one tracked link: it and every visible link with the same UTM values leave the Links inventory under one dismissed\_at stamp. Conversions that arrive while the link is dismissed do not count for it, also after a restore. A dismissed link keeps its stamp. Undo it with roofkit.attribution.links.restore and the dismissed\_at of the answer. Requires an idempotency key.

| Tool name | Access | Kind |
| - | - | - |
| `roofkit.attribution.links.dismiss` | `analytics.manage` | Destructive write |

**Arguments**

**link\_id** `string` *required*

**idempotency\_key** `string` *required*

## Restore attribution link

Show a dismissed link again: every link of its UTM values that still carries dismissed\_at returns to the Links inventory. CONFLICT means no row carries that stamp any more, because a later dismissal, a Builder save, or another restore changed it.

| Tool name | Access | Kind |
| - | - | - |
| `roofkit.attribution.links.restore` | `analytics.manage` | Write |

**Arguments**

**link\_id** `string` *required*

**dismissed\_at** `string` *required*


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.