Revenue ledger

The metric endpoints give you the aggregates; the ledger gives you the rows behind them. Three paginated object: "list" endpoints: every subscription entity, every transaction in the payout ledger, and a per-acquisition-cohort LTV rollup. Each subscription and transaction row carries a stable id so you can MERGE / dedup downstream and reconcile state over time.


GET/api/v1/apps/:app/subscriptions

Subscriptions

The app's Partner-API subscription entities — the row-level detail behind the active_subscriptions count metric. Each row has a stable id for MERGE / dedup and its own ISO currency (the Partner payout currency can differ per subscription, so there is no envelope-level currency). Test subscriptions are excluded by default — pass include_test=true to include them.

Path parameter

  • Name
    app
    Type
    string
    Description

    The team app's ULID.

Query parameters

  • Name
    status
    Type
    string
    Description

    Filter by status: active, cancelled, declined, expired, frozen.

  • Name
    include_test
    Type
    boolean
    Description

    Include Shopify test subscriptions. Default false.

  • Name
    sort
    Type
    string
    Description

    Sort column: activated_at (default), cancelled_at, created_at, amount.

  • Name
    order
    Type
    string
    Description

    asc or desc (default desc).

  • Name
    page
    Type
    integer
    Description

    Page to return. Default 1.

  • Name
    per_page
    Type
    integer
    Description

    Rows per page. Default 50, maximum 100.

Row fields: id, shop, plan, status, amount, currency, billing_interval, activated_at, cancelled_at, created_at. metadata carries summary.total_subscriptions (the filtered total) and the echoed filters.

Request

GET
/api/v1/apps/:app/subscriptions
curl -G https://ranksyapp.com/api/v1/apps/01JN4HKQX0000000000000000/subscriptions \
  -H "Authorization: Bearer rk_live_..." \
  -d status=active \
  -d per_page=50

Response

{
  "object": "list",
  "url": "/api/v1/apps/01JN4HKQX0000000000000000/subscriptions",
  "page": 1,
  "per_page": 50,
  "total_count": 640,
  "has_more": true,
  "metadata": {
    "summary": { "total_subscriptions": 640 },
    "filters": {
      "status": "active",
      "include_test": false,
      "sort": "activated_at",
      "order": "desc"
    }
  },
  "data": [
    {
      "id": "48217",
      "shop": "acme-store.myshopify.com",
      "plan": "Pro",
      "status": "active",
      "amount": 19.0,
      "currency": "USD",
      "billing_interval": "EVERY_30_DAYS",
      "activated_at": "2026-01-14T09:32:11+00:00",
      "cancelled_at": null,
      "created_at": "2026-01-14T09:35:00+00:00"
    }
  ]
}

GET/api/v1/apps/:app/transactions

Transactions

The app's Partner-API transaction ledger — the payout rows behind the revenue metric. Each row has a stable id, its own ISO currency, and a full processed_at timestamp (not just a day), plus the gross / net / shopify_fee split per row. Optional type and date-range filters; date filters apply to processed_at. Test transactions are excluded by default.

Path parameter

  • Name
    app
    Type
    string
    Description

    The team app's ULID.

Query parameters

  • Name
    type
    Type
    string
    Description

    Filter by Partner transaction type: APP_SUBSCRIPTION_SALE, APP_USAGE_SALE, APP_ONE_TIME_SALE, APP_SALE_ADJUSTMENT, APP_SALE_CREDIT, REFERRAL_TRANSACTION, APP_REFUND.

  • Name
    include_test
    Type
    boolean
    Description

    Include Shopify test transactions. Default false.

  • Name
    start_date
    Type
    string
    Description

    YYYY-MM-DD. Filters on processed_at (inclusive).

  • Name
    end_date
    Type
    string
    Description

    YYYY-MM-DD. Must be greater than or equal to start_date.

  • Name
    sort
    Type
    string
    Description

    Sort column: processed_at (default), created_at, gross_amount, net_amount.

  • Name
    order
    Type
    string
    Description

    asc or desc (default desc).

  • Name
    page
    Type
    integer
    Description

    Page to return. Default 1.

  • Name
    per_page
    Type
    integer
    Description

    Rows per page. Default 50, maximum 100.

Row fields: id, type, type_label, shop, amount (alias of gross_amount), gross_amount, net_amount, shopify_fee, currency, processed_at, created_at. metadata carries summary.total_transactions and the echoed filters.

Request

GET
/api/v1/apps/:app/transactions
curl -G https://ranksyapp.com/api/v1/apps/01JN4HKQX0000000000000000/transactions \
  -H "Authorization: Bearer rk_live_..." \
  -d type=APP_SUBSCRIPTION_SALE \
  -d start_date=2026-05-01 \
  -d end_date=2026-05-31

Response

{
  "object": "list",
  "url": "/api/v1/apps/01JN4HKQX0000000000000000/transactions",
  "page": 1,
  "per_page": 50,
  "total_count": 318,
  "has_more": true,
  "metadata": {
    "summary": { "total_transactions": 318 },
    "filters": {
      "type": "APP_SUBSCRIPTION_SALE",
      "include_test": false,
      "start_date": "2026-05-01",
      "end_date": "2026-05-31",
      "sort": "processed_at",
      "order": "desc"
    }
  },
  "data": [
    {
      "id": "9912034",
      "type": "APP_SUBSCRIPTION_SALE",
      "type_label": "Subscription sale",
      "shop": "acme-store.myshopify.com",
      "amount": 19.0,
      "gross_amount": 19.0,
      "net_amount": 15.2,
      "shopify_fee": 3.8,
      "currency": "USD",
      "processed_at": "2026-05-01T00:00:00+00:00",
      "created_at": "2026-05-01T04:12:00+00:00"
    }
  ]
}

GET/api/v1/apps/:app/ltv/cohorts

LTV cohorts

Per-acquisition-cohort lifetime value — one row per install month, with the cohort's customer count and its average / median / total lifetime revenue. This is the cohort detail behind the aggregate ltv metric: LTV per shop is SUM(gross_amount) over its real paid transactions, and the cohort is the month a shop first installed. Rows are ordered oldest cohort first.

Monetary values share one base payout currency, declared once on the envelope's currency key (never per row). Only pagination parameters are accepted — the breakdown is a full computed set.

Path parameter

  • Name
    app
    Type
    string
    Description

    The team app's ULID.

Query parameters

  • Name
    page
    Type
    integer
    Description

    Page to return. Default 1.

  • Name
    per_page
    Type
    integer
    Description

    Cohorts per page. Default 100, maximum 100.

Row fields: cohort (YYYY-MM), customers, average_ltv, median_ltv, total_revenue. metadata carries summary.total_cohorts and a value_note describing the calculation.

Request

GET
/api/v1/apps/:app/ltv/cohorts
curl https://ranksyapp.com/api/v1/apps/01JN4HKQX0000000000000000/ltv/cohorts \
  -H "Authorization: Bearer rk_live_..."

Response

{
  "object": "list",
  "url": "/api/v1/apps/01JN4HKQX0000000000000000/ltv/cohorts",
  "currency": "USD",
  "page": 1,
  "per_page": 100,
  "total_count": 18,
  "has_more": false,
  "metadata": {
    "summary": { "total_cohorts": 18 },
    "value_note": "LTV is per-shop SUM(gross_amount) over real paid transactions; cohort = the month a shop first installed. Amounts are in the app's base payout currency."
  },
  "data": [
    {
      "cohort": "2026-01",
      "customers": 42,
      "average_ltv": 184.5,
      "median_ltv": 96.0,
      "total_revenue": 7749.0
    },
    {
      "cohort": "2026-02",
      "customers": 51,
      "average_ltv": 132.4,
      "median_ltv": 72.0,
      "total_revenue": 6752.4
    }
  ]
}

Response shape

All three endpoints share the standard object: "list" envelope. They are not date-windowed in the series sense, so there is no coverage block. The currency key is present only on LTV cohorts (subscriptions and transactions carry currency per row instead).

  • Name
    object
    Type
    string
    Description

    Always "list".

  • Name
    url
    Type
    string
    Description

    The endpoint path.

  • Name
    currency
    Type
    string
    Description

    Base-currency ISO code. Present only on LTV cohorts; applies to every row.

  • Name
    page
    Type
    integer
    Description

    Current page number.

  • Name
    per_page
    Type
    integer
    Description

    Rows per page.

  • Name
    total_count
    Type
    integer
    Description

    Total rows across all pages (the filtered total for subscriptions / transactions).

  • Name
    has_more
    Type
    boolean
    Description

    Whether further pages exist.

  • Name
    metadata
    Type
    object
    Description

    A summary (filtered total) plus the echoed filters (subscriptions / transactions) or a value_note (LTV cohorts).

  • Name
    data
    Type
    array
    Description

    The rows.


Pagination

Walk the result set with page and per_page (default 50 for subscriptions / transactions, 100 for LTV cohorts; maximum 100), and check has_more / total_count to know when to stop. The metadata (and currency for LTV cohorts) on the envelope applies to every page.


Errors

Beyond the universal 401 / 403 / 422 / 429 (see Errors), these endpoints return:

  • 409 — the app's Shopify Partner integration isn't usable: partner_integration_not_connected, partner_integration_unauthorized (reconnect in Ranksy), or partner_integration_pending (first sync still running — retry shortly).

A bad query parameter (unknown status / type, malformed date, out-of-range per_page) surfaces as a 422.


Things to keep in mind

  • Use id to MERGE. Subscription and transaction rows carry a stable id — dedup and reconcile on it rather than on natural keys.
  • Currency placement differs. Subscriptions and transactions put currency on each row (per-subscription payout currency); LTV cohorts declare it once on the envelope.
  • Test data is opt-in. Subscriptions and transactions exclude Shopify test rows by default; pass include_test=true to include them. (LTV cohorts already exclude test shops.)
  • These are the rows behind the aggregates. Subscriptions back active_subscriptions, transactions back revenue, and LTV cohorts decompose ltv.

Was this page helpful?