# MCP tools reference

Every tool the SourceLoop MCP server exposes (18 in total), what each one answers, and the arguments it takes.

Source: https://sourceloop.ai/help/mcp/tools/

---

Endpoint: `https://app.sourceloop.ai/api/mcp`

| Tool | Answers | Permission |
| --- | --- | --- |
| `list_workspaces` | List workspaces | `metrics:read` |
| `get_performance` | Get headline performance | `metrics:read` |
| `break_down_performance` | Break performance down, and attribute it | `metrics:read` |
| `get_ad_performance` | Get ad platform performance | `metrics:read` |
| `check_data_health` | Check whether the data can be trusted right now | `metrics:read` |
| `check_attribution_coverage` | Check how much money attribution can explain, and why not | `metrics:read` |
| `explain_metrics` | Explain what a metric means | `metrics:read` |
| `find_contacts` | Find the people who converted | `conversions:read` |
| `get_deals` | Get deals, and what marketing produced them | `deals:read` |
| `get_companies` | Get companies, with their pipeline and engagement | `companies:read` |
| `update_contact` | Record what a lead turned out to be worth | `conversions:write` |
| `update_deal` | Move a deal, or change its value, in the CRM | `deals:write` |
| `update_company` | Correct a company, or pin its stage | `companies:write` |
| `get_journey` | Get the full journey behind a conversion, company or deal | `conversions:read` |
| `analyze_ltv` | Analyse lifetime value and payback | `metrics:read` |
| `get_funnel` | Get funnel conversion between stages | `metrics:read` |
| `get_products` | Get product-level sales | `metrics:read` |
| `get_paths` | Get the touch sequences that lead to conversions | `metrics:read` |

## list_workspaces

List workspaces

Lists the websites this account can report on, with each one's timezone and currency. Call this first when unsure which website a question refers to, or when another tool reports that the website is ambiguous.

Requires scope: `metrics:read`

## get_performance

Get headline performance

Headline marketing numbers for a period: visitors, conversions, revenue and conversion rate. Use for "how did we do", "how many leads last month", "what is our conversion rate". For a per-channel or per-campaign split, use break_down_performance instead.

Requires scope: `metrics:read`

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `website` | string | no | Website domain, e.g. "acme.com". Omit when the account has only one. |
| `period` | string | no | Period in plain language: "last 30 days", "yesterday", "July 2026", or "2026-07-01..2026-07-31". Defaults to the last 30 days. |
| `compare_to_previous` | boolean | no | Also return the preceding period of equal length, with the change. Ignored when granularity is set, since a series already shows the movement. |
| `granularity` | string | no | Return a TIME SERIES of daily buckets instead of a single total. Use for "show the trend", "conversions per day", or any chart over time. Buckets are calendar days in the website's own timezone, not UTC. Only day is available; to chart weeks or months, take days and sum conversions and revenue, but NOT visitors or sessions, which are unique counts and cannot be added across days. |
| `filter` | string | no | Dimension filter, "dimension:operator:value". Operators: eq, ne, in, nin, contains, not_contains. Examples: "channel:in:paid_search,paid_social", "country:eq:US", "campaign:contains:brand". |
| `events` | string[] | no | Only count these conversion EVENT names, e.g. ["demo_booked"]. Takes precedence over types. |
| `types` | string[] | no | Only count these conversion categories, e.g. ["Web Form","Meeting"]. Coarser than events. |
| `only_paid` | boolean | no | Restrict to paid traffic only. |

## break_down_performance

Break performance down, and attribute it

Splits performance by channel, source, campaign, landing page, country, device and similar. Use for "which channels drive leads", "top landing pages", "where does our traffic come from".

Pass SEVERAL dimensions to cross them: dimensions=["channel","source"] returns one row per pair, up to four deep.

Pass `attribution` to credit conversions across the whole visitor journey instead of counting only the touch where the conversion fired. Pass SEVERAL models to compare them side by side in one answer, which is the honest way to do it: separate calls can land on different windows and the comparison then looks fine and is wrong.

Attribution takes ONE dimension at a time, and only conversions and revenue can be attributed, because a visitor was on one channel at a time and has no credit to split.

Pass `stages` to break down CRM and lifecycle milestones instead of tracked conversions: stages=["deal_won"] with attribution credits closed-won DEAL revenue to the channels that earned it, which is the closed-loop number a B2B team cannot get from an ad platform. A deal is credited across its whole buying committee, so every contact on it contributes their journey.

THREE DIMENSIONS ANSWER SOMETHING DIFFERENT FROM THE REST:
- dimension="platform" or "ad_campaign" with metrics like cac or ltv_cac joins ad SPEND to the campaign that acquired each customer, which is how to answer "is this campaign paying for itself". ltv_cac comes back null when the ad account and the ledger are in different currencies, because there is no FX layer and the wrong ratio is a number people switch campaigns off over.
- dimension="resolution" splits credited outcomes by HOW their touches were tied to marketing: `click_id` (matched to a specific ad by id), `utm` (matched through UTM parameters), `unresolved` (a real visit tied to no ad), `unattributed` (no visit at all). To find out WHY outcomes went unattributed, call check_attribution_coverage instead.
- dimension="cohort" returns a retention curve instead of a ranking: one row per (cohort, period_index) with revenue and customers at each age. Use analyze_ltv for that rather than this tool.

Requires scope: `metrics:read`

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `dimension` | string | no | What to split by. Use `dimensions` to cross several. Ad dimensions (platform, ad_campaign) unlock cost per acquisition; `resolution` explains unattributed outcomes. |
| `dimensions` | string[] | no | Two to four dimensions to cross, e.g. ["channel","source"]. Each row is one combination. Crossing is for traffic dimensions; attribution, ads and cohorts take one at a time. |
| `attribution` | string[] | no | One or more attribution models. Several are compared side by side. Total credit is conserved across models, so every model sums to the same conversion count; only the split moves. |
| `metrics` | string[] | no | Defaults to visitors, conversions and revenue. With attribution, only conversions and revenue are allowed. |
| `website` | string | no | Website domain, e.g. "acme.com". Omit when the account has only one. |
| `period` | string | no | Period in plain language: "last 30 days", "yesterday", "July 2026", or "2026-07-01..2026-07-31". Defaults to the last 30 days. |
| `filter` | string | no | Dimension filter, "dimension:operator:value". Operators: eq, ne, in, nin, contains, not_contains. Examples: "channel:in:paid_search,paid_social", "country:eq:US", "campaign:contains:brand". |
| `events` | string[] | no | Only count these conversion EVENT names, e.g. ["demo_booked"]. Takes precedence over types. |
| `types` | string[] | no | Only count these conversion categories, e.g. ["Web Form","Meeting"]. Coarser than events. |
| `stages` | string[] | no | Count CRM or lifecycle milestones instead of tracked conversions, e.g. ["deal_won"] for closed-won deals, ["mql"], ["trial_started"], ["subscription_churned"]. With an attribution model this is how you credit DEAL revenue to the channels that earned it, which is the closed-loop number a B2B team is judged on. A deal is credited across its whole buying committee, so every contact on it contributes their journey. |
| `only_paid` | boolean | no | Restrict to paid traffic only. |
| `limit` | number | no | Rows to return. Default 10, max 100. |

## get_ad_performance

Get ad platform performance

Ad spend, clicks, impressions and platform-reported conversions from the connected ad accounts. Use for "how much did we spend", "which campaigns are working", "what is our cost per click".

A level is REQUIRED because spend is stored once per grain (campaign, ad set, ad, keyword) and mixing grains multiplies it. Figures named platform_* come from the ad platform under ITS OWN attribution rules and will not match Sourceloop attributed conversions; that difference is expected and is not an error.

Requires scope: `metrics:read`

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `level` | string | yes | Grain to report at. Use "campaign" for the usual view, "account" for a per-platform total. |
| `metrics` | string[] | no |  |
| `breakdown` | boolean | no | One row per item at that level, instead of a single total. |
| `platform` | string | no | Restrict to one platform, e.g. google_ads or meta_ads. |
| `filter` | string | no | Narrow to particular ad entities, "dimension:operator:value". Examples: "campaign:contains:brand", "campaign:in:Search - Brand,Search - Generic". |
| `website` | string | no | Website domain, e.g. "acme.com". Omit when the account has only one. |
| `period` | string | no | Period in plain language: "last 30 days", "yesterday", "July 2026", or "2026-07-01..2026-07-31". Defaults to the last 30 days. |

## check_data_health

Check whether the data can be trusted right now

Reports recent tracking activity so a surprising number can be sanity-checked before conclusions are drawn from it. Call this whenever a figure looks wrong, or before recommending a decision based on an unexpected drop.

Requires scope: `metrics:read`

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `website` | string | no | Website domain, e.g. "acme.com". Omit when the account has only one. |

## check_attribution_coverage

Check how much money attribution can explain, and why not

How much recorded revenue the journey spine explains, and for the rest, WHY NOT. Call this whenever a large share of revenue shows as Unattributed, BEFORE reporting that attribution or tracking is broken, because most of the time it is not.

The reasons are not comparable and must never be summed into one "unattributed" number:
- `imported_contact`: loaded from a CRM or spreadsheet. There was never a visit to find.
- `predates_tracking`: the CUSTOMER arrived before the tracker existed. Keyed on when the relationship started, not on the payment date, so renewals from customers won a year ago land here rather than reading as failures.
- `no_visitor` and `no_sessions`: the tracker was running and the person still could not be tied to a visit. These are the only ones worth investigating.

The first two are permanent facts about the business. Telling a customer to fix their install because of them wastes their time and their trust.

Requires scope: `metrics:read`

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `website` | string | no | Website domain, e.g. "acme.com". Omit when the account has only one. |
| `period` | string | no | Period in plain language: "last 30 days", "yesterday", "July 2026", or "2026-07-01..2026-07-31". Defaults to the last 30 days. |

## explain_metrics

Explain what a metric means

Returns the exact definition of any Sourceloop metric or dimension, and the filter syntax. Use before reporting an unfamiliar metric so it is never described incorrectly, and whenever a user asks how something is calculated.

Requires scope: `metrics:read`

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `metric` | string | no | A metric name. Omit to list everything. |

## find_contacts

Find the people who converted

The actual leads, not counts: who converted, when, from which channel, and what they turned out to be worth. Use for "who came in from LinkedIn last week", "show me the leads worth over 5000", "which leads has nobody followed up".

One row per CONVERSION, so a person who converts twice appears twice; group by identity_id to count people. Channel filters match FIRST touch, because "leads from Google" almost always means "leads Google introduced us to".

Email, phone and name are MASKED unless the key carries pii:read, and the domain is kept when masking so a lead at acme.com is still recognisable.

Requires scope: `conversions:read`

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `website` | string | no | Website domain, e.g. "acme.com". Omit when the account has only one. |
| `period` | string | no | Period in plain language: "last 30 days", "yesterday", "July 2026", or "2026-07-01..2026-07-31". Defaults to the last 30 days. |
| `channel` | string | no | First-touch channel, e.g. "paid search". |
| `source` | string | no | First-touch source, e.g. "google". |
| `medium` | string | no | First-touch medium, e.g. "cpc". |
| `campaign` | string | no | First-touch campaign. |
| `latest_channel` | string | no | LAST-touch channel: what they came back on, rather than what introduced them. |
| `latest_source` | string | no | Last-touch source. |
| `latest_campaign` | string | no | Last-touch campaign. |
| `type` | string | no | Conversion category, e.g. "Web Form". |
| `event_name` | string | no | Exact conversion event, e.g. "demo_booked". |
| `status` | string | no |  |
| `lifecycle_stage` | string | no | CRM lifecycle stage as the CRM spells it. |
| `owner_email` | string | no | The CRM owner the contact is assigned to. |
| `company_domain` | string | no | Matches on company name. Not personal data, so no pii:read needed. |
| `email` | string | no | Search by email. Requires pii:read, because searching by an address IS reading it. |
| `phone` | string | no | Search by phone. Requires pii:read. |
| `has_value` | boolean | no | true returns only contacts with a sales value recorded. |
| `min_sales_value` | number | no |  |
| `has_quote` | boolean | no | true returns only contacts with a quote value recorded. |
| `include_spam` | boolean | no | Default false. Spam is excluded unless asked for. |
| `include_duplicates` | boolean | no | Default true. |
| `limit` | number | no | Default 25, max 200. |

## get_deals

Get deals, and what marketing produced them

Deals from the connected CRM with the attribution Sourceloop computed for them, so revenue can be traced back to the channel that started it. Use for "what is in the pipeline", "which channel produces won deals", "how much revenue did paid search actually generate".

Set group_by to summarise instead of listing: group_by="first_channel" returns won, open and lost value per channel.

TWO WAYS TO CREDIT A DEAL, AND THEY DIFFER:
- By default a grouped answer uses the deal record's own first and latest touch, which is the ANCHOR CONTACT's journey. Simple, and it under-counts: two thirds of deals have another contact on them carrying their own browsing history.
- Pass `credit` with an attribution model and the answer comes from the journey spine instead, where a deal is one outcome whose touches are the union of the WHOLE buying committee. If the champion arrived from organic search and the VP typed the URL, the anchor view credits Direct alone and this one does not. Deals average 1.83 contacts and reach 3, so this is the normal case rather than an edge one.

Deal amounts come from your CRM, not from our tracking, so they are the real numbers your sales team sees.

Requires scope: `deals:read`

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `website` | string | no | Website domain, e.g. "acme.com". Omit when the account has only one. |
| `period` | string | no | Period in plain language: "last 30 days", "yesterday", "July 2026", or "2026-07-01..2026-07-31". Defaults to the last 30 days. |
| `status` | string | no | Restrict to one status. |
| `pipeline_id` | string | no | From get_deals results or the pipelines endpoint. |
| `stage_id` | string | no |  |
| `account_id` | string | no | Only deals for one company, from get_companies. |
| `owner_email` | string | no | The CRM owner the deal is assigned to. |
| `min_amount` | number | no |  |
| `channel` | string | no | First-touch channel that introduced the deal. |
| `source` | string | no | First-touch source. |
| `campaign` | string | no | First-touch campaign. |
| `latest_channel` | string | no | Last-touch channel. |
| `closed_after` | string | no | YYYY-MM-DD. Filters on close date, not creation date. |
| `closed_before` | string | no | YYYY-MM-DD. |
| `sort` | string | no | Default amount, largest first. |
| `group_by` | string | no | Summarise by this instead of listing individual deals. |
| `credit` | string | no | Credit won-deal value across the whole buying committee using this attribution model, from the journey spine, instead of the anchor contact's stored first touch. Only with group_by on a channel, source or campaign. |
| `limit` | number | no | Default 25, max 200. |

## get_companies

Get companies, with their pipeline and engagement

The account-based view: which companies are engaging, how many people from each, what pipeline they represent and which channel introduced them. Use for "which accounts are most engaged", "what companies visited but never converted", "show me our biggest accounts by pipeline".

Sorted by pipeline value by default, or by engagement when sort="engagement". Company data is not personal data, so this needs no pii:read.

Requires scope: `companies:read`

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `website` | string | no | Website domain, e.g. "acme.com". Omit when the account has only one. |
| `sort` | string | no | pipeline = total open + won value, engagement = number of people, recent = last seen. |
| `has_deals` | boolean | no | true returns only companies with at least one deal. |
| `has_open_deals` | boolean | no | true returns only companies with a deal still open. |
| `min_conversions` | number | no |  |
| `domain` | string | no | Match on company domain, e.g. "acme.com". |
| `industry` | string | no |  |
| `country` | string | no |  |
| `channel` | string | no | First-touch channel that introduced the company. |
| `source` | string | no | First-touch source. |
| `include_personal` | boolean | no | Default false. Personal email domains (gmail.com and similar) are not companies and are excluded. |
| `limit` | number | no | Default 25, max 200. |

## update_contact

Record what a lead turned out to be worth

Writes an outcome back onto a contact: the deal value, the status, notes. This is how cost-per-lead reporting becomes cost-per-revenue reporting, because until someone records that a lead closed for 14,000 the attribution has nothing to attribute.

Changes propagate to any connected CRM. A write that changes nothing writes nothing. Attribution is computed by Sourceloop and cannot be set.

Requires scope: `conversions:write`

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `contact_id` | string | yes | The contact id, from find_contacts. |
| `status` | string | no | Sourceloop status, e.g. "won", "qualified". |
| `lifecycle_stage` | string | no | CRM lifecycle stage, as the CRM spells it, e.g. "Customer". Propagates to the connected CRM. |
| `lead_status` | string | no | CRM lead status, as the CRM spells it. Propagates to the connected CRM. |
| `qualified` | boolean | no | Mark the lead qualified. |
| `lead_score` | number | no |  |
| `sales_value` | number | no | What the deal was actually worth. |
| `quote_value` | number | no |  |
| `currency` | string | no |  |
| `notes` | string | no |  |
| `is_spam` | boolean | no | Mark a junk lead, excluding it from reporting. |

## update_deal

Move a deal, or change its value, in the CRM

Updates a deal in the customer's own CRM (HubSpot or Pipedrive). Use for "mark that deal won", "the contract came in at 22,000".

The CRM owns these fields, so the change is saved and QUEUED for push rather than applied instantly. The result says whether it was queued: if it was not, outbound is disabled on that connection and the next sync will overwrite the value.

status is translated per provider. HubSpot has no status field, because won and lost are stages there, so "won" is resolved to that pipeline's won stage.

Requires scope: `deals:write`

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `deal_id` | string | yes | The deal id, from get_deals. |
| `status` | string | no |  |
| `amount` | number | no |  |
| `name` | string | no |  |
| `close_date` | string | no | YYYY-MM-DD. |

## update_company

Correct a company, or pin its stage

Corrects a company record: firmographics (industry, employee count, country and so on) and its lifecycle stage.

Most companies here were discovered from traffic rather than imported, so nobody else owns them and the write simply sticks. When a company IS linked to a CRM the write still lands, and the result says the next sync will overwrite it.

Stage is normally DERIVED from deals and contact activity. Setting it PINS the company, stopping that recomputation, and the result says so: do not pin a stage without telling the user that is what happened.

Engagement counts, deal rollups and attribution are computed and cannot be set.

Requires scope: `companies:write`

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `company_id` | string | yes | The company id, from get_companies. |
| `company_name` | string | no |  |
| `industry` | string | no |  |
| `employee_count` | number | no |  |
| `annual_revenue` | number | no |  |
| `size_range` | string | no |  |
| `country` | string | no |  |
| `region` | string | no |  |
| `city` | string | no |  |
| `website_url` | string | no |  |
| `linkedin_url` | string | no |  |
| `description` | string | no |  |
| `lifecycle_stage` | string | no | A stage name from this workspace, e.g. "Customer". Pins the company: stage stops being derived. |

## get_journey

Get the full journey behind a conversion, company or deal

The timeline the attribution numbers summarise: every session, in order, with how the person arrived each time and what they did once there. Use for "how did this lead find us", "what marketing produced this deal", "show me this account's path".

Pass exactly ONE of contact_id, company_id or deal_id. A company or deal journey merges every person attached to it, because in B2B the person who first read a blog post is rarely the person who signs.

Devices are merged via the identity graph, so someone who browsed on a phone and converted on a laptop is one timeline, not two half-journeys.

When no raw events exist the timeline is reconstructed from stored first-touch and last-touch attribution and marked synthetic:true. Say so rather than presenting it as a complete history.

Requires scope: `conversions:read`

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `contact_id` | string | no | From find_contacts. |
| `company_id` | string | no | From get_companies. Merges everyone at the company. |
| `deal_id` | string | no | From get_deals. Merges everyone on the deal. |
| `days` | number | no | How far back to look. Default 365. |
| `limit` | number | no | Maximum rows from the event store. Default 2000. |

## analyze_ltv

Analyse lifetime value and payback

What the customers acquired in a period turn out to be worth, and how long they take to pay back. Use for "what is our LTV", "which channel brings the most valuable customers", "how long until a customer pays for themselves", "what is our repeat rate".

THIS IS A COHORT MEASURE AND IT IS NOT REVENUE. The period selects WHO was acquired, not which payments count, so it includes money those customers paid afterwards and grows as they mature. Revenue recorded IN a period is a different question: ask get_performance for that. On a subscription workspace the two differed by 3.1x, so quoting one as the other is a real error.

Set `curve: true` for the payback curve: one row per cohort per age, where period_index 0 is the month of acquisition. Set `dimension` to compare acquisition channels.

For cost per acquisition and whether a campaign has paid for itself, use break_down_performance with dimension="ad_campaign" and metrics including cac and ltv_cac, which joins the spend the ad platform reports.

Requires scope: `metrics:read`

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `website` | string | no | Website domain, e.g. "acme.com". Omit when the account has only one. |
| `period` | string | no | Period in plain language: "last 30 days", "yesterday", "July 2026", or "2026-07-01..2026-07-31". Defaults to the last 30 days. |
| `dimension` | string | no | Compare acquisition channels. Omit for one overall figure. |
| `curve` | boolean | no | Return the payback curve, one row per cohort per age, instead of a single rollup. |
| `grain` | string | no | The AGE unit for the curve, not a calendar bucket. Default month. |
| `metrics` | string[] | no | Defaults to lifetime value, customers and average LTV. A curve reports lifetime value, customers and revenue per customer only. |
| `limit` | number | no | Rows to return. Default 25, max 100. |

## get_funnel

Get funnel conversion between stages

How many people or deals reached each stage, and the drop-off between them. Use for "what is our lead to customer rate", "where are we losing deals", "how many trials convert".

Pass the stages IN ORDER, e.g. stages=["lead","mql","sql","deal_won"]. Each count is distinct entities that ENTERED that stage in the period, so somebody who reached it twice counts once.

STAGES ARE COUNTED OVER THE WHOLE POPULATION, including people the tracker never saw: imported contacts, deals closed over the phone, customers who predate the tracking script. That is deliberate, and it is why these rates are lower and more honest than a funnel computed over tracked visitors alone.

To credit a stage to the marketing that produced it, use break_down_performance with `stages` and an attribution model instead.

Requires scope: `metrics:read`

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `stages` | string[] | yes | Stage keys in funnel order, e.g. ["lead","mql","customer"] or ["trial_started","trial_converted"]. |
| `website` | string | no | Website domain, e.g. "acme.com". Omit when the account has only one. |
| `period` | string | no | Period in plain language: "last 30 days", "yesterday", "July 2026", or "2026-07-01..2026-07-31". Defaults to the last 30 days. |

## get_products

Get product-level sales

What each product sold, refunded and earned, for connected commerce stores. Use for "best selling products", "which products get refunded", "what is our margin by product".

Revenue is NET of refunds. Margin is reported only for the share of revenue where the merchant has set a cost, and that share is returned alongside it, so a partial cost catalogue does not read as 100% margin.

Requires scope: `metrics:read`

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `website` | string | no | Website domain, e.g. "acme.com". Omit when the account has only one. |
| `period` | string | no | Period in plain language: "last 30 days", "yesterday", "July 2026", or "2026-07-01..2026-07-31". Defaults to the last 30 days. |
| `platform` | string | no | Commerce platform. Default shopify. |
| `limit` | number | no | Default 25, max 200. |

## get_paths

Get the touch sequences that lead to conversions

Which SEQUENCES of touchpoints end in an outcome, and what each sequence is worth. Use for "what path do customers take", "how many touches before someone buys", "which combinations of channels work together".

This is what a single-channel breakdown cannot show: that paid search rarely closes on its own, or that a particular pair of channels appears before most of the revenue.

Long journeys are capped at max_touches and marked with a trailing "..." so two long journeys that begin the same way group together instead of each becoming a row of one.

Requires scope: `metrics:read`

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `website` | string | no | Website domain, e.g. "acme.com". Omit when the account has only one. |
| `period` | string | no | Period in plain language: "last 30 days", "yesterday", "July 2026", or "2026-07-01..2026-07-31". Defaults to the last 30 days. |
| `step` | string | no | What each step in the path is. Default channel. |
| `stages` | string[] | no | Count CRM or lifecycle milestones instead of tracked conversions, e.g. ["deal_won"] for closed-won deals, ["mql"], ["trial_started"], ["subscription_churned"]. With an attribution model this is how you credit DEAL revenue to the channels that earned it, which is the closed-loop number a B2B team is judged on. A deal is credited across its whole buying committee, so every contact on it contributes their journey. |
| `events` | string[] | no | Only count these conversion EVENT names, e.g. ["demo_booked"]. Takes precedence over types. |
| `types` | string[] | no | Only count these conversion categories, e.g. ["Web Form","Meeting"]. Coarser than events. |
| `max_touches` | number | no | Steps kept before truncation. Default 5. |
| `limit` | number | no | Paths to return. Default 20, max 100. |
