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.


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 with start_date/end_date (supplying both is a 422).

  • Name
    start_date
    Type
    string
    Description

    YYYY-MM-DD. Supplying start_date and/or end_date switches the response to series mode.

  • Name
    end_date
    Type
    string
    Description

    YYYY-MM-DD. Must be greater than or equal to start_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. (nrr is 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, maximum 200.

Request

GET
/api/v1/apps/:app/metrics/:name
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

GET
/api/v1/apps/:app/metrics/mrr
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

GET
/api/v1/apps/:app/metrics/revenue
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

GET
/api/v1/apps/:app/metrics/active_subscriptions
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

GET
/api/v1/apps/:app/metrics/active_trials
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) or year (that figure annualised, ×12). Any other value returns 400 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

GET
/api/v1/apps/:app/metrics/ltv
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

GET
/api/v1/apps/:app/metrics/nrr
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

GET
/api/v1/apps/:app/metrics/trial_conversion_rate
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_churn only (the default and only basis in v1). Any other value returns 400 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

GET
/api/v1/apps/:app/metrics/churn_rate
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_churn only (the default). Any other value returns 400 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

GET
/api/v1/apps/:app/metrics/revenue_churn_rate
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

GET
/api/v1/apps/:app/metrics/churned_total
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

GET
/api/v1/apps/:app/metrics/installs
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

GET
/api/v1/apps/:app/metrics/uninstalls
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

GET
/api/v1/apps/:app/metrics/reactivations
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

GET
/api/v1/apps/:app/metrics/active_merchants
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 requested date, 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 requested vs what was available. available is null when 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.code is partner_integration_not_connected (never connected), partner_integration_unauthorized (credentials revoked or rejected — reconnect in Ranksy), or partner_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 — on ltv only: basis must be month or year. error.param is basis.
  • 400 unsupported_basis — on churn_rate / revenue_churn_rate only: basis must be real_churn. error.param is basis.

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 value is a fraction, not a percentage. 0.30 means 30%; the raw inputs live in components.
  • 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.
  • coverage is your source of truth for how much data backed a series response.

Was this page helpful?