revenue.sum
Calculate total revenue from events, optionally grouped by traffic source or campaign. Supports first-touch and last-touch attribution for understanding customer acquisition.
Instructions
Sum revenue from Money-typed event properties. Returns per-currency totals, optionally grouped by a traffic dimension (referrer_host, channel, country, device_type, pathname, utm_source/medium/campaign). Different currencies are never mixed in a single sum — each row is one (group, currency) pair. Money properties are tracked via clamp.track("purchase", { total: { amount: 29, currency: "USD" } }) — see /docs/concepts/revenue for the full Money type.
Attribution: attribution_model="last_touch" (default) groups revenue by the dimensions of the session where the revenue event fired — answers "what surface was active at conversion?". attribution_model="first_touch" joins each revenue event with the visitor's earliest-known session and groups by that session's acquisition dimension — answers "where did my paying customers actually come from?". For multi-visit funnels (typical B2B SaaS), first-touch is usually the more honest read on which channels actually drive revenue.
Examples:
"total revenue this month" → no group_by, period="30d"
"revenue by channel" → group_by="channel", period="30d"
"where did paying customers actually come from" → group_by="channel", attribution_model="first_touch"
"first-touch revenue per UTM campaign" → group_by="utm_campaign", attribution_model="first_touch"
"how much did Stripe purchases bring in from organic search" → event="purchase", channel="organic_search"
"top revenue countries" → group_by="country"
Limitations: events without any Money property contribute zero. If property is set, only that one Money key is summed; omitted, every Money property on matched events is included. Stripe-typed revenue (recommended) flows through server-side webhooks; client-only revenue is subject to ad-blocker loss. attribution_model="first_touch" only supports acquisition-dimension group_by (channel, referrer_host, utm_*); first-touch country / device / pathname are rejected because they're rarely what people actually mean by them. First-touch breakdowns are extremely sensitive to small samples — at single-digit paying-customer counts the per-channel rate is dominated by 1-2 users' acquisition history; check visitors before reading the rate, or pair with users.journey to validate against specific customers.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| project_id | No | Target project ID (e.g. "proj_abc123"). Required when the credential has access to multiple projects. If omitted and only one project is accessible, that project is used automatically. Call `projects.list` to discover available project IDs. | |
| period | No | Time period. Use "today", "yesterday", "7d", "30d", "90d", or a custom range as "YYYY-MM-DD:YYYY-MM-DD" (e.g. "2026-01-01:2026-03-31"). Defaults to "30d". | |
| event | No | Filter to a specific event name (e.g. "purchase", "checkout_completed"). Omit to sum Money properties across all events. | |
| property | No | Restrict the sum to a single Money property key on the event (e.g. "total", "mrr", "ltv"). Omit to sum every Money-typed property on matched events. | |
| group_by | No | Group revenue by a traffic dimension. Returns one row per (dimension, currency) pair. Omit for a single total per currency. | |
| attribution_model | No | Attribution model. "last_touch" (default) groups by the dimensions of the session where revenue fired. "first_touch" joins each revenue event with the visitor's earliest session and groups by that session's acquisition dim. First-touch only supports group_by in acquisition dimensions (channel, referrer_host, utm_*). | |
| limit | No | Max rows to return (1-50). Defaults to 10. | |
| pathname | No | Filter to a specific page path (e.g. "/pricing", "/blog/my-post"). Must start with /. | |
| utm_source | No | Filter by UTM source (e.g. "google", "twitter", "newsletter"). Case-sensitive, must match the value in the tracking URL. | |
| utm_medium | No | Filter by UTM medium (e.g. "cpc", "email", "social"). Case-sensitive. | |
| utm_campaign | No | Filter by UTM campaign name (e.g. "spring-launch", "product-hunt"). Case-sensitive. | |
| utm_content | No | Filter by UTM content (e.g. "hero-cta", "sidebar-banner"). Case-sensitive. | |
| utm_term | No | Filter by UTM term (e.g. "running+shoes"). Case-sensitive. | |
| referrer_host | No | Filter by referrer hostname (e.g. "news.ycombinator.com", "twitter.com", "github.com"). Use this to see what traffic from a specific source did. Must match the value returned by `traffic.breakdown(dimension="referrer_host")` exactly (lowercase, no protocol or path). | |
| country | No | ISO 3166-1 alpha-2 country code, uppercase (e.g. "US", "GB", "DE", "NL", "JP"). Filter results to visitors from this country. | |
| region | No | Administrative region inside a country (e.g. "California", "Bavaria"). Case-sensitive; must match the stored region exactly. Use traffic.breakdown(dimension="region") to discover values. | |
| city | No | City name (e.g. "San Francisco", "London"). Case-sensitive; must match the stored value. Use traffic.breakdown(dimension="city") to discover values. | |
| device_type | No | Device category. One of: "desktop", "mobile", "tablet". | |
| browser | No | Browser family (e.g. "Chrome", "Safari", "Firefox"). Use traffic.breakdown(dimension="browser") to discover the exact stored values. | |
| browser_version | No | Browser version string (e.g. "120.0"). Case-sensitive. | |
| os | No | Operating system family (e.g. "macOS", "iOS", "Windows", "Android"). Use traffic.breakdown(dimension="os") to discover stored values. | |
| os_version | No | OS version string (e.g. "14.2"). Case-sensitive. | |
| channel | No | Traffic channel. One of: "direct", "organic_search", "organic_social", "paid", "email", "referral". |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| rows | Yes |