# Channels, web, email & organic

**Read-only tools.** Cross-channel performance, GA4 web analytics, email marketing and organic social.

| Tool | Purpose |
|---|---|
| [`get_channels`](#get_channels) | All channels |
| [`get_ga4`](#get_ga4) | GA4 web analytics |
| [`get_email`](#get_email) | Email marketing |
| [`get_organic`](#get_organic) | Organic social |

## `get_channels`

**All channels**

Cross-channel performance from the unified channel_daily mart, which unions paid ads, email, organic social, GA4 web sessions, ecommerce orders and Signal conversions onto ONE canonical channel grain: Paid Search, Paid Social, Paid Other, Organic Search, Organic Social, Email, Direct, Referral, Affiliate, Other. This is the tool for channel mix, blended CAC/ROAS and any "which channel" question — the per-platform tools cannot be added up into these numbers.
mode=overview returns per-channel spend, impressions, clicks, sends, delivered, opens, reach, views, engagements, followers, sessions and key_events, plus a picked conversions and revenue with cac and roas, the native reach/engagement metric with its label, a per-platform breakdown and prior-period deltas, with a totals row spanning all channels. mode=daily returns the per-day, per-channel spend / sessions / conversions / revenue series.
conversions is picked orders → Signal → GA4 key events and revenue order_revenue → signal_revenue → ga4_revenue, applied consistently across channels, so the comparison is like for like — say which basis you are quoting. There are no filters beyond the window. Omit both dates for the default window: the last 30 complete days ending yesterday. If you bucket the daily series into weeks, use MONDAY-start weeks, the boundary the rest of this product uses.

**Posture:** read-only · **Module gate:** `channels` · **REST:** `POST /api/v1/tools/get_channels`

| Argument | Type | Required | Notes |
|---|---|---|---|
| `mode` | `overview` \| `daily` | **yes** | overview = per-channel totals with deltas and a totals row; daily = the per-day, per-channel series. |
| `end_date` | string | no | Window end, YYYY-MM-DD (inclusive). (pattern `^\d{4}-\d{2}-\d{2}$`) |
| `start_date` | string | no | Window start, YYYY-MM-DD (inclusive). Omit both dates for the default window: the last 30 complete days ending yesterday. (pattern `^\d{4}-\d{2}-\d{2}$`) |

## `get_ga4`

**GA4 web analytics**

Google Analytics 4 web analytics for this organization. Pick the mode for the question: summary (sessions / users / conversions totals), daily (per-day series), traffic_sources (by source and medium), campaigns (by GA4 campaign), channels (GA4's default channel grouping), engagement (sessions, bounce and duration by channel), key_events (GA4 conversion events), landing_pages, or geo_devices (device category and geography).
These are GA4's own session-scoped, GA4-attributed numbers: they will NOT tie out to ad-platform clicks or to the paid-ads tools, and GA4 channel groupings are not the Bellaso channel groupings — use get_channels for cross-channel comparison and say which source you are quoting. property_id limits to one property when several are connected. Omit both dates for the default window: the last 30 complete days ending yesterday. Weeks are MONDAY-start if you bucket the daily series.

**Posture:** read-only · **Module gate:** `ga4` · **REST:** `POST /api/v1/tools/get_ga4`

| Argument | Type | Required | Notes |
|---|---|---|---|
| `mode` | `summary` \| `daily` \| `traffic_sources` \| `campaigns` \| `channels` \| `engagement` \| `key_events` \| `landing_pages` \| `geo_devices` | **yes** | Which GA4 cut to return — see the tool description for each. |
| `end_date` | string | no | Window end, YYYY-MM-DD (inclusive). (pattern `^\d{4}-\d{2}-\d{2}$`) |
| `property_id` | string | no | Limit to one GA4 property id. Omit (or pass "all") to cover every connected property. (length 1–64, pattern `^[A-Za-z0-9_-]+$`) |
| `start_date` | string | no | Window start, YYYY-MM-DD (inclusive). Omit both dates for the default window: the last 30 complete days ending yesterday. (pattern `^\d{4}-\d{2}-\d{2}$`) |

## `get_email`

**Email marketing**

Email marketing analytics from the email_campaigns mart. Pick the mode: summary (sends, delivered, opens, clicks, unsubscribes, bounces with prior-period deltas), daily (per-day series), campaigns (the per-campaign table — sortable with sort_by/sort_dir, searchable with search over subject and campaign name, paged with limit/offset), subject_lines (subject leaderboard plus open/click rates broken out by subject feature, length bucket, weekday, hour and split test; min_sends gates who reaches the leaderboard), or filter_options (all-time campaign types, lists, sources and the available date range — call this first when you need a valid filter value).
Filters: campaign_type (exact), list_name (substring), source (exact). Open rates are inflated by privacy proxies on some clients — treat click-through and CTOR as the reliable engagement signals, and never present open rate as a deliverability measure. Omit both dates for the default window: the last 30 complete days ending yesterday.

**Posture:** read-only · **Module gate:** `email` · **REST:** `POST /api/v1/tools/get_email`

| Argument | Type | Required | Notes |
|---|---|---|---|
| `mode` | `summary` \| `daily` \| `campaigns` \| `subject_lines` \| `filter_options` | **yes** | Which email cut to return — see the tool description for each. |
| `campaign_type` | string | no | Filter to one campaign type (exact match; get the available values from mode=filter_options). (length 1–200, pattern `^[^'\\]+$`) |
| `end_date` | string | no | Window end, YYYY-MM-DD (inclusive). (pattern `^\d{4}-\d{2}-\d{2}$`) |
| `limit` | integer | no | Table mode: rows to return, 1-500 (default 25). (1–500) |
| `list_name` | string | no | Filter to campaigns sent to a list whose name CONTAINS this text (substring match). (length 1–200, pattern `^[^'\\]+$`) |
| `min_sends` | integer | no | subject_lines mode: minimum total sends before a subject enters the leaderboard (default 100; 0 removes the gate). Lower it for a low-volume sender. (0–100000) |
| `offset` | integer | no | Table mode: rows to skip, for paging (default 0). (0–100000) |
| `search` | string | no | campaigns mode: case-insensitive match on the subject or campaign name. (length 1–200) |
| `sort_by` | string | no | campaigns mode: sort column — sent_at \| sends \| delivered \| unique_opens \| unique_clicks \| open_rate \| click_rate \| ctor \| unsub_rate \| bounce_rate \| campaign_name \| subject (default sent_at). An invalid value returns the allowed list. (length 1–64) |
| `sort_dir` | `asc` \| `desc` | no | Sort direction for the table mode (default desc). |
| `source` | string | no | Filter to one email source/connector (exact match). (length 1–200, pattern `^[^'\\]+$`) |
| `start_date` | string | no | Window start, YYYY-MM-DD (inclusive). Omit both dates for the default window: the last 30 complete days ending yesterday. (pattern `^\d{4}-\d{2}-\d{2}$`) |

## `get_organic`

**Organic social**

Organic (unpaid) social analytics from the organic_social_daily and organic_social_posts marts — Facebook Pages and Instagram Business accounts today. Pick the mode: summary (followers, follower_change, reach, views, engagements, likes/comments/shares/saves, link_clicks, posts_published and engagement_rate, with prior-period deltas), daily (per-day series), accounts (per-account rollup with the latest follower count, ordered by reach), posts (the per-post table — sortable with sort_by/sort_dir, searchable with search over the caption, filterable by media_type, paged with limit/offset), or filter_options (all-time platforms, accounts, media types and the available date range).
followers is the LATEST per-account count inside the window, never a sum — do not add it across days or accounts. These are unpaid metrics only: paid social lives in the ads tools, and get_channels is what compares the two. Filters: platform (facebook | instagram), account_id (exact). Omit both dates for the default window: the last 30 complete days ending yesterday.

**Posture:** read-only · **Module gate:** `organic` · **REST:** `POST /api/v1/tools/get_organic`

| Argument | Type | Required | Notes |
|---|---|---|---|
| `mode` | `summary` \| `daily` \| `accounts` \| `posts` \| `filter_options` | **yes** | Which organic-social cut to return — see the tool description for each. |
| `account_id` | string | no | Filter to one social account id (exact; get ids from mode=accounts or mode=filter_options). (length 1–200, pattern `^[^'\\]+$`) |
| `end_date` | string | no | Window end, YYYY-MM-DD (inclusive). (pattern `^\d{4}-\d{2}-\d{2}$`) |
| `limit` | integer | no | Table mode: rows to return, 1-500 (default 25). (1–500) |
| `media_type` | string | no | posts mode: filter to one media type (e.g. IMAGE, VIDEO, CAROUSEL_ALBUM, REEL, STORY). (length 1–200, pattern `^[^'\\]+$`) |
| `offset` | integer | no | Table mode: rows to skip, for paging (default 0). (0–100000) |
| `platform` | `facebook` \| `instagram` | no | Filter to one platform. |
| `search` | string | no | posts mode: case-insensitive match on the post caption. (length 1–200) |
| `sort_by` | string | no | posts mode: sort column — published_at \| reach \| views \| likes \| comments \| shares \| saves \| engagements \| engagement_rate (default published_at). An invalid value returns the allowed list. (length 1–64) |
| `sort_dir` | `asc` \| `desc` | no | Sort direction for the table mode (default desc). |
| `start_date` | string | no | Window start, YYYY-MM-DD (inclusive). Omit both dates for the default window: the last 30 complete days ending yesterday. (pattern `^\d{4}-\d{2}-\d{2}$`) |
