# Metrics

Aggregated metrics, breakdowns and timeseries across any dimension, with the attribution model you choose.

Source: https://sourceloop.ai/help/api/metrics/

---

| Endpoint | Method | Path | Permission |
| --- | --- | --- | --- |
| Get metrics | GET | `/v1/metrics` | `metrics:read` |

Base URL: `https://app.sourceloop.ai/api/v1`

## Get metrics

`GET /v1/metrics`

Aggregate metrics, breakdowns and timeseries

Requires scope: `metrics:read`

Omit `group_by` for a single total. Add it for one row per dimension value,
which also returns the window totals so the share each row represents is visible.
Add `granularity` for a timeseries.

Note that a total and a timeseries are different queries: unique visitors cannot
be summed across days without counting returning people twice, so the aggregate
is computed once across the whole window.

### Query parameters

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `website` | string | no | Website domain, e.g. acme.com. Required only when the key covers more than one. |
| `period` | string | no | Plain-language period: "last 30 days", "yesterday", "July 2026", or "2026-07-01..2026-07-31". Ignored when from/to are given. |
| `from` | string (date-time) | no |  |
| `to` | string (date-time) | no |  |
| `metrics` | string | yes | Comma-separated. One or more of: visitors, sessions, pageviews, events, conversions, influenced_conversions, unique_converters, revenue, lifetime_value, customers, avg_ltv, repeat_rate, avg_orders, cohort_mrr, revenue_per_customer, milestones, conversion_rate, pageviews_per_session, revenue_per_visitor, spend, impressions, clicks, roas, cac, ltv_cac |
| `group_by` | string | no | Split by one dimension, or up to four comma-separated for a nested breakdown such as channel,source. Omit for a single total. One of: channel, source, medium, campaign, utm_term, utm_content, referrer_domain, page, landing_page, hostname, page_title, country, region, city, device_type, browser, operating_system, resolution, platform, ad_campaign, ad_set, ad, cohort Three of those are answered by a different store and behave differently: - platform and ad_campaign join ad SPEND to the campaign that acquired each customer, which is what makes cac and ltv_cac available. They take one dimension at a time and cannot be crossed with traffic dimensions. - resolution splits outcomes by WHY they had no journey (unmatched, predates tracking, imported contact) and is only available alongside credited metrics. - cohort returns a retention curve instead of a ranking: rows are (cohort, period_index) and the window chooses which cohorts appear, never which payments count. |
| `filter` | string[] | no | Repeatable, ANDed. Form: dimension:operator:value. Operators: eq, ne, in, nin, contains, not_contains. Filterable dimensions: channel, source, medium, campaign, utm_term, utm_content, referrer_domain, page, landing_page, hostname, page_title, country, region, city, device_type, browser, operating_system, resolution, event_name, event_type, identified, platform, ad_campaign, ad_set, ad, campaign_type, match_type, company_domain, crm_stage, crm_account_stage |
| `granularity` | string | no | Return a daily time series instead of a single total. Only day is supported: the underlying store buckets by calendar day in the website timezone, so hour, week and month are rejected rather than silently returning days under another label. |
| `attribution` | string | no | Credit conversions to a touchpoint using an attribution model instead of counting the event where the conversion fired. One of first_touch, last_touch, linear, u_shaped, time_decay, or up to five comma-separated to compare them in one response, which guarantees every model saw the same window and filters. Requires group_by, and only conversions and revenue can be attributed: a visitor has one channel at a time. When several models are given, each row nests one object per model; a null metric means that model truncated before reaching this value (see meta.truncated_models), which is not the same as zero. |
| `stages` | string | no | Count CRM and lifecycle milestones instead of tracked conversions: deal_created, deal_won, mql, trial_started, trial_converted, subscription_started, subscription_churned and the rest of the workspace stage vocabulary. A milestone is a different KIND of outcome from a conversion rather than a category of one, so the two are never blended. A milestone has no channel of its own, so this implies an attribution model and defaults to last_touch; the model used is echoed in meta.definitions. Deals are credited across the whole buying committee. |
| `conjunction` | string | no | How repeated filters combine. Default and. |
| `only_paid` | boolean | no | Restrict to paid traffic: a paid medium, or the presence of an ad click id. |
| `limit` | integer | no |  |

### Responses

- `200` Rows plus meta
- `400` Something was wrong with the request or the credential.
- `429` Too many requests for this workspace in the current minute. Wait Retry-After seconds and repeat the request unchanged.

### Example (cURL)

```bash
curl -s -X GET "https://app.sourceloop.ai/api/v1/metrics?website=acme.com&period=last%2030%20days" \
  -H "Authorization: Bearer $SOURCELOOP_API_KEY"
```

### Example (Node)

```javascript
const res = await fetch(
  "https://app.sourceloop.ai/api/v1/metrics?website=acme.com&period=last%2030%20days",
  {
    method: "GET",
    headers: {
      Authorization: `Bearer ${process.env.SOURCELOOP_API_KEY}`,
    },
  },
);

const data = await res.json();
```

### Example (Python)

```python
import os, requests

res = requests.get(
    "https://app.sourceloop.ai/api/v1/metrics?website=acme.com&period=last%2030%20days",
    headers={"Authorization": f"Bearer {os.environ['SOURCELOOP_API_KEY']}"},
)
data = res.json()
```
