Churned customers

A churned customer is a shop that left — it had your app and now it doesn't. GET /api/v1/apps/:app/churned-customers returns a paginated object: "list" of the shops that have churned, with when they left, the plan they were last on, and their lifetime revenue and duration. Useful for win-back campaigns and warehouse ingestion. Requires the metrics:read scope.


GET/api/v1/apps/:app/churned-customers

Churned customers

Returns the app's churned shops as a paginated object: "list", most recently churned first. Each row is a shop that has left, with its churn timestamp, the plan it was last on, its lifetime revenue, and how long it stayed. total_count is the count after the lookback window and has_more tells you when to fetch the next page.

Use the months window to scope how far back to look — for example, only the shops that churned in the last quarter. To export the full list into a warehouse, prefer cursor pagination.

Path parameter

  • Name
    app
    Type
    string
    Description

    The team app's ULID, e.g. 01JN4HKQX0000000000000000.

Query parameters

  • Name
    months
    Type
    integer
    Description

    Look back this many months from today; 1–12. Omit to use the default lookback window.

  • Name
    cursor
    Type
    string
    Description

    Opt-in cursor pagination; opaque, max 64 chars. See Pagination.

  • Name
    page
    Type
    integer
    Description

    Page number, min 1.

  • Name
    per_page
    Type
    integer
    Description

    Rows per page, 1–100.

Request

GET
/api/v1/apps/:app/churned-customers
curl -G https://ranksyapp.com/api/v1/apps/01JN4HKQX0000000000000000/churned-customers \
  -H "Authorization: Bearer rk_live_..." \
  -d months=3 \
  -d per_page=25

Response

{
  "object": "list",
  "url": "/api/v1/apps/01JN4HKQX0000000000000000/churned-customers",
  "currency": "USD",
  "page": 1,
  "per_page": 25,
  "total_count": 47,
  "has_more": true,
  "metadata": {},
  "data": [
    {
      "shop_domain": "skin-authority.myshopify.com",
      "shop_id": "5271523",
      "churned_at": "2026-07-08T00:00:00+00:00",
      "last_plan_name": "Growth",
      "last_plan_amount": 49.00,
      "lifetime_revenue": 98.00,
      "lifetime_days": 30
    }
  ]
}

Response fields

The list is the shared catalog object: "list" envelope; each item in data is a churned-customer row.

List envelope (object: "list")

  • Name
    object
    Type
    string
    Description

    Always "list".

  • Name
    url
    Type
    string
    Description

    The endpoint path for this resource.

  • Name
    currency
    Type
    string
    Description

    The currency the monetary fields are reported in, e.g. USD.

  • Name
    page
    Type
    integer
    Description

    The current page number (1-based). null in cursor mode.

  • Name
    per_page
    Type
    integer
    Description

    Rows per page.

  • Name
    total_count
    Type
    integer
    Description

    Total churned shops in the lookback window. null in cursor mode.

  • Name
    has_more
    Type
    boolean
    Description

    Whether further pages exist.

  • Name
    metadata
    Type
    object
    Description

    Extra context about the query. {} when there is none.

  • Name
    next_cursor
    Type
    string
    Description

    Present only in cursor mode: the cursor to pass to fetch the next page, or null when there are no more rows.

  • Name
    data
    Type
    array
    Description

    The churned-customer rows for this page.

Churned-customer row

  • Name
    shop_domain
    Type
    string
    Description

    The *.myshopify.com domain of the churned shop, or null when unknown.

  • Name
    shop_id
    Type
    string
    Description

    The Shopify shop id, or null when unknown.

  • Name
    churned_at
    Type
    string
    Description

    ISO-8601 timestamp of when the shop churned.

  • Name
    last_plan_name
    Type
    string
    Description

    The plan the shop was on when it churned, or null when unknown.

  • Name
    last_plan_amount
    Type
    number
    Description

    That plan's amount in the plan currency, or null when unknown.

  • Name
    lifetime_revenue
    Type
    number
    Description

    Total revenue earned from the shop before it churned.

  • Name
    lifetime_days
    Type
    integer
    Description

    How many days the shop was a customer, or null when unknown.


Pagination

By default the list uses offset pagination. Use page and per_page (1–100) to walk the result set, and check has_more / total_count to know when to stop.

For exports, prefer cursor pagination — it opts in the moment you send a cursor parameter. Start with an empty cursor, read next_cursor off the response, and pass it back on the next request; repeat until next_cursor is null (equivalently, has_more is false). Cursor mode is stable under concurrent inserts and is not subject to the page-mode row cap, so it is the recommended way to export the full list into a warehouse (e.g. BigQuery). In cursor mode, page and total_count come back null.


Errors

Beyond the universal 401 / 403 / 422 / 429 (see Errors):

  • The list never 404s — an app with no configured Partner API integration, or no churned shops, returns an empty data list (a 200).
  • An out-of-range months (outside 1–12) surfaces as 422 validation_failed.

Was this page helpful?