Metrics
Every partner metric is its own endpoint — GET /api/v1/apps/:app/metrics/:name. With no date parameters you get a point-in-time snapshot (object: "metric") for the latest value; pass a single date for the snapshot as of that day; supplying start_date and/or end_date switches the same URL into a paginated time series (object: "list"). Each endpoint below documents only the parameters, components, and errors that apply to it.
Every metric reads the app's Shopify Partner integration. If it is not connected, rejected, or still initializing the request returns a 409 — see partner errors below and the Errors reference.
Common parameters
Every metric endpoint takes the same path parameter and the same date / pagination query parameters. The per-endpoint sections only call out the extra parameters specific to that metric (basis, window, currency, excluded_plans).
Path parameter
- Name
app- Type
- string
- Description
The team app's ULID, e.g.
01JN4HKQX0000000000000000.
Query parameters
- Name
date- Type
- string
- Description
YYYY-MM-DD. Returns a snapshot as of that day instead of the latest. Mutually exclusive withstart_date/end_date(supplying both is a422).
- Name
start_date- Type
- string
- Description
YYYY-MM-DD. Supplyingstart_dateand/orend_dateswitches the response to series mode.
- Name
end_date- Type
- string
- Description
YYYY-MM-DD. Must be greater than or equal tostart_date.
- Name
granularity- Type
- string
- Description
Series only. One of
day(default),week,month. Stock metrics take the bucket's last-day value; flow metrics SUM the bucket; ratios sum their components then divide. (nrris always monthly and ignores this.)
- Name
include_test- Type
- boolean
- Description
Acknowledged but has no effect — partner metrics never include Shopify test data. Echoed in
metadata.
- Name
page- Type
- integer
- Description
Series only. The page to return. Default
1.
- Name
per_page- Type
- integer
- Description
Series only. Points per page. Default
50, maximum200.
Request
curl https://ranksyapp.com/api/v1/apps/01JN4HKQX0000000000000000/metrics/mrr \
-H "Authorization: Bearer rk_live_..."
Revenue & subscriptions
Monthly recurring revenue
The app's current monthly recurring revenue. A money metric reported in the app's base payout currency (the currency key). Today's snapshot is recomputed live before the daily job writes; a series is a stock, so each bucket is the value as of its last day — never summed.
Additional parameters
- Name
currency- Type
- string
- Description
3-letter ISO code. Acknowledged but not converted — values stay in the app's base currency; a mismatch is noted in
metadata.currency_note.
No components.
Request
curl https://ranksyapp.com/api/v1/apps/01JN4HKQX0000000000000000/metrics/mrr \
-H "Authorization: Bearer rk_live_..."
Snapshot
{
"object": "metric",
"id": "mrr",
"app": "01JN4HKQX0000000000000000",
"date": "2026-05-29",
"value": 2331.52,
"currency": "USD",
"metadata": { "partner_sync_status": "complete", "currency_basis": "base" }
}
Revenue (gross + net)
Transaction revenue in the app's base payout currency. A money breakdown: value is gross revenue (the total transaction value before Shopify's revenue share). components carries the payout breakdown — net (after Shopify's cut), the derived shopify_fee (gross − net), and the per-stream sale flows subscription_revenue / usage_revenue / one_time_revenue (each the summed gross of that sale type). A flow metric — week/month buckets SUM the value and every component. The three streams do not add up to gross: refunds, credits, adjustments and referral transactions also move gross/net/shopify_fee but are not sale streams. Recurring subscription run-rate (MRR) is a point-in-time stock on a different time-basis — get it from the mrr metric, not here.
Additional parameters
- Name
currency- Type
- string
- Description
3-letter ISO code. Acknowledged but not converted (base currency only).
Components: gross, net, shopify_fee, subscription_revenue, usage_revenue, one_time_revenue.
Request
curl -G https://ranksyapp.com/api/v1/apps/01JN4HKQX0000000000000000/metrics/revenue \
-H "Authorization: Bearer rk_live_..." \
-d start_date=2026-05-01 \
-d end_date=2026-05-31 \
-d granularity=month
Series
{
"object": "list",
"url": "/api/v1/apps/01JN4HKQX0000000000000000/metrics/revenue",
"currency": "USD",
"page": 1,
"per_page": 50,
"total_count": 1,
"has_more": false,
"coverage": {
"requested": { "start": "2026-05-01", "end": "2026-05-31" },
"available": { "start": "2026-05-01", "end": "2026-05-31" }
},
"metadata": {
"partner_sync_status": "complete",
"currency_basis": "base",
"value_note": "value is gross revenue; components.net is after Shopify's cut"
},
"data": [
{
"date": "2026-05-01",
"value": 8421.00,
"components": {
"gross": 8421.00,
"net": 6736.80,
"shopify_fee": 1684.20,
"subscription_revenue": 7400.00,
"usage_revenue": 821.00,
"one_time_revenue": 200.00
}
}
]
}
Active subscriptions
Point-in-time count of active paid subscriptions. A stock — a series bucket reports the value as of its last day, never summed. No components, no currency. Takes only the common parameters.
Request
curl https://ranksyapp.com/api/v1/apps/01JN4HKQX0000000000000000/metrics/active_subscriptions \
-H "Authorization: Bearer rk_live_..."
Snapshot
{
"object": "metric",
"id": "active_subscriptions",
"app": "01JN4HKQX0000000000000000",
"date": "2026-05-29",
"value": 214,
"metadata": { "partner_sync_status": "complete" }
}
Active trials
Point-in-time count of subscriptions currently in a trial. A stock — series buckets take the last-day value, never summed. No components, no currency. Takes only the common parameters.
Request
curl https://ranksyapp.com/api/v1/apps/01JN4HKQX0000000000000000/metrics/active_trials \
-H "Authorization: Bearer rk_live_..."
Snapshot
{
"object": "metric",
"id": "active_trials",
"app": "01JN4HKQX0000000000000000",
"date": "2026-05-29",
"value": 18,
"metadata": { "partner_sync_status": "complete" }
}
Lifetime value & retention
Estimated lifetime value (LTV)
The dashboard's live, plan-aware estimated LTV (current ARPU ÷ 30-day churn rate) — computed live, never the lagging stored columns. A money metric. LTV is a point-in-time level, so a series stamps the current value on each bucket (never summed).
Additional parameters
- Name
basis- Type
- string
- Description
month(default — monthly estimated LTV) oryear(that figure annualised, ×12). Any other value returns400 invalid_basis.
- Name
excluded_plans- Type
- string | string[]
- Description
Plan names to drop from the calculation — comma-separated (
excluded_plans=Free,Trial) or repeated (excluded_plans[]=Free). Mirrors the dashboard LTV page.
- Name
currency- Type
- string
- Description
3-letter ISO code. Acknowledged but not converted (base currency only).
No components.
Request
curl -G https://ranksyapp.com/api/v1/apps/01JN4HKQX0000000000000000/metrics/ltv \
-H "Authorization: Bearer rk_live_..." \
-d basis=year \
-d excluded_plans=Free
Snapshot
{
"object": "metric",
"id": "ltv",
"app": "01JN4HKQX0000000000000000",
"date": "2026-05-29",
"value": 612.40,
"currency": "USD",
"metadata": {
"partner_sync_status": "complete",
"currency_basis": "base",
"basis": "year",
"computed": "live",
"excluded_plans": ["Free"]
}
}
Net revenue retention (NRR)
Net revenue retention, cohort-anchored and reported monthly (reuses the dashboard NRR calc). value is a fraction (1.05 = 105%). The snapshot is the trailing-12-month cohort NRR; a series returns one point per month and the granularity parameter has no effect.
Components: mrr_retained, mrr_base, plus the moving parts expansion, contraction, churn, and the derived net_change (expansion − contraction − churn) — all MRR amounts in the app's base currency. The value itself is dimensionless, so there is no currency key. Takes only the common parameters.
Request
curl https://ranksyapp.com/api/v1/apps/01JN4HKQX0000000000000000/metrics/nrr \
-H "Authorization: Bearer rk_live_..."
Snapshot
{
"object": "metric",
"id": "nrr",
"app": "01JN4HKQX0000000000000000",
"date": "2026-05-29",
"value": 1.05,
"components": {
"mrr_retained": 14962.50,
"mrr_base": 14250.00,
"expansion": 1200.00,
"contraction": 312.50,
"churn": 175.00,
"net_change": 712.50
},
"metadata": {
"partner_sync_status": "complete",
"basis": "cohort",
"window": "12mo",
"granularity_note": "NRR is reported monthly; the granularity param has no effect."
}
}
Trial conversion rate
Share of trials that convert to a paid subscription, cohort-anchored on the trial-start date (matches the dashboard + MCP). value is a fraction (0.30 = 30%). The snapshot is the trailing-30-day cohort and reads low because that cohort hasn't finished; a week/month series SUMS numerators and denominators then divides — daily rates are never averaged.
Components: trials_converted, trials_started. metadata also carries two supplementary figures for the same window — trials_churned (trials that cancelled without converting) and avg_time_to_convert_days (mean days from trial start to conversion). Takes only the common parameters.
Request
curl https://ranksyapp.com/api/v1/apps/01JN4HKQX0000000000000000/metrics/trial_conversion_rate \
-H "Authorization: Bearer rk_live_..."
Snapshot
{
"object": "metric",
"id": "trial_conversion_rate",
"app": "01JN4HKQX0000000000000000",
"date": "2026-05-29",
"value": 0.30,
"components": { "trials_converted": 30, "trials_started": 100 },
"metadata": {
"partner_sync_status": "complete",
"basis": "cohort",
"window": "30d",
"trials_churned": 12,
"avg_time_to_convert_days": 4.2,
"window_note": "Snapshot rate is the cohort of trials started in the trailing 30 days; it reads low because that cohort has not finished."
}
}
Churn
Customer churn rate
Rolling logo churn rate — the canonical "real churn" calc shared with the dashboard, frozen daily into a snapshot keyed on the Shopify event date (metadata.computed = "stored", never computed live). value is a fraction (0.125 = 12.5%). Overlapping windows are never summed: each series point is the rate as of the bucket's last day.
Additional parameters
- Name
window- Type
- string
- Description
Rolling-window length:
7d,30d(default),90d,365d. Selects which frozen daily snapshot column is read.
- Name
basis- Type
- string
- Description
real_churnonly (the default and only basis in v1). Any other value returns400 unsupported_basis.
Components: customers_churned, customers_at_risk — present only for the default 30d window; other windows store the rate alone and omit components (flagged by metadata.components_note).
Request
curl -G https://ranksyapp.com/api/v1/apps/01JN4HKQX0000000000000000/metrics/churn_rate \
-H "Authorization: Bearer rk_live_..." \
-d start_date=2026-04-01 \
-d end_date=2026-04-30 \
-d granularity=day \
-d window=30d
Series
{
"object": "list",
"url": "/api/v1/apps/01JN4HKQX0000000000000000/metrics/churn_rate",
"page": 1,
"per_page": 50,
"total_count": 30,
"has_more": false,
"coverage": {
"requested": { "start": "2026-04-01", "end": "2026-04-30" },
"available": { "start": "2026-04-01", "end": "2026-04-30" }
},
"metadata": {
"partner_sync_status": "complete",
"basis": "real_churn",
"computed": "stored",
"window": "30d",
"window_note": "Rolling 30d churn, frozen daily snapshot keyed on Shopify event date."
},
"data": [
{
"date": "2026-04-30",
"value": 0.042,
"components": { "customers_churned": 9, "customers_at_risk": 214 }
}
]
}
Revenue churn rate
Rolling revenue (MRR) churn rate from the same frozen daily snapshot as churn_rate (metadata.computed = "stored"), keyed on the Shopify event date. value is a fraction. Series points take the value as of the bucket's last day — never summed.
Additional parameters
- Name
window- Type
- string
- Description
Rolling-window length:
7d,30d(default),90d,365d.
- Name
basis- Type
- string
- Description
real_churnonly (the default). Any other value returns400 unsupported_basis.
Components: mrr_churned — the churned MRR amount behind the rate, present only for the default 30d window. Other windows store the rate alone and omit components (flagged by metadata.components_note).
Request
curl -G https://ranksyapp.com/api/v1/apps/01JN4HKQX0000000000000000/metrics/revenue_churn_rate \
-H "Authorization: Bearer rk_live_..." \
-d start_date=2026-04-01 \
-d end_date=2026-04-30 \
-d window=90d
Series
{
"object": "list",
"url": "/api/v1/apps/01JN4HKQX0000000000000000/metrics/revenue_churn_rate",
"page": 1,
"per_page": 50,
"total_count": 30,
"has_more": false,
"coverage": {
"requested": { "start": "2026-04-01", "end": "2026-04-30" },
"available": { "start": "2026-04-01", "end": "2026-04-30" }
},
"metadata": {
"partner_sync_status": "complete",
"basis": "real_churn",
"computed": "stored",
"window": "90d",
"window_note": "Rolling 90d churn, frozen daily snapshot keyed on Shopify event date."
},
"data": [
{ "date": "2026-04-30", "value": 0.038 }
]
}
Churned merchants
Count of distinct paying shops that churned in the trailing 30 days as of each date — a rolling window, not a per-day count (metadata.window = "30d"). A stock: series buckets report the value as of the bucket's last day; do not sum across days. No components, no currency. Takes only the common parameters.
Request
curl https://ranksyapp.com/api/v1/apps/01JN4HKQX0000000000000000/metrics/churned_total \
-H "Authorization: Bearer rk_live_..."
Snapshot
{
"object": "metric",
"id": "churned_total",
"app": "01JN4HKQX0000000000000000",
"date": "2026-05-29",
"value": 9,
"metadata": {
"partner_sync_status": "complete",
"window": "30d",
"window_note": "churned_total is the count of distinct paying shops that churned in the trailing 30 days as of each date — a rolling window, not a per-day count."
}
}
Installs & merchants
Installs
Daily app installs. A flow count — a week/month bucket SUMS the daily installs (dated to the bucket's last day); day keeps every row. A snapshot returns the latest stored day's value. No components, no currency. Takes only the common parameters.
Request
curl -G https://ranksyapp.com/api/v1/apps/01JN4HKQX0000000000000000/metrics/installs \
-H "Authorization: Bearer rk_live_..." \
-d start_date=2026-05-01 \
-d end_date=2026-05-31 \
-d granularity=week
Series
{
"object": "list",
"url": "/api/v1/apps/01JN4HKQX0000000000000000/metrics/installs",
"page": 1,
"per_page": 50,
"total_count": 5,
"has_more": false,
"coverage": {
"requested": { "start": "2026-05-01", "end": "2026-05-31" },
"available": { "start": "2026-05-01", "end": "2026-05-31" }
},
"metadata": { "partner_sync_status": "complete" },
"data": [
{ "date": "2026-05-04", "value": 41 },
{ "date": "2026-05-11", "value": 38 }
]
}
Uninstalls
Daily app uninstalls. A flow count — a week/month bucket SUMS the daily uninstalls; day keeps every row. No components, no currency. Takes only the common parameters.
Request
curl https://ranksyapp.com/api/v1/apps/01JN4HKQX0000000000000000/metrics/uninstalls \
-H "Authorization: Bearer rk_live_..."
Snapshot
{
"object": "metric",
"id": "uninstalls",
"app": "01JN4HKQX0000000000000000",
"date": "2026-05-29",
"value": 6,
"metadata": { "partner_sync_status": "complete" }
}
Reactivations
Daily reinstalls by shops that had previously uninstalled. A flow count — a week/month bucket SUMS the daily values; day keeps every row. No components, no currency. Takes only the common parameters.
Request
curl https://ranksyapp.com/api/v1/apps/01JN4HKQX0000000000000000/metrics/reactivations \
-H "Authorization: Bearer rk_live_..."
Snapshot
{
"object": "metric",
"id": "reactivations",
"app": "01JN4HKQX0000000000000000",
"date": "2026-05-29",
"value": 3,
"metadata": { "partner_sync_status": "complete" }
}
Active merchants
Point-in-time count of active (paying) merchants. The value is a stock — series buckets take the last-day value, never summed. components adds the period's flows: new activations and churned, plus the derived net_change (new − churned) — these do SUM across a week/month bucket. No currency.
Components: new, churned, net_change.
Request
curl https://ranksyapp.com/api/v1/apps/01JN4HKQX0000000000000000/metrics/active_merchants \
-H "Authorization: Bearer rk_live_..."
Snapshot
{
"object": "metric",
"id": "active_merchants",
"app": "01JN4HKQX0000000000000000",
"date": "2026-05-29",
"value": 1284,
"components": { "new": 22, "churned": 9, "net_change": 13 },
"metadata": { "partner_sync_status": "complete" }
}
Response shapes
Two shapes, selected by whether you pass dates. Money series declare currency once on the envelope — never per point.
Snapshot (object: "metric")
- Name
object- Type
- string
- Description
Always
"metric".
- Name
id- Type
- string
- Description
The metric name, e.g.
mrr.
- Name
app- Type
- string
- Description
The app ULID.
- Name
date- Type
- string
- Description
The date the value is current as of (
YYYY-MM-DD) — the requesteddate, or the latest available day when none was given.
- Name
value- Type
- number
- Description
The metric value. For ratios this is a fraction (e.g.
0.30), not a percentage.
- Name
currency- Type
- string
- Description
Present only for money metrics; the app's base payout currency.
- Name
components- Type
- object
- Description
Present only for ratio and breakdown metrics; the raw inputs behind
value.
- Name
metadata- Type
- object
- Description
Partner-sync health (
partner_sync_status,currency_basis) plus any per-metric notes.
Series (object: "list")
- Name
object- Type
- string
- Description
Always
"list".
- Name
url- Type
- string
- Description
The endpoint path for this metric.
- Name
currency- Type
- string
- Description
Present only for money metrics; applies to every point in
data.
- Name
page- Type
- integer
- Description
The current page number.
- Name
per_page- Type
- integer
- Description
Points per page.
- Name
total_count- Type
- integer
- Description
Total number of points across all pages.
- Name
has_more- Type
- boolean
- Description
Whether further pages exist.
- Name
coverage- Type
- object
- Description
What was
requestedvs what wasavailable.availableisnullwhen there is no data in range.
- Name
metadata- Type
- object
- Description
Partner-sync health plus per-metric notes.
- Name
data- Type
- array
- Description
The series points.
Point
Series points are compact — no per-row object tag and no per-row currency.
- Name
date- Type
- string
- Description
The bucket date (
YYYY-MM-DD); for week/month, the bucket's last day.
- Name
value- Type
- number
- Description
The value for that bucket. Ratios are fractions.
- Name
components- Type
- object
- Description
Present only for ratio and breakdown metrics.
Coverage
coverage tells the caller exactly how much data was available versus requested, so a short or empty result is never ambiguous.
coverage
"coverage": {
"requested": { "start": "2026-03-01", "end": "2026-05-29" },
"available": { "start": "2026-03-01", "end": "2026-05-29" }
}
Pagination
Series responses are paginated. Use page and per_page (default 50, max 200) to walk the result set, and check has_more / total_count to know when to stop. The currency and metadata on the envelope apply to every page.
Errors
Beyond the universal 401 / 403 / 422 / 429 (see Errors), the metric endpoints return:
409— the app's Shopify Partner integration isn't usable.error.codeispartner_integration_not_connected(never connected),partner_integration_unauthorized(credentials revoked or rejected — reconnect in Ranksy), orpartner_integration_pending(first sync still running — retry shortly). Every metric returns this until the integration is connected and has synced. Metrics never read BigQuery, so a BigQuery error is never returned here.400 invalid_basis— onltvonly:basismust bemonthoryear.error.paramisbasis.400 unsupported_basis— onchurn_rate/revenue_churn_rateonly:basismust bereal_churn.error.paramisbasis.
The other 12 metric endpoints have a route-fixed name and no rejectable basis, so they never return 400 — a bad query parameter surfaces as 422 instead.
Things to keep in mind
- Ratio
valueis a fraction, not a percentage.0.30means 30%; the raw inputs live incomponents. - Money metrics carry currency once. Inline on a snapshot, once on a series envelope — never on individual points. Values are always in the app's base payout currency (v1 does not convert).
- Stock vs flow vs ratio. Stock metrics take the bucket's last-day value; flow metrics SUM the bucket; ratios SUM their components then divide. Rolling-window metrics (
churned_total,churn_rate,revenue_churn_rate) overlap day-to-day and are never summed. coverageis your source of truth for how much data backed a series response.