Quick start
ROAS of October’s cohorts by media source:paywall_viewed: count, value and ROAS per day since install:
Authentication
Every request must include anAuthorization header containing your Appstack API key, as for the Export API.
Cohorts are built from production data only, whatever the environment of the key.
Endpoint
Query parameters
Cohorts
string
required
First install date (inclusive),
YYYY-MM-DD.string
required
Last install date (inclusive),
YYYY-MM-DD. The range is capped at 366 days.string
One cohort per install
day, week (weeks start on Sunday) or month, returned in install_date. Without it, the whole date range is one cohort. Only installs between start_date and end_date count, so the first and last weeks or months can be partial.string
One row per
day, week or month since install, returned in days_since_install, weeks_since_install or months_since_install. Without it, you get the cohort totals.integer
With
period: stop at this period. period=day&max_period=30 returns D0 to D30.string
Split the cohorts by
media_source, campaign_name, adset_name, ad_name or keyword. Several values allowed. event_name is also accepted, to list your custom events.Filters
string
Keep only these media sources, for example
meta or organic.string
Keep only these campaigns.
adset_name, ad_name and keyword work the same way.string
default:"USD"
Currency of spend, revenue and values, as an ISO 4217 code such as
EUR. Amounts are converted with each day’s exchange rate.Metrics and output
string
default:"installs,total_spend,cohort_revenue"
The metrics to return, one column each. See Measures.
string
default:"json"
json (default), ndjson, csv, tsv, xml, xlsx or parquet.integer
default:"10000"
Maximum number of rows, between
1 and 10000.integer
default:"0"
Rows to skip. Increase it by
limit to get the next page; a page with fewer than limit rows is the last one.Measures
How measures work: cohort totals vs. by period
You can query a cohort in two ways:- Cohort totals (no
period): one value per cohort, covering everything since install. - By period (with
period): one row per period since install (D0, D1, D2…), so you can build curves.
days_since_install = 0) and never on later periods. As a result, any measure that divides by or subtracts spend (CPI, ROAS, profit, cost per event) is only available on cohort totals. To get ROAS or profit by period, use the roas_of_* and profit_of_* measures.
Measures
Measures marked ✗ are rejected with a
422 when period is set.
Event measures
Every standard in-app event has three measures:
The event name is prefixed with its source:
Custom events
Your own (non-standard) events don’t have fixed measure names. Query them withcustom: followed by the event name, exactly as your app sends it:
Server-to-server events keep their prefix:
custom:s2s_paywall_viewed. Each one is its own column, so you can request several custom events in one call, next to any other measure: measures=installs,custom:paywall_viewed,custom:onboarding_start. An event name your app never sent returns null.
Listing your custom events. Custom events also share a single set of measures per source:
To choose which event these measures refer to:
- All events side by side: add
group_by=event_name. This is also how you list the event names available. Installs, spend and revenue have no event name: they come back on a separate row whoseevent_nameisN/A. - One event: pass its name in
event_name(only these measures are allowed with it).
ROAS and profit by period
roas_of_<value measure> and profit_of_<value measure> compute ROAS and profit for a given value measure, matching the Cohorts view of the dashboard. Unlike roas and profit, they work with period, so use them to build ROAS or profit curves.
How they are calculated
- ROAS = value ÷ the cohort’s total ad spend.
- Profit = value − the cohort’s total ad spend.
- By period: each period’s ROAS is that period’s value divided by the cohort’s spend. Spend is subtracted from profit on the install period only. To get cumulative figures, sum the periods: D7 ROAS = ROAS of D0 + D1 + … + D7.
- With
group_by=event_name: each event is measured against the cohort’s whole spend, not a share of it. - Cohort without spend: ROAS is
null.
Extra rows. If a group has no value on the install period (for example, an event first tracked on day 7), the response still adds an install-period row for it, so its profit includes the spend. A page can therefore contain slightly more rows than
limit.Missing periods. With
period, a missing row means no value, not 0. Either nothing happened in that period, or the cohort hasn’t reached it yet (e.g. D30 for a cohort installed last week).Finding measures. An unknown measure is rejected with a
422 that names it. To list every measure available to your app, use the MCP server’s list_metrics tool with view eac_cohorts_view.Response
format=json returns a JSON object. The other formats return a file whose columns are, in order: install_date, the group_by dimensions, the period, then the measures.
With period=day&group_by=media_source:
array
One row per cohort (and per period with
period). install_date is the first day of the install day, week or month (2026-10-01T00:00:00.000). A measure with no value for the row is null.integer
Number of rows in this page.
Errors
A
422 is returned when:
- a date is missing or invalid,
end_dateis beforestart_date, or the range exceeds 366 days; period,group_by,install_date_granularity,formatorcurrencyhas an invalid value, ormax_periodis set withoutperiod;- a measure is unknown, or is marked ✗ in Measures while
periodis set; roas_of_orprofit_of_isn’t followed by a revenue or value measure;- a
custom:measure has no event name, or is combined withevent_nameorgroup_by=event_name; event_nameis used with measures other than the custom event ones;- the request covers too many cohorts to compute
roas_of_,profit_of_orcustom:measures (narrow the dates or thegroup_by); limitoroffsetis out of range.

