{
    "openapi": "3.1.0",
    "info": {
        "title": "Ranksy API",
        "version": "1.0.0",
        "description": "Read-only REST API exposing Shopify partner metrics, App Store rankings, reviews and traffic analytics for the apps a Ranksy team tracks. Ranksy is the SaaS that Shopify app developers use to observe their apps; this API serves the same data programmatically.",
        "contact": {
            "name": "Ranksy",
            "url": "https://api.ranksyapp.com"
        }
    },
    "servers": [
        {
            "url": "https://ranksyapp.com/api/v1",
            "description": "Production"
        }
    ],
    "security": [
        {
            "bearerAuth": []
        }
    ],
    "paths": {
        "/apps/{app}": {
            "get": {
                "operationId": "v1.appOverview",
                "tags": [
                    "AppOverview"
                ],
                "parameters": [
                    {
                        "name": "app",
                        "in": "path",
                        "required": true,
                        "description": "The app ulid",
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "`AppDetailResource`",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/AppDetailResource"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Missing/invalid API key, or missing_team_scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "insufficient_permissions \u2014 the key lacks the required scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "resource_not_found \u2014 the addressed app / category / keyword does not exist or is not tracked.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "validation_failed \u2014 bad query parameters.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limit exceeded. See the Retry-After header.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        },
                        "headers": {
                            "Retry-After": {
                                "description": "Seconds to wait before retrying.",
                                "schema": {
                                    "type": "integer"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/apps": {
            "get": {
                "operationId": "v1.apps",
                "tags": [
                    "Apps"
                ],
                "parameters": [
                    {
                        "name": "page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1
                        }
                    },
                    {
                        "name": "per_page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1,
                            "maximum": 200
                        }
                    },
                    {
                        "name": "filter[name]",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "maxLength": 255
                        }
                    },
                    {
                        "name": "filter[status]",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "maxLength": 50
                        }
                    },
                    {
                        "name": "filter[built_for_shopify]",
                        "in": "query",
                        "schema": {
                            "type": [
                                "boolean",
                                "null"
                            ]
                        }
                    },
                    {
                        "name": "sort",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "maxLength": 50
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Paginated set of `AppResource`",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/AppsCollection"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Missing/invalid API key, or missing_team_scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "insufficient_permissions \u2014 the key lacks the required scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "validation_failed \u2014 bad query parameters.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limit exceeded. See the Retry-After header.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        },
                        "headers": {
                            "Retry-After": {
                                "description": "Seconds to wait before retrying.",
                                "schema": {
                                    "type": "integer"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/categories/{handle}": {
            "get": {
                "operationId": "v1.category",
                "tags": [
                    "Category"
                ],
                "parameters": [
                    {
                        "name": "handle",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "insight_type",
                        "in": "query",
                        "description": "overview = rating/sentiment distributions; complaints = pain points\n/ missing features; features = common + loved features.",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "enum": [
                                "overview",
                                "complaints",
                                "features"
                            ]
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "`CategoryResource`",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/CategoryResource"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Missing/invalid API key, or missing_team_scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "insufficient_permissions \u2014 the key lacks the required scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "resource_not_found \u2014 the addressed app / category / keyword does not exist or is not tracked.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "validation_failed \u2014 bad query parameters.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limit exceeded. See the Retry-After header.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        },
                        "headers": {
                            "Retry-After": {
                                "description": "Seconds to wait before retrying.",
                                "schema": {
                                    "type": "integer"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/categories/{handle}/rankings": {
            "get": {
                "operationId": "v1.categoryRankings",
                "tags": [
                    "CategoryRankings"
                ],
                "parameters": [
                    {
                        "name": "handle",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "sort",
                        "in": "query",
                        "description": "rank = scraped category rank ascending; rating / reviews = descending.",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "enum": [
                                "rank",
                                "rating",
                                "reviews"
                            ]
                        }
                    },
                    {
                        "name": "page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1
                        }
                    },
                    {
                        "name": "per_page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1,
                            "maximum": 50
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Paginated set of `CategoryRankingRowResource`",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/CategoryRankingsCollection"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Missing/invalid API key, or missing_team_scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "insufficient_permissions \u2014 the key lacks the required scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "resource_not_found \u2014 the addressed app / category / keyword does not exist or is not tracked.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "validation_failed \u2014 bad query parameters.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limit exceeded. See the Retry-After header.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        },
                        "headers": {
                            "Retry-After": {
                                "description": "Seconds to wait before retrying.",
                                "schema": {
                                    "type": "integer"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/apps/{app}/competitors": {
            "get": {
                "operationId": "v1.competitors",
                "tags": [
                    "Competitors"
                ],
                "parameters": [
                    {
                        "name": "app",
                        "in": "path",
                        "required": true,
                        "description": "The app ulid",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "sort",
                        "in": "query",
                        "description": "Whitelist guards the in-memory sort: only these tokens are accepted,\neach mapped to a stable column in sortColumn(). Anything else \u2192 422.",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "enum": [
                                "relevance",
                                "reviews",
                                "rating"
                            ]
                        }
                    },
                    {
                        "name": "order",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "enum": [
                                "asc",
                                "desc"
                            ]
                        }
                    },
                    {
                        "name": "page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1
                        }
                    },
                    {
                        "name": "per_page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1,
                            "maximum": 100
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Paginated set of `CompetitorResource`",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/CompetitorsCollection"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Missing/invalid API key, or missing_team_scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "insufficient_permissions \u2014 the key lacks the required scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "resource_not_found \u2014 the addressed app / category / keyword does not exist or is not tracked.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "validation_failed \u2014 bad query parameters.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limit exceeded. See the Retry-After header.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        },
                        "headers": {
                            "Retry-After": {
                                "description": "Seconds to wait before retrying.",
                                "schema": {
                                    "type": "integer"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/apps/{app}/metrics/mrr": {
            "get": {
                "operationId": "v1.getMetric.mrr",
                "description": "The app's current monthly recurring revenue, a **money** metric reported in the app's base payout currency (the `currency` key).\n\n- **Snapshot** (no date range): the latest stored MRR; today's value is recomputed live before the daily snapshot writes.\n- **Series** (`start_date`/`end_date`): MRR is a *stock* (a level), so each bucket reports the value as of the bucket's last day \u2014 never summed.\n\nNo `components`. A `currency` param is acknowledged in metadata only \u2014 values are never converted from the base currency.",
                "summary": "Monthly recurring revenue (MRR)",
                "tags": [
                    "Metrics"
                ],
                "parameters": [
                    {
                        "name": "app",
                        "in": "path",
                        "required": true,
                        "description": "The app ulid",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "date",
                        "in": "query",
                        "description": "Single as-of date \u2192 a snapshot for that date. Mutually exclusive\nwith start_date/end_date (which select a series); supplying both\nis a 422. Omit all three for the latest value.",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "start_date",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "end_date",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "granularity",
                        "in": "query",
                        "description": "Aggregation bucket size for a series response. 'day' is the\nnative PMD grain; week/month are rolled up by GetMetricForApi.",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "enum": [
                                "day",
                                "week",
                                "month"
                            ]
                        }
                    },
                    {
                        "name": "currency",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "minLength": 3,
                            "maxLength": 3
                        }
                    },
                    {
                        "name": "include_test",
                        "in": "query",
                        "schema": {
                            "type": [
                                "boolean",
                                "null"
                            ]
                        }
                    },
                    {
                        "name": "page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1
                        }
                    },
                    {
                        "name": "per_page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1,
                            "maximum": 200
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "`MetricSeriesCollection`\n\n`MetricResource`",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "anyOf": [
                                        {
                                            "$ref": "#/components/schemas/MetricSeriesCollection"
                                        },
                                        {
                                            "$ref": "#/components/schemas/MetricResource"
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Missing/invalid API key, or missing_team_scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "insufficient_permissions \u2014 the key lacks the required scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "409": {
                        "description": "**409** \u2014 this metric depends on the app's Shopify Partner integration, which isn't usable yet. `error.code` is one of: `partner_integration_not_connected` (no Partner API integration has ever been connected for this app), `partner_integration_unauthorized` (the stored Partner credentials were revoked or rejected \u2014 reconnect the integration in Ranksy), or `partner_integration_pending` (the first partner sync is still running \u2014 retry once it completes). Partner metrics keep returning 409 until the integration is connected and has synced at least once.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "validation_failed \u2014 bad query parameters.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limit exceeded. See the Retry-After header.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        },
                        "headers": {
                            "Retry-After": {
                                "description": "Seconds to wait before retrying.",
                                "schema": {
                                    "type": "integer"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/apps/{app}/metrics/revenue": {
            "get": {
                "operationId": "v1.getMetric.revenue",
                "description": "Transaction revenue in the app's base payout currency. A **money breakdown** metric: `value` is **gross** revenue (total transaction value before Shopify's revenue share) and `components` carries `{ gross, net }`, where net is after Shopify's cut.\n\nA *flow* metric: week/month buckets SUM `value` and every component. Carries the base-currency `currency` code.",
                "summary": "Revenue (gross + net)",
                "tags": [
                    "Metrics"
                ],
                "parameters": [
                    {
                        "name": "app",
                        "in": "path",
                        "required": true,
                        "description": "The app ulid",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "date",
                        "in": "query",
                        "description": "Single as-of date \u2192 a snapshot for that date. Mutually exclusive\nwith start_date/end_date (which select a series); supplying both\nis a 422. Omit all three for the latest value.",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "start_date",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "end_date",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "granularity",
                        "in": "query",
                        "description": "Aggregation bucket size for a series response. 'day' is the\nnative PMD grain; week/month are rolled up by GetMetricForApi.",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "enum": [
                                "day",
                                "week",
                                "month"
                            ]
                        }
                    },
                    {
                        "name": "currency",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "minLength": 3,
                            "maxLength": 3
                        }
                    },
                    {
                        "name": "include_test",
                        "in": "query",
                        "schema": {
                            "type": [
                                "boolean",
                                "null"
                            ]
                        }
                    },
                    {
                        "name": "page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1
                        }
                    },
                    {
                        "name": "per_page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1,
                            "maximum": 200
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "`MetricSeriesCollection`\n\n`MetricResource`",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "anyOf": [
                                        {
                                            "$ref": "#/components/schemas/MetricSeriesCollection"
                                        },
                                        {
                                            "$ref": "#/components/schemas/MetricResource"
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Missing/invalid API key, or missing_team_scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "insufficient_permissions \u2014 the key lacks the required scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "409": {
                        "description": "**409** \u2014 this metric depends on the app's Shopify Partner integration, which isn't usable yet. `error.code` is one of: `partner_integration_not_connected` (no Partner API integration has ever been connected for this app), `partner_integration_unauthorized` (the stored Partner credentials were revoked or rejected \u2014 reconnect the integration in Ranksy), or `partner_integration_pending` (the first partner sync is still running \u2014 retry once it completes). Partner metrics keep returning 409 until the integration is connected and has synced at least once.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "validation_failed \u2014 bad query parameters.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limit exceeded. See the Retry-After header.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        },
                        "headers": {
                            "Retry-After": {
                                "description": "Seconds to wait before retrying.",
                                "schema": {
                                    "type": "integer"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/apps/{app}/metrics/ltv": {
            "get": {
                "operationId": "v1.getMetric.ltv",
                "description": "The dashboard's live, plan-aware **estimated LTV** (current ARPU \u00f7 30-day churn rate), computed live \u2014 never the lagging stored columns. A **money** metric (base-currency `currency`).\n\n- `basis` = `month` (default) or `year` (the monthly figure annualised, \u00d712).\n- `excluded_plans` removes plans from the calculation (comma-separated, or repeated `excluded_plans[]`), exactly like the dashboard LTV page.\n- LTV is a point-in-time *level* computed as-of-now; a series stamps that current value on each bucket and never sums.\n\nNo `components`. Returns **400** `invalid_basis` for an unsupported basis.",
                "summary": "Estimated lifetime value (LTV)",
                "tags": [
                    "Metrics"
                ],
                "parameters": [
                    {
                        "name": "app",
                        "in": "path",
                        "required": true,
                        "description": "The app ulid",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "date",
                        "in": "query",
                        "description": "Single as-of date \u2192 a snapshot for that date. Mutually exclusive\nwith start_date/end_date (which select a series); supplying both\nis a 422. Omit all three for the latest value.",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "start_date",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "end_date",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "granularity",
                        "in": "query",
                        "description": "Aggregation bucket size for a series response. 'day' is the\nnative PMD grain; week/month are rolled up by GetMetricForApi.",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "enum": [
                                "day",
                                "week",
                                "month"
                            ]
                        }
                    },
                    {
                        "name": "basis",
                        "in": "query",
                        "description": "Period basis: `month` (default \u2014 monthly estimated LTV) or `year` (that figure annualised, \u00d712).",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "enum": [
                                "month",
                                "year"
                            ],
                            "default": "month"
                        }
                    },
                    {
                        "name": "currency",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "minLength": 3,
                            "maxLength": 3
                        }
                    },
                    {
                        "name": "excluded_plans[]",
                        "in": "query",
                        "schema": {
                            "type": "array",
                            "items": {
                                "type": "string"
                            }
                        }
                    },
                    {
                        "name": "include_test",
                        "in": "query",
                        "schema": {
                            "type": [
                                "boolean",
                                "null"
                            ]
                        }
                    },
                    {
                        "name": "page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1
                        }
                    },
                    {
                        "name": "per_page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1,
                            "maximum": 200
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "`MetricSeriesCollection`\n\n`MetricResource`",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "anyOf": [
                                        {
                                            "$ref": "#/components/schemas/MetricSeriesCollection"
                                        },
                                        {
                                            "$ref": "#/components/schemas/MetricResource"
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "**400 `invalid_basis`** \u2014 the `basis` query param was not a value LTV supports. Pass `basis=month` (the default) or `basis=year`; anything else is rejected with `error.param` = `basis` and `error.message` listing the supported values. This is the only 400 this endpoint returns (the metric name is fixed by the route, so `unknown_metric` cannot occur here).",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Missing/invalid API key, or missing_team_scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "insufficient_permissions \u2014 the key lacks the required scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "409": {
                        "description": "**409** \u2014 this metric depends on the app's Shopify Partner integration, which isn't usable yet. `error.code` is one of: `partner_integration_not_connected` (no Partner API integration has ever been connected for this app), `partner_integration_unauthorized` (the stored Partner credentials were revoked or rejected \u2014 reconnect the integration in Ranksy), or `partner_integration_pending` (the first partner sync is still running \u2014 retry once it completes). Partner metrics keep returning 409 until the integration is connected and has synced at least once.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "validation_failed \u2014 bad query parameters.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limit exceeded. See the Retry-After header.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        },
                        "headers": {
                            "Retry-After": {
                                "description": "Seconds to wait before retrying.",
                                "schema": {
                                    "type": "integer"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/apps/{app}/metrics/nrr": {
            "get": {
                "operationId": "v1.getMetric.nrr",
                "description": "Net revenue retention, cohort-anchored and reported **monthly** (reuses the dashboard NRR computation). Value is a **fraction** (1.10 = 110%).\n\n`components`: `{ mrr_retained, mrr_base }` \u2014 MRR amounts in the app's base payout currency. The `value` itself is dimensionless, so there is no top-level `currency` key.\n\n- **Snapshot**: the trailing-12-month cohort NRR (`metadata.window` = `12mo`).\n- **Series**: one point per month over the requested range; the `granularity` param has no effect (NRR is always monthly).",
                "summary": "Net revenue retention (NRR)",
                "tags": [
                    "Metrics"
                ],
                "parameters": [
                    {
                        "name": "app",
                        "in": "path",
                        "required": true,
                        "description": "The app ulid",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "date",
                        "in": "query",
                        "description": "Single as-of date \u2192 a snapshot for that date. Mutually exclusive\nwith start_date/end_date (which select a series); supplying both\nis a 422. Omit all three for the latest value.",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "start_date",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "end_date",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "granularity",
                        "in": "query",
                        "description": "Aggregation bucket size for a series response. 'day' is the\nnative PMD grain; week/month are rolled up by GetMetricForApi.",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "enum": [
                                "day",
                                "week",
                                "month"
                            ]
                        }
                    },
                    {
                        "name": "include_test",
                        "in": "query",
                        "schema": {
                            "type": [
                                "boolean",
                                "null"
                            ]
                        }
                    },
                    {
                        "name": "page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1
                        }
                    },
                    {
                        "name": "per_page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1,
                            "maximum": 200
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "`MetricSeriesCollection`\n\n`MetricResource`",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "anyOf": [
                                        {
                                            "$ref": "#/components/schemas/MetricSeriesCollection"
                                        },
                                        {
                                            "$ref": "#/components/schemas/MetricResource"
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Missing/invalid API key, or missing_team_scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "insufficient_permissions \u2014 the key lacks the required scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "409": {
                        "description": "**409** \u2014 this metric depends on the app's Shopify Partner integration, which isn't usable yet. `error.code` is one of: `partner_integration_not_connected` (no Partner API integration has ever been connected for this app), `partner_integration_unauthorized` (the stored Partner credentials were revoked or rejected \u2014 reconnect the integration in Ranksy), or `partner_integration_pending` (the first partner sync is still running \u2014 retry once it completes). Partner metrics keep returning 409 until the integration is connected and has synced at least once.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "validation_failed \u2014 bad query parameters.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limit exceeded. See the Retry-After header.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        },
                        "headers": {
                            "Retry-After": {
                                "description": "Seconds to wait before retrying.",
                                "schema": {
                                    "type": "integer"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/apps/{app}/metrics/trial_conversion_rate": {
            "get": {
                "operationId": "v1.getMetric.trial_conversion_rate",
                "description": "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%), not a percentage.\n\n`components`: `{ trials_converted, trials_started }` \u2014 the raw cohort counts behind `value`.\n\n- **Snapshot**: the trailing-30-day cohort rate (`metadata.window` = `30d`); it reads low because that cohort hasn't finished.\n- **Series**: week/month buckets SUM numerators and denominators then divide \u2014 daily rates are never averaged.",
                "summary": "Trial conversion rate",
                "tags": [
                    "Metrics"
                ],
                "parameters": [
                    {
                        "name": "app",
                        "in": "path",
                        "required": true,
                        "description": "The app ulid",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "date",
                        "in": "query",
                        "description": "Single as-of date \u2192 a snapshot for that date. Mutually exclusive\nwith start_date/end_date (which select a series); supplying both\nis a 422. Omit all three for the latest value.",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "start_date",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "end_date",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "granularity",
                        "in": "query",
                        "description": "Aggregation bucket size for a series response. 'day' is the\nnative PMD grain; week/month are rolled up by GetMetricForApi.",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "enum": [
                                "day",
                                "week",
                                "month"
                            ]
                        }
                    },
                    {
                        "name": "include_test",
                        "in": "query",
                        "schema": {
                            "type": [
                                "boolean",
                                "null"
                            ]
                        }
                    },
                    {
                        "name": "page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1
                        }
                    },
                    {
                        "name": "per_page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1,
                            "maximum": 200
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "`MetricSeriesCollection`\n\n`MetricResource`",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "anyOf": [
                                        {
                                            "$ref": "#/components/schemas/MetricSeriesCollection"
                                        },
                                        {
                                            "$ref": "#/components/schemas/MetricResource"
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Missing/invalid API key, or missing_team_scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "insufficient_permissions \u2014 the key lacks the required scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "409": {
                        "description": "**409** \u2014 this metric depends on the app's Shopify Partner integration, which isn't usable yet. `error.code` is one of: `partner_integration_not_connected` (no Partner API integration has ever been connected for this app), `partner_integration_unauthorized` (the stored Partner credentials were revoked or rejected \u2014 reconnect the integration in Ranksy), or `partner_integration_pending` (the first partner sync is still running \u2014 retry once it completes). Partner metrics keep returning 409 until the integration is connected and has synced at least once.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "validation_failed \u2014 bad query parameters.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limit exceeded. See the Retry-After header.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        },
                        "headers": {
                            "Retry-After": {
                                "description": "Seconds to wait before retrying.",
                                "schema": {
                                    "type": "integer"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/apps/{app}/metrics/active_merchants": {
            "get": {
                "operationId": "v1.getMetric.active_merchants",
                "description": "Point-in-time count of active (installed) merchants. A *stock*: a series bucket reports the value as of the bucket's last day \u2014 never summed. No `components`, no currency.",
                "summary": "Active merchants",
                "tags": [
                    "Metrics"
                ],
                "parameters": [
                    {
                        "name": "app",
                        "in": "path",
                        "required": true,
                        "description": "The app ulid",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "date",
                        "in": "query",
                        "description": "Single as-of date \u2192 a snapshot for that date. Mutually exclusive\nwith start_date/end_date (which select a series); supplying both\nis a 422. Omit all three for the latest value.",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "start_date",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "end_date",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "granularity",
                        "in": "query",
                        "description": "Aggregation bucket size for a series response. 'day' is the\nnative PMD grain; week/month are rolled up by GetMetricForApi.",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "enum": [
                                "day",
                                "week",
                                "month"
                            ]
                        }
                    },
                    {
                        "name": "include_test",
                        "in": "query",
                        "schema": {
                            "type": [
                                "boolean",
                                "null"
                            ]
                        }
                    },
                    {
                        "name": "page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1
                        }
                    },
                    {
                        "name": "per_page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1,
                            "maximum": 200
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "`MetricSeriesCollection`\n\n`MetricResource`",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "anyOf": [
                                        {
                                            "$ref": "#/components/schemas/MetricSeriesCollection"
                                        },
                                        {
                                            "$ref": "#/components/schemas/MetricResource"
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Missing/invalid API key, or missing_team_scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "insufficient_permissions \u2014 the key lacks the required scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "409": {
                        "description": "**409** \u2014 this metric depends on the app's Shopify Partner integration, which isn't usable yet. `error.code` is one of: `partner_integration_not_connected` (no Partner API integration has ever been connected for this app), `partner_integration_unauthorized` (the stored Partner credentials were revoked or rejected \u2014 reconnect the integration in Ranksy), or `partner_integration_pending` (the first partner sync is still running \u2014 retry once it completes). Partner metrics keep returning 409 until the integration is connected and has synced at least once.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "validation_failed \u2014 bad query parameters.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limit exceeded. See the Retry-After header.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        },
                        "headers": {
                            "Retry-After": {
                                "description": "Seconds to wait before retrying.",
                                "schema": {
                                    "type": "integer"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/apps/{app}/metrics/active_subscriptions": {
            "get": {
                "operationId": "v1.getMetric.active_subscriptions",
                "description": "Point-in-time count of active paid subscriptions. A *stock* (a level): a series bucket reports the value as of the bucket's last day \u2014 never summed. No `components`, no currency.",
                "summary": "Active subscriptions",
                "tags": [
                    "Metrics"
                ],
                "parameters": [
                    {
                        "name": "app",
                        "in": "path",
                        "required": true,
                        "description": "The app ulid",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "date",
                        "in": "query",
                        "description": "Single as-of date \u2192 a snapshot for that date. Mutually exclusive\nwith start_date/end_date (which select a series); supplying both\nis a 422. Omit all three for the latest value.",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "start_date",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "end_date",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "granularity",
                        "in": "query",
                        "description": "Aggregation bucket size for a series response. 'day' is the\nnative PMD grain; week/month are rolled up by GetMetricForApi.",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "enum": [
                                "day",
                                "week",
                                "month"
                            ]
                        }
                    },
                    {
                        "name": "include_test",
                        "in": "query",
                        "schema": {
                            "type": [
                                "boolean",
                                "null"
                            ]
                        }
                    },
                    {
                        "name": "page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1
                        }
                    },
                    {
                        "name": "per_page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1,
                            "maximum": 200
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "`MetricSeriesCollection`\n\n`MetricResource`",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "anyOf": [
                                        {
                                            "$ref": "#/components/schemas/MetricSeriesCollection"
                                        },
                                        {
                                            "$ref": "#/components/schemas/MetricResource"
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Missing/invalid API key, or missing_team_scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "insufficient_permissions \u2014 the key lacks the required scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "409": {
                        "description": "**409** \u2014 this metric depends on the app's Shopify Partner integration, which isn't usable yet. `error.code` is one of: `partner_integration_not_connected` (no Partner API integration has ever been connected for this app), `partner_integration_unauthorized` (the stored Partner credentials were revoked or rejected \u2014 reconnect the integration in Ranksy), or `partner_integration_pending` (the first partner sync is still running \u2014 retry once it completes). Partner metrics keep returning 409 until the integration is connected and has synced at least once.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "validation_failed \u2014 bad query parameters.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limit exceeded. See the Retry-After header.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        },
                        "headers": {
                            "Retry-After": {
                                "description": "Seconds to wait before retrying.",
                                "schema": {
                                    "type": "integer"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/apps/{app}/metrics/active_trials": {
            "get": {
                "operationId": "v1.getMetric.active_trials",
                "description": "Point-in-time count of subscriptions currently in a trial. A *stock*: a series bucket reports the value as of the bucket's last day \u2014 never summed. No `components`, no currency.",
                "summary": "Active trials",
                "tags": [
                    "Metrics"
                ],
                "parameters": [
                    {
                        "name": "app",
                        "in": "path",
                        "required": true,
                        "description": "The app ulid",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "date",
                        "in": "query",
                        "description": "Single as-of date \u2192 a snapshot for that date. Mutually exclusive\nwith start_date/end_date (which select a series); supplying both\nis a 422. Omit all three for the latest value.",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "start_date",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "end_date",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "granularity",
                        "in": "query",
                        "description": "Aggregation bucket size for a series response. 'day' is the\nnative PMD grain; week/month are rolled up by GetMetricForApi.",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "enum": [
                                "day",
                                "week",
                                "month"
                            ]
                        }
                    },
                    {
                        "name": "include_test",
                        "in": "query",
                        "schema": {
                            "type": [
                                "boolean",
                                "null"
                            ]
                        }
                    },
                    {
                        "name": "page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1
                        }
                    },
                    {
                        "name": "per_page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1,
                            "maximum": 200
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "`MetricSeriesCollection`\n\n`MetricResource`",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "anyOf": [
                                        {
                                            "$ref": "#/components/schemas/MetricSeriesCollection"
                                        },
                                        {
                                            "$ref": "#/components/schemas/MetricResource"
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Missing/invalid API key, or missing_team_scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "insufficient_permissions \u2014 the key lacks the required scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "409": {
                        "description": "**409** \u2014 this metric depends on the app's Shopify Partner integration, which isn't usable yet. `error.code` is one of: `partner_integration_not_connected` (no Partner API integration has ever been connected for this app), `partner_integration_unauthorized` (the stored Partner credentials were revoked or rejected \u2014 reconnect the integration in Ranksy), or `partner_integration_pending` (the first partner sync is still running \u2014 retry once it completes). Partner metrics keep returning 409 until the integration is connected and has synced at least once.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "validation_failed \u2014 bad query parameters.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limit exceeded. See the Retry-After header.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        },
                        "headers": {
                            "Retry-After": {
                                "description": "Seconds to wait before retrying.",
                                "schema": {
                                    "type": "integer"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/apps/{app}/metrics/installs": {
            "get": {
                "operationId": "v1.getMetric.installs",
                "description": "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.",
                "summary": "Installs",
                "tags": [
                    "Metrics"
                ],
                "parameters": [
                    {
                        "name": "app",
                        "in": "path",
                        "required": true,
                        "description": "The app ulid",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "date",
                        "in": "query",
                        "description": "Single as-of date \u2192 a snapshot for that date. Mutually exclusive\nwith start_date/end_date (which select a series); supplying both\nis a 422. Omit all three for the latest value.",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "start_date",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "end_date",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "granularity",
                        "in": "query",
                        "description": "Aggregation bucket size for a series response. 'day' is the\nnative PMD grain; week/month are rolled up by GetMetricForApi.",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "enum": [
                                "day",
                                "week",
                                "month"
                            ]
                        }
                    },
                    {
                        "name": "include_test",
                        "in": "query",
                        "schema": {
                            "type": [
                                "boolean",
                                "null"
                            ]
                        }
                    },
                    {
                        "name": "page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1
                        }
                    },
                    {
                        "name": "per_page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1,
                            "maximum": 200
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "`MetricSeriesCollection`\n\n`MetricResource`",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "anyOf": [
                                        {
                                            "$ref": "#/components/schemas/MetricSeriesCollection"
                                        },
                                        {
                                            "$ref": "#/components/schemas/MetricResource"
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Missing/invalid API key, or missing_team_scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "insufficient_permissions \u2014 the key lacks the required scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "409": {
                        "description": "**409** \u2014 this metric depends on the app's Shopify Partner integration, which isn't usable yet. `error.code` is one of: `partner_integration_not_connected` (no Partner API integration has ever been connected for this app), `partner_integration_unauthorized` (the stored Partner credentials were revoked or rejected \u2014 reconnect the integration in Ranksy), or `partner_integration_pending` (the first partner sync is still running \u2014 retry once it completes). Partner metrics keep returning 409 until the integration is connected and has synced at least once.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "validation_failed \u2014 bad query parameters.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limit exceeded. See the Retry-After header.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        },
                        "headers": {
                            "Retry-After": {
                                "description": "Seconds to wait before retrying.",
                                "schema": {
                                    "type": "integer"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/apps/{app}/metrics/uninstalls": {
            "get": {
                "operationId": "v1.getMetric.uninstalls",
                "description": "Daily app uninstalls. A **flow count**: a week/month bucket SUMS the daily uninstalls (dated to the bucket's last day); `day` keeps every row. No `components`, no currency.",
                "summary": "Uninstalls",
                "tags": [
                    "Metrics"
                ],
                "parameters": [
                    {
                        "name": "app",
                        "in": "path",
                        "required": true,
                        "description": "The app ulid",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "date",
                        "in": "query",
                        "description": "Single as-of date \u2192 a snapshot for that date. Mutually exclusive\nwith start_date/end_date (which select a series); supplying both\nis a 422. Omit all three for the latest value.",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "start_date",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "end_date",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "granularity",
                        "in": "query",
                        "description": "Aggregation bucket size for a series response. 'day' is the\nnative PMD grain; week/month are rolled up by GetMetricForApi.",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "enum": [
                                "day",
                                "week",
                                "month"
                            ]
                        }
                    },
                    {
                        "name": "include_test",
                        "in": "query",
                        "schema": {
                            "type": [
                                "boolean",
                                "null"
                            ]
                        }
                    },
                    {
                        "name": "page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1
                        }
                    },
                    {
                        "name": "per_page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1,
                            "maximum": 200
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "`MetricSeriesCollection`\n\n`MetricResource`",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "anyOf": [
                                        {
                                            "$ref": "#/components/schemas/MetricSeriesCollection"
                                        },
                                        {
                                            "$ref": "#/components/schemas/MetricResource"
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Missing/invalid API key, or missing_team_scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "insufficient_permissions \u2014 the key lacks the required scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "409": {
                        "description": "**409** \u2014 this metric depends on the app's Shopify Partner integration, which isn't usable yet. `error.code` is one of: `partner_integration_not_connected` (no Partner API integration has ever been connected for this app), `partner_integration_unauthorized` (the stored Partner credentials were revoked or rejected \u2014 reconnect the integration in Ranksy), or `partner_integration_pending` (the first partner sync is still running \u2014 retry once it completes). Partner metrics keep returning 409 until the integration is connected and has synced at least once.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "validation_failed \u2014 bad query parameters.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limit exceeded. See the Retry-After header.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        },
                        "headers": {
                            "Retry-After": {
                                "description": "Seconds to wait before retrying.",
                                "schema": {
                                    "type": "integer"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/apps/{app}/metrics/reactivations": {
            "get": {
                "operationId": "v1.getMetric.reactivations",
                "description": "Daily reinstalls by shops that had previously uninstalled. A **flow count**: a week/month bucket SUMS the daily values (dated to the bucket's last day); `day` keeps every row. No `components`, no currency.",
                "summary": "Reactivations",
                "tags": [
                    "Metrics"
                ],
                "parameters": [
                    {
                        "name": "app",
                        "in": "path",
                        "required": true,
                        "description": "The app ulid",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "date",
                        "in": "query",
                        "description": "Single as-of date \u2192 a snapshot for that date. Mutually exclusive\nwith start_date/end_date (which select a series); supplying both\nis a 422. Omit all three for the latest value.",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "start_date",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "end_date",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "granularity",
                        "in": "query",
                        "description": "Aggregation bucket size for a series response. 'day' is the\nnative PMD grain; week/month are rolled up by GetMetricForApi.",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "enum": [
                                "day",
                                "week",
                                "month"
                            ]
                        }
                    },
                    {
                        "name": "include_test",
                        "in": "query",
                        "schema": {
                            "type": [
                                "boolean",
                                "null"
                            ]
                        }
                    },
                    {
                        "name": "page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1
                        }
                    },
                    {
                        "name": "per_page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1,
                            "maximum": 200
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "`MetricSeriesCollection`\n\n`MetricResource`",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "anyOf": [
                                        {
                                            "$ref": "#/components/schemas/MetricSeriesCollection"
                                        },
                                        {
                                            "$ref": "#/components/schemas/MetricResource"
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Missing/invalid API key, or missing_team_scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "insufficient_permissions \u2014 the key lacks the required scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "409": {
                        "description": "**409** \u2014 this metric depends on the app's Shopify Partner integration, which isn't usable yet. `error.code` is one of: `partner_integration_not_connected` (no Partner API integration has ever been connected for this app), `partner_integration_unauthorized` (the stored Partner credentials were revoked or rejected \u2014 reconnect the integration in Ranksy), or `partner_integration_pending` (the first partner sync is still running \u2014 retry once it completes). Partner metrics keep returning 409 until the integration is connected and has synced at least once.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "validation_failed \u2014 bad query parameters.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limit exceeded. See the Retry-After header.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        },
                        "headers": {
                            "Retry-After": {
                                "description": "Seconds to wait before retrying.",
                                "schema": {
                                    "type": "integer"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/apps/{app}/metrics/churned_total": {
            "get": {
                "operationId": "v1.getMetric.churned_total",
                "description": "Count of distinct paying shops that churned in the trailing **30 days** as of each date \u2014 a rolling window, **not** a per-day count (`metadata.window` = `30d`).\n\nA *stock*: series buckets report the value as of the bucket's last day; **do not sum** across days. No `components`, no currency.",
                "summary": "Churned merchants (rolling 30d)",
                "tags": [
                    "Metrics"
                ],
                "parameters": [
                    {
                        "name": "app",
                        "in": "path",
                        "required": true,
                        "description": "The app ulid",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "date",
                        "in": "query",
                        "description": "Single as-of date \u2192 a snapshot for that date. Mutually exclusive\nwith start_date/end_date (which select a series); supplying both\nis a 422. Omit all three for the latest value.",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "start_date",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "end_date",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "granularity",
                        "in": "query",
                        "description": "Aggregation bucket size for a series response. 'day' is the\nnative PMD grain; week/month are rolled up by GetMetricForApi.",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "enum": [
                                "day",
                                "week",
                                "month"
                            ]
                        }
                    },
                    {
                        "name": "include_test",
                        "in": "query",
                        "schema": {
                            "type": [
                                "boolean",
                                "null"
                            ]
                        }
                    },
                    {
                        "name": "page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1
                        }
                    },
                    {
                        "name": "per_page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1,
                            "maximum": 200
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "`MetricSeriesCollection`\n\n`MetricResource`",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "anyOf": [
                                        {
                                            "$ref": "#/components/schemas/MetricSeriesCollection"
                                        },
                                        {
                                            "$ref": "#/components/schemas/MetricResource"
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Missing/invalid API key, or missing_team_scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "insufficient_permissions \u2014 the key lacks the required scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "409": {
                        "description": "**409** \u2014 this metric depends on the app's Shopify Partner integration, which isn't usable yet. `error.code` is one of: `partner_integration_not_connected` (no Partner API integration has ever been connected for this app), `partner_integration_unauthorized` (the stored Partner credentials were revoked or rejected \u2014 reconnect the integration in Ranksy), or `partner_integration_pending` (the first partner sync is still running \u2014 retry once it completes). Partner metrics keep returning 409 until the integration is connected and has synced at least once.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "validation_failed \u2014 bad query parameters.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limit exceeded. See the Retry-After header.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        },
                        "headers": {
                            "Retry-After": {
                                "description": "Seconds to wait before retrying.",
                                "schema": {
                                    "type": "integer"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/apps/{app}/metrics/churn_rate": {
            "get": {
                "operationId": "v1.getMetric.churn_rate",
                "description": "Rolling **logo churn** rate \u2014 the canonical \"real churn\" calc shared with the dashboard, frozen daily into a snapshot keyed on the Shopify event date (`metadata.computed` = `stored`). Value is a **fraction** (0.125 = 12.5%).\n\n- `window` = `7d` | `30d` (default) | `90d` | `365d` selects the rolling window.\n- `basis` = `real_churn` (the only basis in v1).\n- `components`: `{ customers_churned, customers_at_risk }` \u2014 present **only** for the default 30d window; other windows store the rate alone and omit `components`.\n- Overlapping windows are never summed: series buckets take the value as of the bucket's last day.\n\nReturns **400** `unsupported_basis` for any basis other than `real_churn`.",
                "summary": "Customer churn rate (rolling)",
                "tags": [
                    "Metrics"
                ],
                "parameters": [
                    {
                        "name": "app",
                        "in": "path",
                        "required": true,
                        "description": "The app ulid",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "date",
                        "in": "query",
                        "description": "Single as-of date \u2192 a snapshot for that date. Mutually exclusive\nwith start_date/end_date (which select a series); supplying both\nis a 422. Omit all three for the latest value.",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "start_date",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "end_date",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "granularity",
                        "in": "query",
                        "description": "Aggregation bucket size for a series response. 'day' is the\nnative PMD grain; week/month are rolled up by GetMetricForApi.",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "enum": [
                                "day",
                                "week",
                                "month"
                            ]
                        }
                    },
                    {
                        "name": "basis",
                        "in": "query",
                        "description": "Churn basis. v1 supports `real_churn` only (the default).",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "enum": [
                                "real_churn"
                            ],
                            "default": "real_churn"
                        }
                    },
                    {
                        "name": "window",
                        "in": "query",
                        "description": "Rolling window for the windowed rate metrics `churn_rate` and\n`revenue_churn_rate` (a frozen daily rolling snapshot); selects\nwhich stored PMD churn column to read. One of 7d, 30d, 90d, 365d;\ndefaults to 30d. Ignored by non-windowed metrics. Example: 90d.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "7d",
                                "30d",
                                "90d",
                                "365d"
                            ]
                        }
                    },
                    {
                        "name": "include_test",
                        "in": "query",
                        "schema": {
                            "type": [
                                "boolean",
                                "null"
                            ]
                        }
                    },
                    {
                        "name": "page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1
                        }
                    },
                    {
                        "name": "per_page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1,
                            "maximum": 200
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "`MetricSeriesCollection`\n\n`MetricResource`",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "anyOf": [
                                        {
                                            "$ref": "#/components/schemas/MetricSeriesCollection"
                                        },
                                        {
                                            "$ref": "#/components/schemas/MetricResource"
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "**400 `unsupported_basis`** \u2014 the `basis` query param was set to something other than `real_churn`, the only churn basis v1 supports. Omit `basis` (it defaults to `real_churn`) or pass `basis=real_churn`; anything else is rejected with `error.param` = `basis`. This is the only 400 this endpoint returns.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Missing/invalid API key, or missing_team_scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "insufficient_permissions \u2014 the key lacks the required scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "409": {
                        "description": "**409** \u2014 this metric depends on the app's Shopify Partner integration, which isn't usable yet. `error.code` is one of: `partner_integration_not_connected` (no Partner API integration has ever been connected for this app), `partner_integration_unauthorized` (the stored Partner credentials were revoked or rejected \u2014 reconnect the integration in Ranksy), or `partner_integration_pending` (the first partner sync is still running \u2014 retry once it completes). Partner metrics keep returning 409 until the integration is connected and has synced at least once.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "validation_failed \u2014 bad query parameters.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limit exceeded. See the Retry-After header.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        },
                        "headers": {
                            "Retry-After": {
                                "description": "Seconds to wait before retrying.",
                                "schema": {
                                    "type": "integer"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/apps/{app}/metrics/revenue_churn_rate": {
            "get": {
                "operationId": "v1.getMetric.revenue_churn_rate",
                "description": "Rolling **revenue (MRR) churn** rate, frozen daily and keyed on the Shopify event date (`metadata.computed` = `stored`). Value is a **fraction**.\n\n- `window` = `7d` | `30d` (default) | `90d` | `365d`.\n- `basis` = `real_churn` (the only basis in v1).\n- No `components` \u2014 revenue churn stores the rate only, for every window. Series buckets take the value as of the bucket's last day \u2014 never summed.\n\nReturns **400** `unsupported_basis` for any basis other than `real_churn`.",
                "summary": "Revenue churn rate (rolling)",
                "tags": [
                    "Metrics"
                ],
                "parameters": [
                    {
                        "name": "app",
                        "in": "path",
                        "required": true,
                        "description": "The app ulid",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "date",
                        "in": "query",
                        "description": "Single as-of date \u2192 a snapshot for that date. Mutually exclusive\nwith start_date/end_date (which select a series); supplying both\nis a 422. Omit all three for the latest value.",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "start_date",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "end_date",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "granularity",
                        "in": "query",
                        "description": "Aggregation bucket size for a series response. 'day' is the\nnative PMD grain; week/month are rolled up by GetMetricForApi.",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "enum": [
                                "day",
                                "week",
                                "month"
                            ]
                        }
                    },
                    {
                        "name": "basis",
                        "in": "query",
                        "description": "Churn basis. v1 supports `real_churn` only (the default).",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "enum": [
                                "real_churn"
                            ],
                            "default": "real_churn"
                        }
                    },
                    {
                        "name": "window",
                        "in": "query",
                        "description": "Rolling window for the windowed rate metrics `churn_rate` and\n`revenue_churn_rate` (a frozen daily rolling snapshot); selects\nwhich stored PMD churn column to read. One of 7d, 30d, 90d, 365d;\ndefaults to 30d. Ignored by non-windowed metrics. Example: 90d.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "7d",
                                "30d",
                                "90d",
                                "365d"
                            ]
                        }
                    },
                    {
                        "name": "include_test",
                        "in": "query",
                        "schema": {
                            "type": [
                                "boolean",
                                "null"
                            ]
                        }
                    },
                    {
                        "name": "page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1
                        }
                    },
                    {
                        "name": "per_page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1,
                            "maximum": 200
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "`MetricSeriesCollection`\n\n`MetricResource`",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "anyOf": [
                                        {
                                            "$ref": "#/components/schemas/MetricSeriesCollection"
                                        },
                                        {
                                            "$ref": "#/components/schemas/MetricResource"
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "**400 `unsupported_basis`** \u2014 the `basis` query param was set to something other than `real_churn`, the only churn basis v1 supports. Omit `basis` (it defaults to `real_churn`) or pass `basis=real_churn`; anything else is rejected with `error.param` = `basis`. This is the only 400 this endpoint returns.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Missing/invalid API key, or missing_team_scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "insufficient_permissions \u2014 the key lacks the required scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "409": {
                        "description": "**409** \u2014 this metric depends on the app's Shopify Partner integration, which isn't usable yet. `error.code` is one of: `partner_integration_not_connected` (no Partner API integration has ever been connected for this app), `partner_integration_unauthorized` (the stored Partner credentials were revoked or rejected \u2014 reconnect the integration in Ranksy), or `partner_integration_pending` (the first partner sync is still running \u2014 retry once it completes). Partner metrics keep returning 409 until the integration is connected and has synced at least once.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "validation_failed \u2014 bad query parameters.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limit exceeded. See the Retry-After header.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        },
                        "headers": {
                            "Retry-After": {
                                "description": "Seconds to wait before retrying.",
                                "schema": {
                                    "type": "integer"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/apps/{app}/installs": {
            "get": {
                "operationId": "v1.installs",
                "tags": [
                    "Installs"
                ],
                "parameters": [
                    {
                        "name": "app",
                        "in": "path",
                        "required": true,
                        "description": "The app ulid",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "start_date",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "end_date",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "group_by",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "enum": [
                                "source",
                                "keyword",
                                "category"
                            ]
                        }
                    },
                    {
                        "name": "page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1
                        }
                    },
                    {
                        "name": "per_page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1,
                            "maximum": 200
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Paginated set of `InstallBucketResource`",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/InstallsCollection"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Missing/invalid API key, or missing_team_scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "insufficient_permissions \u2014 the key lacks the required scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "409": {
                        "description": "The required integration (Shopify Partner or BigQuery/GA4) is not connected, unauthorized, or still initializing.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "validation_failed \u2014 bad query parameters.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limit exceeded. See the Retry-After header.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        },
                        "headers": {
                            "Retry-After": {
                                "description": "Seconds to wait before retrying.",
                                "schema": {
                                    "type": "integer"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/apps/{app}/keywords": {
            "get": {
                "operationId": "v1.keywords",
                "tags": [
                    "Keywords"
                ],
                "parameters": [
                    {
                        "name": "app",
                        "in": "path",
                        "required": true,
                        "description": "The app ulid",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "start_date",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "end_date",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "sort",
                        "in": "query",
                        "description": "Sort column. rank = best organic rank ascending; installs = BigQuery\ninstalls descending; keyword = alphabetical.",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "enum": [
                                "rank",
                                "installs",
                                "keyword"
                            ]
                        }
                    },
                    {
                        "name": "page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1
                        }
                    },
                    {
                        "name": "per_page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1,
                            "maximum": 200
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Paginated set of `KeywordPerformanceResource`",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/KeywordsCollection"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Missing/invalid API key, or missing_team_scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "insufficient_permissions \u2014 the key lacks the required scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "validation_failed \u2014 bad query parameters.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limit exceeded. See the Retry-After header.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        },
                        "headers": {
                            "Retry-After": {
                                "description": "Seconds to wait before retrying.",
                                "schema": {
                                    "type": "integer"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/apps/{app}/ltv/cohorts": {
            "get": {
                "operationId": "v1.ltvCohorts",
                "tags": [
                    "LtvCohorts"
                ],
                "parameters": [
                    {
                        "name": "app",
                        "in": "path",
                        "required": true,
                        "description": "The app ulid",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1
                        }
                    },
                    {
                        "name": "per_page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1,
                            "maximum": 100
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Paginated set of `LtvCohortResource`",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/LtvCohortsCollection"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Missing/invalid API key, or missing_team_scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "insufficient_permissions \u2014 the key lacks the required scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "validation_failed \u2014 bad query parameters.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limit exceeded. See the Retry-After header.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        },
                        "headers": {
                            "Retry-After": {
                                "description": "Seconds to wait before retrying.",
                                "schema": {
                                    "type": "integer"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/apps/{app}/rankings/history": {
            "get": {
                "operationId": "v1.rankingHistory",
                "tags": [
                    "RankingHistory"
                ],
                "parameters": [
                    {
                        "name": "app",
                        "in": "path",
                        "required": true,
                        "description": "The app ulid",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "type",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "category",
                                "keyword"
                            ]
                        }
                    },
                    {
                        "name": "name",
                        "in": "query",
                        "description": "`name` is the keyword string, or \u2014 for type=category \u2014 the category\nname. Required unless a `category` slug is supplied for a category.",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "maxLength": 255
                        }
                    },
                    {
                        "name": "category",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "maxLength": 255
                        }
                    },
                    {
                        "name": "days",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1,
                            "maximum": 90
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Paginated set of `RankingHistoryPointResource`",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/RankingHistoryCollection"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Missing/invalid API key, or missing_team_scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "insufficient_permissions \u2014 the key lacks the required scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "resource_not_found \u2014 the addressed app / category / keyword does not exist or is not tracked.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "validation_failed \u2014 bad query parameters.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limit exceeded. See the Retry-After header.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        },
                        "headers": {
                            "Retry-After": {
                                "description": "Seconds to wait before retrying.",
                                "schema": {
                                    "type": "integer"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/apps/{app}/rankings": {
            "get": {
                "operationId": "v1.rankings",
                "tags": [
                    "Rankings"
                ],
                "parameters": [
                    {
                        "name": "app",
                        "in": "path",
                        "required": true,
                        "description": "The app ulid",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "type",
                        "in": "query",
                        "description": "Which ranking surface to return. all = both; keywords/categories\nnarrow to one. Mirrors AppStore\\GetAppRankings.",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "enum": [
                                "all",
                                "keywords",
                                "categories"
                            ]
                        }
                    },
                    {
                        "name": "limit",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1,
                            "maximum": 50
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Paginated set of `RankingRowResource`",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/RankingsCollection"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Missing/invalid API key, or missing_team_scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "insufficient_permissions \u2014 the key lacks the required scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "validation_failed \u2014 bad query parameters.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limit exceeded. See the Retry-After header.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        },
                        "headers": {
                            "Retry-After": {
                                "description": "Seconds to wait before retrying.",
                                "schema": {
                                    "type": "integer"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/apps/{app}/reviews": {
            "get": {
                "operationId": "v1.reviews",
                "tags": [
                    "Reviews"
                ],
                "parameters": [
                    {
                        "name": "app",
                        "in": "path",
                        "required": true,
                        "description": "The app ulid",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "rating",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1,
                            "maximum": 5
                        }
                    },
                    {
                        "name": "has_reply",
                        "in": "query",
                        "schema": {
                            "type": [
                                "boolean",
                                "null"
                            ]
                        }
                    },
                    {
                        "name": "start_date",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "end_date",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "sort",
                        "in": "query",
                        "description": "Whitelist guards orderBy(): only these tokens are accepted, each\nmapped to a real column in sortColumn(). Anything else \u2192 422.",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "enum": [
                                "date",
                                "rating"
                            ]
                        }
                    },
                    {
                        "name": "order",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "enum": [
                                "asc",
                                "desc"
                            ]
                        }
                    },
                    {
                        "name": "page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1
                        }
                    },
                    {
                        "name": "per_page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1,
                            "maximum": 100
                        }
                    },
                    {
                        "name": "include_archived",
                        "in": "query",
                        "description": "RAN-662: opt-in to also receive archived reviews as a separate set.",
                        "schema": {
                            "type": [
                                "boolean",
                                "null"
                            ]
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "`ReviewsCollection`",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ReviewsCollection"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Missing/invalid API key, or missing_team_scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "insufficient_permissions \u2014 the key lacks the required scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "validation_failed \u2014 bad query parameters.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limit exceeded. See the Retry-After header.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        },
                        "headers": {
                            "Retry-After": {
                                "description": "Seconds to wait before retrying.",
                                "schema": {
                                    "type": "integer"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/apps/{app}/scorecard": {
            "get": {
                "operationId": "v1.scorecard",
                "tags": [
                    "Scorecard"
                ],
                "parameters": [
                    {
                        "name": "app",
                        "in": "path",
                        "required": true,
                        "description": "The app ulid",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "refresh",
                        "in": "query",
                        "schema": {
                            "type": [
                                "boolean",
                                "null"
                            ]
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "`ScorecardResource`",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ScorecardResource"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Missing/invalid API key, or missing_team_scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "insufficient_permissions \u2014 the key lacks the required scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "resource_not_found \u2014 the addressed app / category / keyword does not exist or is not tracked.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "validation_failed \u2014 bad query parameters.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limit exceeded. See the Retry-After header.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        },
                        "headers": {
                            "Retry-After": {
                                "description": "Seconds to wait before retrying.",
                                "schema": {
                                    "type": "integer"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/shopify/apps": {
            "get": {
                "operationId": "v1.shopify.apps",
                "tags": [
                    "ShopifyAppsCatalog"
                ],
                "parameters": [
                    {
                        "name": "page",
                        "in": "query",
                        "schema": {
                            "type": "integer",
                            "minimum": 1
                        }
                    },
                    {
                        "name": "per_page",
                        "in": "query",
                        "schema": {
                            "type": "integer",
                            "minimum": 1,
                            "maximum": 1000
                        }
                    },
                    {
                        "name": "state",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "Active",
                                "Delisted",
                                "Deleted"
                            ]
                        }
                    },
                    {
                        "name": "category",
                        "in": "query",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "min_installs",
                        "in": "query",
                        "schema": {
                            "type": "integer",
                            "minimum": 0
                        }
                    },
                    {
                        "name": "updated_since",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "format": "date-time"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/ShopifyAppCatalogResource"
                                            }
                                        },
                                        "meta": {
                                            "type": "object",
                                            "properties": {
                                                "total": {
                                                    "type": "integer"
                                                },
                                                "current_page": {
                                                    "type": "integer"
                                                },
                                                "last_page": {
                                                    "type": "integer"
                                                },
                                                "per_page": {
                                                    "type": "integer"
                                                }
                                            },
                                            "required": [
                                                "total",
                                                "current_page",
                                                "last_page",
                                                "per_page"
                                            ]
                                        }
                                    },
                                    "required": [
                                        "data",
                                        "meta"
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Missing/invalid API key, or missing_team_scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "insufficient_permissions \u2014 the key lacks the required scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "validation_failed \u2014 bad query parameters.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limit exceeded. See the Retry-After header.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        },
                        "headers": {
                            "Retry-After": {
                                "description": "Seconds to wait before retrying.",
                                "schema": {
                                    "type": "integer"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/apps/{app}/subscriptions": {
            "get": {
                "operationId": "v1.subscriptions",
                "tags": [
                    "Subscriptions"
                ],
                "parameters": [
                    {
                        "name": "app",
                        "in": "path",
                        "required": true,
                        "description": "The app ulid",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "status",
                        "in": "query",
                        "description": "Partner subscription status as stored (lower-cased forms accepted).",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "enum": [
                                "active",
                                "cancelled",
                                "declined",
                                "expired",
                                "frozen"
                            ]
                        }
                    },
                    {
                        "name": "include_test",
                        "in": "query",
                        "schema": {
                            "type": [
                                "boolean",
                                "null"
                            ]
                        }
                    },
                    {
                        "name": "sort",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "enum": [
                                "activated_at",
                                "cancelled_at",
                                "created_at",
                                "amount"
                            ]
                        }
                    },
                    {
                        "name": "order",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "enum": [
                                "asc",
                                "desc"
                            ]
                        }
                    },
                    {
                        "name": "page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1
                        }
                    },
                    {
                        "name": "per_page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1,
                            "maximum": 100
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "`SubscriptionsCollection`",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/SubscriptionsCollection"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Missing/invalid API key, or missing_team_scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "insufficient_permissions \u2014 the key lacks the required scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "validation_failed \u2014 bad query parameters.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limit exceeded. See the Retry-After header.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        },
                        "headers": {
                            "Retry-After": {
                                "description": "Seconds to wait before retrying.",
                                "schema": {
                                    "type": "integer"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/apps/{app}/traffic/keywords": {
            "get": {
                "operationId": "v1.trafficKeywords",
                "tags": [
                    "TrafficKeywords"
                ],
                "parameters": [
                    {
                        "name": "app",
                        "in": "path",
                        "required": true,
                        "description": "The app ulid",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "start_date",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "end_date",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "filter[keyword]",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "maxLength": 100
                        }
                    },
                    {
                        "name": "sort",
                        "in": "query",
                        "description": "Sort column (always descending, matching the underlying action).",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "enum": [
                                "total_installs",
                                "organic_installs",
                                "ad_installs"
                            ]
                        }
                    },
                    {
                        "name": "page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1
                        }
                    },
                    {
                        "name": "per_page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1,
                            "maximum": 200
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Paginated set of `TrafficKeywordResource`",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/TrafficKeywordsCollection"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Missing/invalid API key, or missing_team_scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "insufficient_permissions \u2014 the key lacks the required scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "409": {
                        "description": "The required integration (Shopify Partner or BigQuery/GA4) is not connected, unauthorized, or still initializing.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "validation_failed \u2014 bad query parameters.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limit exceeded. See the Retry-After header.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        },
                        "headers": {
                            "Retry-After": {
                                "description": "Seconds to wait before retrying.",
                                "schema": {
                                    "type": "integer"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/apps/{app}/traffic/sources": {
            "get": {
                "operationId": "v1.trafficSources",
                "tags": [
                    "TrafficSources"
                ],
                "parameters": [
                    {
                        "name": "app",
                        "in": "path",
                        "required": true,
                        "description": "The app ulid",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "start_date",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "end_date",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "granularity",
                        "in": "query",
                        "description": "BigQuery traffic is aggregated into fixed-length periods; the\nunderlying action supports 7-day (week) or 14-day (biweekly).",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "enum": [
                                "week",
                                "biweekly"
                            ]
                        }
                    },
                    {
                        "name": "page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1
                        }
                    },
                    {
                        "name": "per_page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1,
                            "maximum": 200
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Paginated set of `TrafficSourcePointResource`",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/TrafficSourcesCollection"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Missing/invalid API key, or missing_team_scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "insufficient_permissions \u2014 the key lacks the required scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "409": {
                        "description": "The required integration (Shopify Partner or BigQuery/GA4) is not connected, unauthorized, or still initializing.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "validation_failed \u2014 bad query parameters.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limit exceeded. See the Retry-After header.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        },
                        "headers": {
                            "Retry-After": {
                                "description": "Seconds to wait before retrying.",
                                "schema": {
                                    "type": "integer"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/apps/{app}/transactions": {
            "get": {
                "operationId": "v1.transactions",
                "tags": [
                    "Transactions"
                ],
                "parameters": [
                    {
                        "name": "app",
                        "in": "path",
                        "required": true,
                        "description": "The app ulid",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "type",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "enum": [
                                "APP_SUBSCRIPTION_SALE",
                                "APP_USAGE_SALE",
                                "APP_ONE_TIME_SALE",
                                "APP_SALE_ADJUSTMENT",
                                "APP_SALE_CREDIT",
                                "REFERRAL_TRANSACTION",
                                "APP_REFUND"
                            ]
                        }
                    },
                    {
                        "name": "include_test",
                        "in": "query",
                        "schema": {
                            "type": [
                                "boolean",
                                "null"
                            ]
                        }
                    },
                    {
                        "name": "start_date",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "end_date",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "sort",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "enum": [
                                "processed_at",
                                "created_at",
                                "gross_amount",
                                "net_amount"
                            ]
                        }
                    },
                    {
                        "name": "order",
                        "in": "query",
                        "schema": {
                            "type": [
                                "string",
                                "null"
                            ],
                            "enum": [
                                "asc",
                                "desc"
                            ]
                        }
                    },
                    {
                        "name": "page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1
                        }
                    },
                    {
                        "name": "per_page",
                        "in": "query",
                        "schema": {
                            "type": [
                                "integer",
                                "null"
                            ],
                            "minimum": 1,
                            "maximum": 100
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "`TransactionsCollection`",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/TransactionsCollection"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Missing/invalid API key, or missing_team_scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "insufficient_permissions \u2014 the key lacks the required scope.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "validation_failed \u2014 bad query parameters.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Rate limit exceeded. See the Retry-After header.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        },
                        "headers": {
                            "Retry-After": {
                                "description": "Seconds to wait before retrying.",
                                "schema": {
                                    "type": "integer"
                                }
                            }
                        }
                    }
                }
            }
        }
    },
    "components": {
        "securitySchemes": {
            "bearerAuth": {
                "type": "http",
                "description": "Authenticate with your Ranksy API key as a bearer token: `Authorization: Bearer rk_live_...` (use an `rk_test_...` key against test data). Manage keys in your Ranksy dashboard.",
                "scheme": "bearer"
            }
        },
        "schemas": {
            "AppDetailResource": {
                "type": "object",
                "properties": {
                    "object": {
                        "type": "string",
                        "description": "Discriminator for this object type; always \"app\".",
                        "examples": [
                            "app"
                        ]
                    },
                    "ulid": {
                        "type": "string",
                        "description": "The app's ULID \u2014 the stable public identifier used as {app} in\nother endpoints.",
                        "examples": [
                            "01HZX9ABCDEF0123456789ABCD"
                        ]
                    },
                    "slug": {
                        "type": "string",
                        "description": "The app's URL slug within the team.",
                        "examples": [
                            "my-app"
                        ]
                    },
                    "name": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "App name from its App Store listing, or null when the listing has\nnot been scraped yet.",
                        "examples": [
                            "My App"
                        ]
                    },
                    "listing": {
                        "type": [
                            "object",
                            "null"
                        ],
                        "description": "App Store listing facts (incl. subtitle/introduction), or null\nwhen the app has no scraped listing.",
                        "properties": {
                            "rating": {
                                "type": [
                                    "number",
                                    "null"
                                ]
                            },
                            "reviews_count": {
                                "type": "integer"
                            },
                            "built_for_shopify": {
                                "type": "boolean"
                            },
                            "status": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            },
                            "developer": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            },
                            "launched_at": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            },
                            "url": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            },
                            "subtitle": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            },
                            "introduction": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            }
                        },
                        "required": [
                            "rating",
                            "reviews_count",
                            "built_for_shopify",
                            "status",
                            "developer",
                            "launched_at",
                            "url",
                            "subtitle",
                            "introduction"
                        ]
                    },
                    "categories": {
                        "type": "array",
                        "description": "App Store categories the app is listed in; empty array when none.",
                        "items": {
                            "type": "object",
                            "properties": {
                                "slug": {
                                    "type": "string"
                                },
                                "name": {
                                    "type": "string"
                                }
                            },
                            "required": [
                                "slug",
                                "name"
                            ]
                        }
                    },
                    "integrations": {
                        "type": "object",
                        "description": "Which data integrations are connected for this app.",
                        "properties": {
                            "partner_api": {
                                "type": "boolean"
                            },
                            "analytics": {
                                "type": "boolean"
                            },
                            "app_store": {
                                "type": "boolean"
                            }
                        },
                        "required": [
                            "partner_api",
                            "analytics",
                            "app_store"
                        ]
                    },
                    "last_synced": {
                        "type": "object",
                        "description": "Last successful sync timestamps (ISO 8601) per integration.",
                        "properties": {
                            "partner_api": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            },
                            "analytics": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            }
                        },
                        "required": [
                            "partner_api",
                            "analytics"
                        ]
                    },
                    "metrics": {
                        "type": [
                            "object",
                            "null"
                        ],
                        "description": "Latest daily Partner metrics snapshot, or null when the app has\nno Partner integration or no daily rows yet.",
                        "properties": {
                            "date": {
                                "type": "string"
                            },
                            "mrr": {
                                "type": "number"
                            },
                            "gross_revenue": {
                                "type": "number"
                            },
                            "net_revenue": {
                                "type": "number"
                            },
                            "installs": {
                                "type": "integer"
                            },
                            "uninstalls": {
                                "type": "integer"
                            },
                            "active_merchants": {
                                "type": "integer"
                            },
                            "active_subscriptions": {
                                "type": "integer"
                            },
                            "paying_customers": {
                                "type": "integer"
                            },
                            "churn_rate": {
                                "type": "number"
                            },
                            "active_installs": {
                                "type": "integer"
                            },
                            "active_installs_real": {
                                "type": "integer"
                            }
                        },
                        "required": [
                            "date",
                            "mrr",
                            "gross_revenue",
                            "net_revenue",
                            "installs",
                            "uninstalls",
                            "active_merchants",
                            "active_subscriptions",
                            "paying_customers",
                            "churn_rate",
                            "active_installs",
                            "active_installs_real"
                        ]
                    },
                    "partner_sync": {
                        "type": [
                            "object",
                            "null"
                        ],
                        "description": "Partner-sync health block, or null when no Partner sync data is\navailable. Keys are present only when their value is known.",
                        "properties": {
                            "partner_sync_status": {
                                "type": "string"
                            },
                            "partner_sync_last_complete_at": {
                                "type": "string"
                            },
                            "partner_sync_last_error_at": {
                                "type": "string"
                            },
                            "partner_sync_error_reason": {
                                "type": "string"
                            }
                        }
                    }
                },
                "required": [
                    "object",
                    "ulid",
                    "slug",
                    "name",
                    "listing",
                    "categories",
                    "integrations",
                    "last_synced",
                    "metrics",
                    "partner_sync"
                ],
                "title": "AppDetailResource"
            },
            "AppResource": {
                "type": "object",
                "properties": {
                    "object": {
                        "type": "string",
                        "description": "Discriminator for this object type; always \"app\".",
                        "examples": [
                            "app"
                        ]
                    },
                    "ulid": {
                        "type": "string",
                        "description": "The app's ULID \u2014 the stable public identifier used as {app} in\nother endpoints.",
                        "examples": [
                            "01HZX9ABCDEF0123456789ABCD"
                        ]
                    },
                    "slug": {
                        "type": "string",
                        "description": "The app's URL slug within the team.",
                        "examples": [
                            "my-app"
                        ]
                    },
                    "name": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "App name from its App Store listing, or null when the listing has\nnot been scraped yet.",
                        "examples": [
                            "My App"
                        ]
                    },
                    "listing": {
                        "type": [
                            "object",
                            "null"
                        ],
                        "description": "App Store listing facts, or null when the app has no scraped\nlisting.",
                        "properties": {
                            "rating": {
                                "type": [
                                    "number",
                                    "null"
                                ]
                            },
                            "reviews_count": {
                                "type": "integer"
                            },
                            "built_for_shopify": {
                                "type": "boolean"
                            },
                            "status": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            },
                            "developer": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            },
                            "launched_at": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            },
                            "url": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            }
                        },
                        "required": [
                            "rating",
                            "reviews_count",
                            "built_for_shopify",
                            "status",
                            "developer",
                            "launched_at",
                            "url"
                        ]
                    },
                    "integrations": {
                        "type": "object",
                        "description": "Which data integrations are connected for this app.",
                        "properties": {
                            "partner_api": {
                                "type": "boolean"
                            },
                            "analytics": {
                                "type": "boolean"
                            },
                            "app_store": {
                                "type": "boolean"
                            }
                        },
                        "required": [
                            "partner_api",
                            "analytics",
                            "app_store"
                        ]
                    },
                    "last_synced": {
                        "type": "object",
                        "description": "Last successful sync timestamps (ISO 8601) per integration.",
                        "properties": {
                            "partner_api": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            },
                            "analytics": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            }
                        },
                        "required": [
                            "partner_api",
                            "analytics"
                        ]
                    }
                },
                "required": [
                    "object",
                    "ulid",
                    "slug",
                    "name",
                    "listing",
                    "integrations",
                    "last_synced"
                ],
                "title": "AppResource"
            },
            "AppsCollection": {
                "type": "object",
                "properties": {
                    "object": {
                        "type": "string",
                        "description": "Always the literal string `list` \u2014 the envelope-type discriminator.",
                        "const": "list",
                        "examples": [
                            "list"
                        ]
                    },
                    "url": {
                        "type": "string",
                        "description": "Path of this list resource.",
                        "examples": [
                            "/api/v1/apps/01JN4HKQX0000000000000000/reviews"
                        ]
                    },
                    "currency": {
                        "type": "string",
                        "description": "Base-currency ISO code (ISO 4217), present only on money series and\ndeclared once for every row in data.",
                        "examples": [
                            "USD"
                        ]
                    },
                    "page": {
                        "type": "integer",
                        "description": "Current page number (1-based).",
                        "examples": [
                            1
                        ]
                    },
                    "per_page": {
                        "type": "integer",
                        "description": "Rows per page.",
                        "examples": [
                            50
                        ]
                    },
                    "total_count": {
                        "type": "integer",
                        "description": "Total rows across every page.",
                        "examples": [
                            128
                        ]
                    },
                    "has_more": {
                        "type": "boolean",
                        "description": "Whether more pages follow this one.",
                        "examples": [
                            true
                        ]
                    },
                    "coverage": {
                        "type": "object",
                        "description": "Requested vs actually-covered date window for the series. Present on\ndate-windowed series only. `requested` echoes the asked-for range;\n`available` is the range actually covered by data, or null when\nnothing fell in range.",
                        "examples": [
                            {
                                "requested": {
                                    "start": "2026-05-01",
                                    "end": "2026-05-31"
                                },
                                "available": {
                                    "start": "2026-05-01",
                                    "end": "2026-05-28"
                                }
                            }
                        ],
                        "properties": {
                            "requested": {
                                "type": "object",
                                "properties": {
                                    "start": {
                                        "type": "string"
                                    },
                                    "end": {
                                        "type": "string"
                                    }
                                },
                                "required": [
                                    "start",
                                    "end"
                                ]
                            },
                            "available": {
                                "type": [
                                    "object",
                                    "null"
                                ],
                                "properties": {
                                    "start": {
                                        "type": "string"
                                    },
                                    "end": {
                                        "type": "string"
                                    }
                                },
                                "required": [
                                    "start",
                                    "end"
                                ]
                            }
                        },
                        "required": [
                            "requested",
                            "available"
                        ]
                    },
                    "metadata": {
                        "type": "object",
                        "description": "Endpoint-specific metadata \u2014 e.g. summary, echoed filters, or\nintegration sync status. Shape varies by endpoint.",
                        "examples": [
                            {
                                "partner_sync_status": "complete"
                            }
                        ],
                        "additionalProperties": {}
                    },
                    "data": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/AppResource"
                        }
                    }
                },
                "required": [
                    "object",
                    "url",
                    "page",
                    "per_page",
                    "total_count",
                    "has_more",
                    "data"
                ],
                "title": "AppsCollection"
            },
            "CategoryRankingRowResource": {
                "type": "object",
                "properties": {
                    "rank": {
                        "type": "integer",
                        "description": "The app's scraped rank within this category for the latest data date.",
                        "examples": [
                            3
                        ]
                    },
                    "change": {
                        "type": "integer",
                        "description": "Rank movement vs the previous scrape (positive = improved toward #1);\n0 when there is no prior data point.",
                        "examples": [
                            1
                        ]
                    },
                    "app": {
                        "type": "object",
                        "description": "Card for the ranked app.",
                        "examples": [
                            {
                                "slug": "acme-reviews",
                                "name": "Acme Reviews",
                                "rating": 4.9,
                                "reviews_count": 1284,
                                "developer": "Acme Labs",
                                "built_for_shopify": true
                            }
                        ],
                        "properties": {
                            "slug": {
                                "type": "string"
                            },
                            "name": {
                                "type": "string"
                            },
                            "rating": {
                                "type": [
                                    "number",
                                    "null"
                                ]
                            },
                            "reviews_count": {
                                "type": "integer"
                            },
                            "developer": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            },
                            "built_for_shopify": {
                                "type": "boolean"
                            }
                        },
                        "required": [
                            "slug",
                            "name",
                            "rating",
                            "reviews_count",
                            "developer",
                            "built_for_shopify"
                        ]
                    }
                },
                "required": [
                    "rank",
                    "change",
                    "app"
                ],
                "title": "CategoryRankingRowResource"
            },
            "CategoryRankingsCollection": {
                "type": "object",
                "properties": {
                    "object": {
                        "type": "string",
                        "description": "Always the literal string `list` \u2014 the envelope-type discriminator.",
                        "const": "list",
                        "examples": [
                            "list"
                        ]
                    },
                    "url": {
                        "type": "string",
                        "description": "Path of this list resource.",
                        "examples": [
                            "/api/v1/apps/01JN4HKQX0000000000000000/reviews"
                        ]
                    },
                    "currency": {
                        "type": "string",
                        "description": "Base-currency ISO code (ISO 4217), present only on money series and\ndeclared once for every row in data.",
                        "examples": [
                            "USD"
                        ]
                    },
                    "page": {
                        "type": "integer",
                        "description": "Current page number (1-based).",
                        "examples": [
                            1
                        ]
                    },
                    "per_page": {
                        "type": "integer",
                        "description": "Rows per page.",
                        "examples": [
                            50
                        ]
                    },
                    "total_count": {
                        "type": "integer",
                        "description": "Total rows across every page.",
                        "examples": [
                            128
                        ]
                    },
                    "has_more": {
                        "type": "boolean",
                        "description": "Whether more pages follow this one.",
                        "examples": [
                            true
                        ]
                    },
                    "coverage": {
                        "type": "object",
                        "description": "Requested vs actually-covered date window for the series. Present on\ndate-windowed series only. `requested` echoes the asked-for range;\n`available` is the range actually covered by data, or null when\nnothing fell in range.",
                        "examples": [
                            {
                                "requested": {
                                    "start": "2026-05-01",
                                    "end": "2026-05-31"
                                },
                                "available": {
                                    "start": "2026-05-01",
                                    "end": "2026-05-28"
                                }
                            }
                        ],
                        "properties": {
                            "requested": {
                                "type": "object",
                                "properties": {
                                    "start": {
                                        "type": "string"
                                    },
                                    "end": {
                                        "type": "string"
                                    }
                                },
                                "required": [
                                    "start",
                                    "end"
                                ]
                            },
                            "available": {
                                "type": [
                                    "object",
                                    "null"
                                ],
                                "properties": {
                                    "start": {
                                        "type": "string"
                                    },
                                    "end": {
                                        "type": "string"
                                    }
                                },
                                "required": [
                                    "start",
                                    "end"
                                ]
                            }
                        },
                        "required": [
                            "requested",
                            "available"
                        ]
                    },
                    "metadata": {
                        "type": "object",
                        "description": "Endpoint-specific metadata \u2014 e.g. summary, echoed filters, or\nintegration sync status. Shape varies by endpoint.",
                        "examples": [
                            {
                                "partner_sync_status": "complete"
                            }
                        ],
                        "additionalProperties": {}
                    },
                    "data": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/CategoryRankingRowResource"
                        }
                    }
                },
                "required": [
                    "object",
                    "url",
                    "page",
                    "per_page",
                    "total_count",
                    "has_more",
                    "data"
                ],
                "title": "CategoryRankingsCollection"
            },
            "CategoryResource": {
                "type": "array",
                "items": {},
                "title": "CategoryResource"
            },
            "CompetitorResource": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "Internal ShopifyApp id of the competitor.",
                        "examples": [
                            4471
                        ]
                    },
                    "slug": {
                        "type": "string",
                        "description": "App Store slug (handle) of the competitor.",
                        "examples": [
                            "stocky"
                        ]
                    },
                    "name": {
                        "type": "string",
                        "description": "Competitor app name.",
                        "examples": [
                            "Stocky"
                        ]
                    },
                    "rating": {
                        "type": [
                            "number",
                            "null"
                        ],
                        "description": "Average star rating (rounded to 1 dp), or null when unrated.",
                        "examples": [
                            4.5
                        ]
                    },
                    "reviews_count": {
                        "type": [
                            "integer",
                            "null"
                        ],
                        "description": "Total number of reviews.",
                        "examples": [
                            540
                        ]
                    },
                    "est_installs": {
                        "type": [
                            "integer",
                            "null"
                        ],
                        "description": "Estimated active installs, or null when not estimated.",
                        "examples": [
                            9100
                        ]
                    },
                    "logo_url": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Competitor app icon URL, or null when not captured.",
                        "examples": [
                            "https://cdn.shopify.com/app-store/listing/stocky/icon.png"
                        ]
                    },
                    "shared_categories": {
                        "type": [
                            "integer",
                            "null"
                        ],
                        "description": "Number of catalog categories shared with the team's own app; null\nwhen the competitor is not one of the team app's catalog-competitors.",
                        "examples": [
                            3
                        ]
                    },
                    "shared_keywords": {
                        "type": [
                            "integer",
                            "null"
                        ],
                        "description": "Number of keywords both apps rank for; null when not a\ncatalog-competitor.",
                        "examples": [
                            27
                        ]
                    },
                    "relevance_score": {
                        "type": [
                            "integer",
                            "null"
                        ],
                        "description": "Catalog relevance score (higher = more similar); null when not a\ncatalog-competitor. Rows with a null score sort last on relevance.",
                        "examples": [
                            84
                        ]
                    },
                    "category_avg_rank": {
                        "type": [
                            "number",
                            "null"
                        ],
                        "description": "Competitor's average rank across the shared categories (1 dp); null\nwhen not a catalog-competitor.",
                        "examples": [
                            6.4
                        ]
                    },
                    "keyword_avg_rank": {
                        "type": [
                            "number",
                            "null"
                        ],
                        "description": "Competitor's average rank across the shared keywords (1 dp); null\nwhen not a catalog-competitor.",
                        "examples": [
                            9.1
                        ]
                    }
                },
                "required": [
                    "id",
                    "slug",
                    "name",
                    "rating",
                    "reviews_count",
                    "est_installs",
                    "logo_url",
                    "shared_categories",
                    "shared_keywords",
                    "relevance_score",
                    "category_avg_rank",
                    "keyword_avg_rank"
                ],
                "title": "CompetitorResource"
            },
            "CompetitorsCollection": {
                "type": "object",
                "properties": {
                    "object": {
                        "type": "string",
                        "description": "Always the literal string `list` \u2014 the envelope-type discriminator.",
                        "const": "list",
                        "examples": [
                            "list"
                        ]
                    },
                    "url": {
                        "type": "string",
                        "description": "Path of this list resource.",
                        "examples": [
                            "/api/v1/apps/01JN4HKQX0000000000000000/reviews"
                        ]
                    },
                    "currency": {
                        "type": "string",
                        "description": "Base-currency ISO code (ISO 4217), present only on money series and\ndeclared once for every row in data.",
                        "examples": [
                            "USD"
                        ]
                    },
                    "page": {
                        "type": "integer",
                        "description": "Current page number (1-based).",
                        "examples": [
                            1
                        ]
                    },
                    "per_page": {
                        "type": "integer",
                        "description": "Rows per page.",
                        "examples": [
                            50
                        ]
                    },
                    "total_count": {
                        "type": "integer",
                        "description": "Total rows across every page.",
                        "examples": [
                            128
                        ]
                    },
                    "has_more": {
                        "type": "boolean",
                        "description": "Whether more pages follow this one.",
                        "examples": [
                            true
                        ]
                    },
                    "coverage": {
                        "type": "object",
                        "description": "Requested vs actually-covered date window for the series. Present on\ndate-windowed series only. `requested` echoes the asked-for range;\n`available` is the range actually covered by data, or null when\nnothing fell in range.",
                        "examples": [
                            {
                                "requested": {
                                    "start": "2026-05-01",
                                    "end": "2026-05-31"
                                },
                                "available": {
                                    "start": "2026-05-01",
                                    "end": "2026-05-28"
                                }
                            }
                        ],
                        "properties": {
                            "requested": {
                                "type": "object",
                                "properties": {
                                    "start": {
                                        "type": "string"
                                    },
                                    "end": {
                                        "type": "string"
                                    }
                                },
                                "required": [
                                    "start",
                                    "end"
                                ]
                            },
                            "available": {
                                "type": [
                                    "object",
                                    "null"
                                ],
                                "properties": {
                                    "start": {
                                        "type": "string"
                                    },
                                    "end": {
                                        "type": "string"
                                    }
                                },
                                "required": [
                                    "start",
                                    "end"
                                ]
                            }
                        },
                        "required": [
                            "requested",
                            "available"
                        ]
                    },
                    "metadata": {
                        "type": "object",
                        "description": "Endpoint-specific metadata \u2014 e.g. summary, echoed filters, or\nintegration sync status. Shape varies by endpoint.",
                        "examples": [
                            {
                                "partner_sync_status": "complete"
                            }
                        ],
                        "additionalProperties": {}
                    },
                    "data": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/CompetitorResource"
                        }
                    }
                },
                "required": [
                    "object",
                    "url",
                    "page",
                    "per_page",
                    "total_count",
                    "has_more",
                    "data"
                ],
                "title": "CompetitorsCollection"
            },
            "Error": {
                "type": "object",
                "properties": {
                    "error": {
                        "type": "object",
                        "description": "The error envelope; always present on a 4xx/5xx response.",
                        "properties": {
                            "type": {
                                "type": "string",
                                "description": "Broad error category (Stripe-shaped).",
                                "enum": [
                                    "invalid_request_error",
                                    "authentication_error",
                                    "permission_error",
                                    "integration_error"
                                ],
                                "example": "invalid_request_error"
                            },
                            "code": {
                                "type": "string",
                                "description": "Machine-readable error code; stable identifier to branch on.",
                                "enum": [
                                    "validation_failed",
                                    "unknown_metric",
                                    "unsupported_basis",
                                    "missing_team_scope",
                                    "insufficient_permissions",
                                    "resource_not_found",
                                    "partner_integration_not_connected",
                                    "partner_integration_unauthorized",
                                    "partner_integration_pending",
                                    "bigquery_integration_not_connected",
                                    "bigquery_integration_unauthorized",
                                    "bigquery_integration_pending"
                                ],
                                "example": "validation_failed"
                            },
                            "message": {
                                "type": "string",
                                "description": "Human-readable explanation of what went wrong.",
                                "example": "The start_date parameter must be a valid date."
                            },
                            "param": {
                                "type": "string",
                                "description": "Present on validation / resource errors: the offending query parameter.",
                                "example": "start_date"
                            },
                            "doc_url": {
                                "type": "string",
                                "format": "uri",
                                "description": "Link to the documentation page for this error code.",
                                "example": "https://api.ranksyapp.com/errors/validation_failed"
                            }
                        },
                        "required": [
                            "type",
                            "code",
                            "message",
                            "doc_url"
                        ]
                    }
                },
                "required": [
                    "error"
                ],
                "title": "Error"
            },
            "InstallBucketResource": {
                "anyOf": [
                    {
                        "type": "object",
                        "properties": {
                            "keyword": {
                                "type": "string",
                                "description": "(group_by=keyword) The search keyword for this bucket.",
                                "examples": [
                                    "inventory sync"
                                ]
                            },
                            "views": {
                                "type": "integer",
                                "description": "(group_by=keyword) Distinct page-view sessions attributed to this keyword in the window.",
                                "examples": [
                                    320
                                ]
                            },
                            "started_installs": {
                                "type": "integer",
                                "description": "(group_by=keyword) Distinct \"Add app\" clicks (install starts) attributed to this keyword.",
                                "examples": [
                                    40
                                ]
                            },
                            "completed_installs": {
                                "type": "integer",
                                "description": "(group_by=keyword) First-touch completed installs attributed to this keyword.",
                                "examples": [
                                    18
                                ]
                            },
                            "conversion_rate": {
                                "description": "(group_by=keyword) Completed installs / views as a percentage; 0 when there are no views.",
                                "examples": [
                                    5.63
                                ],
                                "anyOf": [
                                    {
                                        "type": "integer"
                                    },
                                    {
                                        "type": "number"
                                    }
                                ]
                            },
                            "organic_installs": {
                                "type": [
                                    "integer",
                                    "null"
                                ],
                                "description": "(group_by=keyword) Organic-sourced installs (from BigQuery search rankings), or null when no ranking row exists for the keyword.",
                                "examples": [
                                    12
                                ]
                            },
                            "ad_installs": {
                                "type": [
                                    "integer",
                                    "null"
                                ],
                                "description": "(group_by=keyword) Ad-sourced installs (from BigQuery search rankings), or null when no ranking row exists for the keyword.",
                                "examples": [
                                    6
                                ]
                            },
                            "organic_pageviews": {
                                "type": [
                                    "integer",
                                    "null"
                                ],
                                "description": "(group_by=keyword) Organic-sourced pageviews (from BigQuery search rankings), or null when no ranking row exists for the keyword.",
                                "examples": [
                                    280
                                ]
                            },
                            "ad_pageviews": {
                                "type": [
                                    "integer",
                                    "null"
                                ],
                                "description": "(group_by=keyword) Ad-sourced pageviews (from BigQuery search rankings), or null when no ranking row exists for the keyword.",
                                "examples": [
                                    40
                                ]
                            }
                        },
                        "required": [
                            "keyword",
                            "views",
                            "started_installs",
                            "completed_installs",
                            "conversion_rate",
                            "organic_installs",
                            "ad_installs",
                            "organic_pageviews",
                            "ad_pageviews"
                        ]
                    },
                    {
                        "type": "object",
                        "properties": {
                            "category": {
                                "type": "string",
                                "description": "(group_by=category) App Store category name.",
                                "examples": [
                                    "Store management"
                                ]
                            },
                            "views": {
                                "type": "integer",
                                "description": "(group_by=category) Distinct page-view sessions attributed to this category in the window.",
                                "examples": [
                                    540
                                ]
                            },
                            "started_installs": {
                                "type": "integer",
                                "description": "(group_by=category) Distinct \"Add app\" clicks (install starts) attributed to this category.",
                                "examples": [
                                    60
                                ]
                            },
                            "completed_installs": {
                                "type": "integer",
                                "description": "(group_by=category) First-touch completed installs attributed to this category.",
                                "examples": [
                                    24
                                ]
                            },
                            "completion_rate": {
                                "type": [
                                    "number",
                                    "null"
                                ],
                                "description": "(group_by=category) Completed/started installs as a percentage, or null when there were no started installs.",
                                "examples": [
                                    40
                                ]
                            }
                        },
                        "required": [
                            "category",
                            "views",
                            "started_installs",
                            "completed_installs",
                            "completion_rate"
                        ]
                    },
                    {
                        "type": "object",
                        "properties": {
                            "source": {
                                "type": "string",
                                "description": "(group_by=source) Attribution source for this bucket.",
                                "examples": [
                                    "organic"
                                ]
                            },
                            "installs": {
                                "type": "integer",
                                "description": "(group_by=source) Attributed installs from this source in the window.",
                                "examples": [
                                    142
                                ]
                            },
                            "share": {
                                "description": "(group_by=source) This source's share of total attributed installs, as a percentage; 0 when there are no installs.",
                                "examples": [
                                    68.5
                                ],
                                "anyOf": [
                                    {
                                        "type": "integer"
                                    },
                                    {
                                        "type": "number"
                                    }
                                ]
                            }
                        },
                        "required": [
                            "source",
                            "installs",
                            "share"
                        ]
                    }
                ],
                "title": "InstallBucketResource"
            },
            "InstallsCollection": {
                "type": "object",
                "properties": {
                    "object": {
                        "type": "string",
                        "description": "Always the literal string `list` \u2014 the envelope-type discriminator.",
                        "const": "list",
                        "examples": [
                            "list"
                        ]
                    },
                    "url": {
                        "type": "string",
                        "description": "Path of this list resource.",
                        "examples": [
                            "/api/v1/apps/01JN4HKQX0000000000000000/reviews"
                        ]
                    },
                    "currency": {
                        "type": "string",
                        "description": "Base-currency ISO code (ISO 4217), present only on money series and\ndeclared once for every row in data.",
                        "examples": [
                            "USD"
                        ]
                    },
                    "page": {
                        "type": "integer",
                        "description": "Current page number (1-based).",
                        "examples": [
                            1
                        ]
                    },
                    "per_page": {
                        "type": "integer",
                        "description": "Rows per page.",
                        "examples": [
                            50
                        ]
                    },
                    "total_count": {
                        "type": "integer",
                        "description": "Total rows across every page.",
                        "examples": [
                            128
                        ]
                    },
                    "has_more": {
                        "type": "boolean",
                        "description": "Whether more pages follow this one.",
                        "examples": [
                            true
                        ]
                    },
                    "coverage": {
                        "type": "object",
                        "description": "Requested vs actually-covered date window for the series. Present on\ndate-windowed series only. `requested` echoes the asked-for range;\n`available` is the range actually covered by data, or null when\nnothing fell in range.",
                        "examples": [
                            {
                                "requested": {
                                    "start": "2026-05-01",
                                    "end": "2026-05-31"
                                },
                                "available": {
                                    "start": "2026-05-01",
                                    "end": "2026-05-28"
                                }
                            }
                        ],
                        "properties": {
                            "requested": {
                                "type": "object",
                                "properties": {
                                    "start": {
                                        "type": "string"
                                    },
                                    "end": {
                                        "type": "string"
                                    }
                                },
                                "required": [
                                    "start",
                                    "end"
                                ]
                            },
                            "available": {
                                "type": [
                                    "object",
                                    "null"
                                ],
                                "properties": {
                                    "start": {
                                        "type": "string"
                                    },
                                    "end": {
                                        "type": "string"
                                    }
                                },
                                "required": [
                                    "start",
                                    "end"
                                ]
                            }
                        },
                        "required": [
                            "requested",
                            "available"
                        ]
                    },
                    "metadata": {
                        "type": "object",
                        "description": "Endpoint-specific metadata \u2014 e.g. summary, echoed filters, or\nintegration sync status. Shape varies by endpoint.",
                        "examples": [
                            {
                                "partner_sync_status": "complete"
                            }
                        ],
                        "additionalProperties": {}
                    },
                    "data": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/InstallBucketResource"
                        }
                    }
                },
                "required": [
                    "object",
                    "url",
                    "page",
                    "per_page",
                    "total_count",
                    "has_more",
                    "data"
                ],
                "title": "InstallsCollection"
            },
            "KeywordPerformanceResource": {
                "type": "object",
                "properties": {
                    "keyword": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "The search keyword, or null when the scraped row had no associated keyword.",
                        "examples": [
                            "inventory sync"
                        ]
                    },
                    "organic_rank": {
                        "type": [
                            "integer",
                            "null"
                        ],
                        "description": "Latest scraped organic App Store rank for this keyword, or null when the app does not rank organically.",
                        "examples": [
                            4
                        ]
                    },
                    "organic_page": {
                        "type": [
                            "integer",
                            "null"
                        ],
                        "description": "Search-results page the organic rank falls on, or null when the app does not rank organically.",
                        "examples": [
                            1
                        ]
                    },
                    "organic_change": {
                        "type": [
                            "integer",
                            "null"
                        ],
                        "description": "Day-over-day change in organic rank (positive = improved), or null when not available.",
                        "examples": [
                            2
                        ]
                    },
                    "sponsored_rank": {
                        "type": [
                            "integer",
                            "null"
                        ],
                        "description": "Latest scraped sponsored (ad) rank for this keyword, or null when the app has no ad placement.",
                        "examples": [
                            1
                        ]
                    },
                    "sponsored_page": {
                        "type": [
                            "integer",
                            "null"
                        ],
                        "description": "Search-results page the sponsored rank falls on, or null when the app has no ad placement.",
                        "examples": [
                            1
                        ]
                    },
                    "sponsored_change": {
                        "type": [
                            "integer",
                            "null"
                        ],
                        "description": "Day-over-day change in sponsored rank (positive = improved), or null when not available.",
                        "examples": [
                            -1
                        ]
                    },
                    "views": {
                        "type": "integer",
                        "description": "Distinct page-view sessions attributed to this keyword in the requested window (BigQuery overlay); 0 when BigQuery is not connected.",
                        "examples": [
                            320
                        ]
                    },
                    "installs": {
                        "type": "integer",
                        "description": "Completed installs attributed to this keyword in the requested window (BigQuery overlay); 0 when BigQuery is not connected.",
                        "examples": [
                            18
                        ]
                    },
                    "organic_installs": {
                        "type": "integer",
                        "description": "Organic-sourced installs attributed to this keyword (BigQuery overlay); 0 when BigQuery is not connected.",
                        "examples": [
                            12
                        ]
                    },
                    "ad_installs": {
                        "type": "integer",
                        "description": "Ad-sourced installs attributed to this keyword (BigQuery overlay); 0 when BigQuery is not connected.",
                        "examples": [
                            6
                        ]
                    }
                },
                "required": [
                    "keyword",
                    "organic_rank",
                    "organic_page",
                    "organic_change",
                    "sponsored_rank",
                    "sponsored_page",
                    "sponsored_change",
                    "views",
                    "installs",
                    "organic_installs",
                    "ad_installs"
                ],
                "title": "KeywordPerformanceResource"
            },
            "KeywordsCollection": {
                "type": "object",
                "properties": {
                    "object": {
                        "type": "string",
                        "description": "Always the literal string `list` \u2014 the envelope-type discriminator.",
                        "const": "list",
                        "examples": [
                            "list"
                        ]
                    },
                    "url": {
                        "type": "string",
                        "description": "Path of this list resource.",
                        "examples": [
                            "/api/v1/apps/01JN4HKQX0000000000000000/reviews"
                        ]
                    },
                    "currency": {
                        "type": "string",
                        "description": "Base-currency ISO code (ISO 4217), present only on money series and\ndeclared once for every row in data.",
                        "examples": [
                            "USD"
                        ]
                    },
                    "page": {
                        "type": "integer",
                        "description": "Current page number (1-based).",
                        "examples": [
                            1
                        ]
                    },
                    "per_page": {
                        "type": "integer",
                        "description": "Rows per page.",
                        "examples": [
                            50
                        ]
                    },
                    "total_count": {
                        "type": "integer",
                        "description": "Total rows across every page.",
                        "examples": [
                            128
                        ]
                    },
                    "has_more": {
                        "type": "boolean",
                        "description": "Whether more pages follow this one.",
                        "examples": [
                            true
                        ]
                    },
                    "coverage": {
                        "type": "object",
                        "description": "Requested vs actually-covered date window for the series. Present on\ndate-windowed series only. `requested` echoes the asked-for range;\n`available` is the range actually covered by data, or null when\nnothing fell in range.",
                        "examples": [
                            {
                                "requested": {
                                    "start": "2026-05-01",
                                    "end": "2026-05-31"
                                },
                                "available": {
                                    "start": "2026-05-01",
                                    "end": "2026-05-28"
                                }
                            }
                        ],
                        "properties": {
                            "requested": {
                                "type": "object",
                                "properties": {
                                    "start": {
                                        "type": "string"
                                    },
                                    "end": {
                                        "type": "string"
                                    }
                                },
                                "required": [
                                    "start",
                                    "end"
                                ]
                            },
                            "available": {
                                "type": [
                                    "object",
                                    "null"
                                ],
                                "properties": {
                                    "start": {
                                        "type": "string"
                                    },
                                    "end": {
                                        "type": "string"
                                    }
                                },
                                "required": [
                                    "start",
                                    "end"
                                ]
                            }
                        },
                        "required": [
                            "requested",
                            "available"
                        ]
                    },
                    "metadata": {
                        "type": "object",
                        "description": "Endpoint-specific metadata \u2014 e.g. summary, echoed filters, or\nintegration sync status. Shape varies by endpoint.",
                        "examples": [
                            {
                                "partner_sync_status": "complete"
                            }
                        ],
                        "additionalProperties": {}
                    },
                    "data": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/KeywordPerformanceResource"
                        }
                    }
                },
                "required": [
                    "object",
                    "url",
                    "page",
                    "per_page",
                    "total_count",
                    "has_more",
                    "data"
                ],
                "title": "KeywordsCollection"
            },
            "LtvCohortResource": {
                "type": "object",
                "properties": {
                    "cohort": {
                        "type": "string",
                        "description": "Acquisition cohort \u2014 the month (YYYY-MM) the shops first installed.",
                        "examples": [
                            "2026-01"
                        ]
                    },
                    "customers": {
                        "type": "integer",
                        "description": "Number of shops acquired in this cohort.",
                        "examples": [
                            42
                        ]
                    },
                    "average_ltv": {
                        "type": "number",
                        "description": "Average lifetime revenue per shop in the cohort.",
                        "examples": [
                            184.5
                        ]
                    },
                    "median_ltv": {
                        "type": "number",
                        "description": "Median lifetime revenue per shop in the cohort (robust to whales).",
                        "examples": [
                            96
                        ]
                    },
                    "total_revenue": {
                        "type": "number",
                        "description": "Total lifetime revenue from every shop in the cohort.",
                        "examples": [
                            7749
                        ]
                    }
                },
                "required": [
                    "cohort",
                    "customers",
                    "average_ltv",
                    "median_ltv",
                    "total_revenue"
                ],
                "title": "LtvCohortResource"
            },
            "LtvCohortsCollection": {
                "type": "object",
                "properties": {
                    "object": {
                        "type": "string",
                        "description": "Always the literal string `list` \u2014 the envelope-type discriminator.",
                        "const": "list",
                        "examples": [
                            "list"
                        ]
                    },
                    "url": {
                        "type": "string",
                        "description": "Path of this list resource.",
                        "examples": [
                            "/api/v1/apps/01JN4HKQX0000000000000000/reviews"
                        ]
                    },
                    "currency": {
                        "type": "string",
                        "description": "Base-currency ISO code (ISO 4217), present only on money series and\ndeclared once for every row in data.",
                        "examples": [
                            "USD"
                        ]
                    },
                    "page": {
                        "type": "integer",
                        "description": "Current page number (1-based).",
                        "examples": [
                            1
                        ]
                    },
                    "per_page": {
                        "type": "integer",
                        "description": "Rows per page.",
                        "examples": [
                            50
                        ]
                    },
                    "total_count": {
                        "type": "integer",
                        "description": "Total rows across every page.",
                        "examples": [
                            128
                        ]
                    },
                    "has_more": {
                        "type": "boolean",
                        "description": "Whether more pages follow this one.",
                        "examples": [
                            true
                        ]
                    },
                    "coverage": {
                        "type": "object",
                        "description": "Requested vs actually-covered date window for the series. Present on\ndate-windowed series only. `requested` echoes the asked-for range;\n`available` is the range actually covered by data, or null when\nnothing fell in range.",
                        "examples": [
                            {
                                "requested": {
                                    "start": "2026-05-01",
                                    "end": "2026-05-31"
                                },
                                "available": {
                                    "start": "2026-05-01",
                                    "end": "2026-05-28"
                                }
                            }
                        ],
                        "properties": {
                            "requested": {
                                "type": "object",
                                "properties": {
                                    "start": {
                                        "type": "string"
                                    },
                                    "end": {
                                        "type": "string"
                                    }
                                },
                                "required": [
                                    "start",
                                    "end"
                                ]
                            },
                            "available": {
                                "type": [
                                    "object",
                                    "null"
                                ],
                                "properties": {
                                    "start": {
                                        "type": "string"
                                    },
                                    "end": {
                                        "type": "string"
                                    }
                                },
                                "required": [
                                    "start",
                                    "end"
                                ]
                            }
                        },
                        "required": [
                            "requested",
                            "available"
                        ]
                    },
                    "metadata": {
                        "type": "object",
                        "description": "Endpoint-specific metadata \u2014 e.g. summary, echoed filters, or\nintegration sync status. Shape varies by endpoint.",
                        "examples": [
                            {
                                "partner_sync_status": "complete"
                            }
                        ],
                        "additionalProperties": {}
                    },
                    "data": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/LtvCohortResource"
                        }
                    }
                },
                "required": [
                    "object",
                    "url",
                    "page",
                    "per_page",
                    "total_count",
                    "has_more",
                    "data"
                ],
                "title": "LtvCohortsCollection"
            },
            "MetricPointResource": {
                "type": "object",
                "properties": {
                    "date": {
                        "type": "string",
                        "description": "The point's date (YYYY-MM-DD); for week/month granularity this is the bucket's last day.",
                        "examples": [
                            "2026-05-01"
                        ]
                    },
                    "value": {
                        "type": "number",
                        "description": "The metric value for this point. For ratios this is a fraction (0.30 = 30%), not a percentage.",
                        "examples": [
                            1990.5
                        ]
                    },
                    "components": {
                        "type": "object",
                        "description": "Present only for ratio/breakdown metrics; the raw inputs behind `value`,\nkeyed by domain name (e.g. trials_converted / trials_started).",
                        "examples": [
                            {
                                "trials_converted": 30,
                                "trials_started": 100
                            }
                        ],
                        "additionalProperties": {
                            "type": "number"
                        }
                    },
                    "group": {
                        "type": "string",
                        "description": "Present only on grouped series; the breakdown bucket this point belongs to.",
                        "examples": [
                            "organic"
                        ]
                    }
                },
                "required": [
                    "date",
                    "value"
                ],
                "title": "MetricPointResource"
            },
            "MetricResource": {
                "type": "object",
                "properties": {
                    "object": {
                        "type": "string",
                        "description": "Discriminator; always the literal string `metric` for a snapshot response.",
                        "examples": [
                            "metric"
                        ]
                    },
                    "id": {
                        "type": "string",
                        "description": "The metric name.",
                        "examples": [
                            "mrr"
                        ]
                    },
                    "app": {
                        "type": "string",
                        "description": "The team app's ULID this metric belongs to.",
                        "examples": [
                            "01JN4HKQX0000000000000000"
                        ]
                    },
                    "date": {
                        "type": "string",
                        "description": "The date the value is current as of (YYYY-MM-DD) \u2014 the requested `date`, or the\nlatest available partner-metrics day when no `date` was given.",
                        "examples": [
                            "2026-05-01"
                        ]
                    },
                    "value": {
                        "type": "number",
                        "description": "The metric value. For ratios this is a fraction (0.30 = 30%), not a percentage.",
                        "examples": [
                            1990.5
                        ]
                    },
                    "components": {
                        "type": "object",
                        "description": "Present only for ratio/breakdown metrics; the raw inputs behind `value`,\nkeyed by domain name (e.g. trials_converted / trials_started).",
                        "examples": [
                            {
                                "trials_converted": 30,
                                "trials_started": 100
                            }
                        ],
                        "additionalProperties": {
                            "type": "number"
                        }
                    },
                    "currency": {
                        "type": "string",
                        "description": "Present only for money metrics; the app's base payout currency (ISO 4217).",
                        "examples": [
                            "USD"
                        ]
                    },
                    "metadata": {
                        "type": "object",
                        "description": "Endpoint-specific metadata \u2014 e.g. partner-sync status and per-metric\nnotes. Shape varies by metric. Windowed rate metrics (`churn_rate`,\n`revenue_churn_rate`) add `computed` (`\"stored\"` \u2014 served from a frozen\ndaily PMD snapshot), the selected rolling `window` (7d|30d|90d|365d),\na human `window_note`, and an optional `components_note` (present only\nwhen the chosen window stores the rate without its raw components).",
                        "examples": [
                            {
                                "partner_sync_status": "complete",
                                "computed": "stored",
                                "window": "30d",
                                "window_note": "Rolling 30d churn, frozen daily snapshot keyed on Shopify event date.",
                                "components_note": "Components (churned/at-risk counts) are only available for the default 30d window; other windows store the rate only."
                            }
                        ],
                        "additionalProperties": {}
                    }
                },
                "required": [
                    "object",
                    "id",
                    "app",
                    "date",
                    "value",
                    "metadata"
                ],
                "title": "MetricResource"
            },
            "MetricSeriesCollection": {
                "type": "object",
                "properties": {
                    "object": {
                        "type": "string",
                        "description": "Discriminator; always the literal string `list` for a paginated series response.",
                        "examples": [
                            "list"
                        ]
                    },
                    "url": {
                        "type": "string",
                        "description": "The request path that produced this list.",
                        "examples": [
                            "/api/v1/apps/01JN4HKQX0000000000000000/metrics/mrr"
                        ]
                    },
                    "currency": {
                        "type": "string",
                        "description": "Present only for money metrics; the app's base payout currency (ISO 4217),\ndeclared once and applying to every point in data.",
                        "examples": [
                            "USD"
                        ]
                    },
                    "page": {
                        "type": "integer",
                        "description": "1-based index of the page returned.",
                        "examples": [
                            1
                        ]
                    },
                    "per_page": {
                        "type": "integer",
                        "description": "Maximum number of points per page.",
                        "examples": [
                            50
                        ]
                    },
                    "total_count": {
                        "type": "integer",
                        "description": "Total number of points across all pages.",
                        "examples": [
                            31
                        ]
                    },
                    "has_more": {
                        "type": "boolean",
                        "description": "True when further pages exist after this one.",
                        "examples": [
                            false
                        ]
                    },
                    "coverage": {
                        "type": "object",
                        "description": "Requested vs actually-covered date window for the series. Present on\ndate-windowed series only. `requested` echoes the asked-for range;\n`available` is the range actually covered by data, or null when\nnothing fell in range.",
                        "examples": [
                            {
                                "requested": {
                                    "start": "2026-05-01",
                                    "end": "2026-05-31"
                                },
                                "available": {
                                    "start": "2026-05-01",
                                    "end": "2026-05-28"
                                }
                            }
                        ],
                        "properties": {
                            "requested": {
                                "type": "object",
                                "properties": {
                                    "start": {
                                        "type": "string"
                                    },
                                    "end": {
                                        "type": "string"
                                    }
                                },
                                "required": [
                                    "start",
                                    "end"
                                ]
                            },
                            "available": {
                                "type": [
                                    "object",
                                    "null"
                                ],
                                "properties": {
                                    "start": {
                                        "type": "string"
                                    },
                                    "end": {
                                        "type": "string"
                                    }
                                },
                                "required": [
                                    "start",
                                    "end"
                                ]
                            }
                        },
                        "required": [
                            "requested",
                            "available"
                        ]
                    },
                    "metadata": {
                        "type": "object",
                        "description": "Endpoint-specific metadata \u2014 e.g. partner-sync status and per-metric\nnotes. Shape varies by endpoint. Windowed rate metrics (`churn_rate`,\n`revenue_churn_rate`) add `computed` (`\"stored\"` \u2014 served from a frozen\ndaily PMD snapshot), the selected rolling `window` (7d|30d|90d|365d),\na human `window_note`, and an optional `components_note` (present only\nwhen the chosen window stores the rate without its raw components).",
                        "examples": [
                            {
                                "partner_sync_status": "complete",
                                "computed": "stored",
                                "window": "30d",
                                "window_note": "Rolling 30d churn, frozen daily snapshot keyed on Shopify event date.",
                                "components_note": "Components (churned/at-risk counts) are only available for the default 30d window; other windows store the rate only."
                            }
                        ],
                        "additionalProperties": {}
                    },
                    "data": {
                        "type": "array",
                        "description": "The page of series points, ordered by date ascending.",
                        "items": {
                            "$ref": "#/components/schemas/MetricPointResource"
                        }
                    }
                },
                "required": [
                    "object",
                    "url",
                    "page",
                    "per_page",
                    "total_count",
                    "has_more",
                    "data"
                ],
                "title": "MetricSeriesCollection"
            },
            "RankingHistoryCollection": {
                "type": "object",
                "properties": {
                    "object": {
                        "type": "string",
                        "description": "Always the literal string `list` \u2014 the envelope-type discriminator.",
                        "const": "list",
                        "examples": [
                            "list"
                        ]
                    },
                    "url": {
                        "type": "string",
                        "description": "Path of this list resource.",
                        "examples": [
                            "/api/v1/apps/01JN4HKQX0000000000000000/reviews"
                        ]
                    },
                    "currency": {
                        "type": "string",
                        "description": "Base-currency ISO code (ISO 4217), present only on money series and\ndeclared once for every row in data.",
                        "examples": [
                            "USD"
                        ]
                    },
                    "page": {
                        "type": "integer",
                        "description": "Current page number (1-based).",
                        "examples": [
                            1
                        ]
                    },
                    "per_page": {
                        "type": "integer",
                        "description": "Rows per page.",
                        "examples": [
                            50
                        ]
                    },
                    "total_count": {
                        "type": "integer",
                        "description": "Total rows across every page.",
                        "examples": [
                            128
                        ]
                    },
                    "has_more": {
                        "type": "boolean",
                        "description": "Whether more pages follow this one.",
                        "examples": [
                            true
                        ]
                    },
                    "coverage": {
                        "type": "object",
                        "description": "Requested vs actually-covered date window for the series. Present on\ndate-windowed series only. `requested` echoes the asked-for range;\n`available` is the range actually covered by data, or null when\nnothing fell in range.",
                        "examples": [
                            {
                                "requested": {
                                    "start": "2026-05-01",
                                    "end": "2026-05-31"
                                },
                                "available": {
                                    "start": "2026-05-01",
                                    "end": "2026-05-28"
                                }
                            }
                        ],
                        "properties": {
                            "requested": {
                                "type": "object",
                                "properties": {
                                    "start": {
                                        "type": "string"
                                    },
                                    "end": {
                                        "type": "string"
                                    }
                                },
                                "required": [
                                    "start",
                                    "end"
                                ]
                            },
                            "available": {
                                "type": [
                                    "object",
                                    "null"
                                ],
                                "properties": {
                                    "start": {
                                        "type": "string"
                                    },
                                    "end": {
                                        "type": "string"
                                    }
                                },
                                "required": [
                                    "start",
                                    "end"
                                ]
                            }
                        },
                        "required": [
                            "requested",
                            "available"
                        ]
                    },
                    "metadata": {
                        "type": "object",
                        "description": "Endpoint-specific metadata \u2014 e.g. summary, echoed filters, or\nintegration sync status. Shape varies by endpoint.",
                        "examples": [
                            {
                                "partner_sync_status": "complete"
                            }
                        ],
                        "additionalProperties": {}
                    },
                    "data": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/RankingHistoryPointResource"
                        }
                    }
                },
                "required": [
                    "object",
                    "url",
                    "page",
                    "per_page",
                    "total_count",
                    "has_more",
                    "data"
                ],
                "title": "RankingHistoryCollection"
            },
            "RankingHistoryPointResource": {
                "type": "object",
                "properties": {
                    "date": {
                        "type": "string",
                        "description": "Date of this rank observation (YYYY-MM-DD).",
                        "examples": [
                            "2026-05-29"
                        ]
                    },
                    "rank": {
                        "type": [
                            "integer",
                            "null"
                        ],
                        "description": "Scraped rank on this date. 0 means the app was not found for this\nterm on that day; null when the rank was not captured.",
                        "examples": [
                            7
                        ]
                    },
                    "page": {
                        "type": [
                            "integer",
                            "null"
                        ],
                        "description": "Search-results page the app appeared on for this date; keyword\nhistory only, otherwise omitted/null.",
                        "examples": [
                            1
                        ]
                    },
                    "change": {
                        "type": [
                            "integer",
                            "null"
                        ],
                        "description": "Rank movement vs the previous observation (positive = improved toward\n#1); null when there is no prior data point.",
                        "examples": [
                            2
                        ]
                    },
                    "is_sponsored": {
                        "type": [
                            "boolean",
                            "null"
                        ],
                        "description": "Whether this keyword rank was a sponsored (ad) placement; keyword\nhistory only, otherwise omitted/null.",
                        "examples": [
                            false
                        ]
                    }
                },
                "required": [
                    "date",
                    "rank",
                    "page",
                    "change",
                    "is_sponsored"
                ],
                "title": "RankingHistoryPointResource"
            },
            "RankingRowResource": {
                "type": "object",
                "properties": {
                    "rank": {
                        "type": "integer",
                        "description": "Current scraped rank for this keyword/category. 0 means the app was\nnot found in the scraped results for this term.",
                        "examples": [
                            7
                        ]
                    },
                    "change": {
                        "type": "integer",
                        "description": "Rank movement vs the previous scrape (positive = improved toward #1);\n0 when there is no prior data point.",
                        "examples": [
                            2
                        ]
                    },
                    "date": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Date this rank was scraped (YYYY-MM-DD), or null when unknown.",
                        "examples": [
                            "2026-05-29"
                        ]
                    },
                    "category": {
                        "type": [
                            "object",
                            "null"
                        ],
                        "description": "Category this rank belongs to; present only for category rows\n(type=categories), otherwise omitted/null.",
                        "examples": [
                            {
                                "slug": "store-management",
                                "name": "Store management"
                            }
                        ],
                        "properties": {
                            "slug": {
                                "type": "string"
                            },
                            "name": {
                                "type": "string"
                            }
                        },
                        "required": [
                            "slug",
                            "name"
                        ]
                    },
                    "keyword": {
                        "type": [
                            "object",
                            "null"
                        ],
                        "description": "Keyword this rank belongs to; present only for keyword rows\n(type=keywords|all), otherwise omitted/null.",
                        "examples": [
                            {
                                "slug": "product-reviews",
                                "keyword": "product reviews"
                            }
                        ],
                        "properties": {
                            "slug": {
                                "type": "string"
                            },
                            "keyword": {
                                "type": "string"
                            }
                        },
                        "required": [
                            "slug",
                            "keyword"
                        ]
                    },
                    "app": {
                        "type": [
                            "object",
                            "null"
                        ],
                        "description": "Small card for the ranked app; present only when the app relation is\nresolved on the row, otherwise omitted/null.",
                        "examples": [
                            {
                                "slug": "acme-reviews",
                                "name": "Acme Reviews"
                            }
                        ],
                        "properties": {
                            "slug": {
                                "type": "string"
                            },
                            "name": {
                                "type": "string"
                            }
                        },
                        "required": [
                            "slug",
                            "name"
                        ]
                    },
                    "is_sponsored": {
                        "type": [
                            "boolean",
                            "null"
                        ],
                        "description": "Whether this keyword rank is a sponsored (ad) placement; present only\non keyword rows, otherwise omitted/null.",
                        "examples": [
                            false
                        ]
                    }
                },
                "required": [
                    "rank",
                    "change",
                    "date",
                    "category",
                    "keyword",
                    "app",
                    "is_sponsored"
                ],
                "title": "RankingRowResource"
            },
            "RankingsCollection": {
                "type": "object",
                "properties": {
                    "object": {
                        "type": "string",
                        "description": "Always the literal string `list` \u2014 the envelope-type discriminator.",
                        "const": "list",
                        "examples": [
                            "list"
                        ]
                    },
                    "url": {
                        "type": "string",
                        "description": "Path of this list resource.",
                        "examples": [
                            "/api/v1/apps/01JN4HKQX0000000000000000/reviews"
                        ]
                    },
                    "currency": {
                        "type": "string",
                        "description": "Base-currency ISO code (ISO 4217), present only on money series and\ndeclared once for every row in data.",
                        "examples": [
                            "USD"
                        ]
                    },
                    "page": {
                        "type": "integer",
                        "description": "Current page number (1-based).",
                        "examples": [
                            1
                        ]
                    },
                    "per_page": {
                        "type": "integer",
                        "description": "Rows per page.",
                        "examples": [
                            50
                        ]
                    },
                    "total_count": {
                        "type": "integer",
                        "description": "Total rows across every page.",
                        "examples": [
                            128
                        ]
                    },
                    "has_more": {
                        "type": "boolean",
                        "description": "Whether more pages follow this one.",
                        "examples": [
                            true
                        ]
                    },
                    "coverage": {
                        "type": "object",
                        "description": "Requested vs actually-covered date window for the series. Present on\ndate-windowed series only. `requested` echoes the asked-for range;\n`available` is the range actually covered by data, or null when\nnothing fell in range.",
                        "examples": [
                            {
                                "requested": {
                                    "start": "2026-05-01",
                                    "end": "2026-05-31"
                                },
                                "available": {
                                    "start": "2026-05-01",
                                    "end": "2026-05-28"
                                }
                            }
                        ],
                        "properties": {
                            "requested": {
                                "type": "object",
                                "properties": {
                                    "start": {
                                        "type": "string"
                                    },
                                    "end": {
                                        "type": "string"
                                    }
                                },
                                "required": [
                                    "start",
                                    "end"
                                ]
                            },
                            "available": {
                                "type": [
                                    "object",
                                    "null"
                                ],
                                "properties": {
                                    "start": {
                                        "type": "string"
                                    },
                                    "end": {
                                        "type": "string"
                                    }
                                },
                                "required": [
                                    "start",
                                    "end"
                                ]
                            }
                        },
                        "required": [
                            "requested",
                            "available"
                        ]
                    },
                    "metadata": {
                        "type": "object",
                        "description": "Endpoint-specific metadata \u2014 e.g. summary, echoed filters, or\nintegration sync status. Shape varies by endpoint.",
                        "examples": [
                            {
                                "partner_sync_status": "complete"
                            }
                        ],
                        "additionalProperties": {}
                    },
                    "data": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/RankingRowResource"
                        }
                    }
                },
                "required": [
                    "object",
                    "url",
                    "page",
                    "per_page",
                    "total_count",
                    "has_more",
                    "data"
                ],
                "title": "RankingsCollection"
            },
            "ReviewResource": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "Shopify review id.",
                        "examples": [
                            "123456789"
                        ]
                    },
                    "rating": {
                        "type": "integer",
                        "description": "Star rating the merchant left, 1\u20135.",
                        "examples": [
                            5
                        ]
                    },
                    "body": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Review text, or null when the merchant left only a rating.",
                        "examples": [
                            "Works exactly as described and support is fast."
                        ]
                    },
                    "author": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Reviewing store name, or null when not captured.",
                        "examples": [
                            "Acme Store"
                        ]
                    },
                    "store_name": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Reviewing store name (same value as author); null when not captured.",
                        "examples": [
                            "Acme Store"
                        ]
                    },
                    "country": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Two-letter country code of the reviewing store, or null when unknown.",
                        "examples": [
                            "US"
                        ]
                    },
                    "usage_duration": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "How long the merchant had used the app when reviewing, or null when unknown.",
                        "examples": [
                            "About 1 year"
                        ]
                    },
                    "review_date": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Date the review was posted (YYYY-MM-DD), or null when unknown.",
                        "examples": [
                            "2026-05-01"
                        ]
                    },
                    "has_reply": {
                        "type": "boolean",
                        "description": "Whether the developer has replied to this review.",
                        "examples": [
                            true
                        ]
                    },
                    "reply": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Developer reply, or null when there is none.",
                        "examples": [
                            "Thanks for the kind words \u2014 glad it helped!"
                        ]
                    },
                    "reply_date": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Date of the developer reply (YYYY-MM-DD), or null when there is no reply.",
                        "examples": [
                            "2026-05-02"
                        ]
                    }
                },
                "required": [
                    "id",
                    "rating",
                    "body",
                    "author",
                    "store_name",
                    "country",
                    "usage_duration",
                    "review_date",
                    "has_reply",
                    "reply",
                    "reply_date"
                ],
                "title": "ReviewResource"
            },
            "ReviewsCollection": {
                "type": "object",
                "properties": {
                    "object": {
                        "type": "string",
                        "description": "Always the literal string `list` \u2014 the envelope-type discriminator.",
                        "const": "list",
                        "examples": [
                            "list"
                        ]
                    },
                    "url": {
                        "type": "string",
                        "description": "Path of this list resource.",
                        "examples": [
                            "/api/v1/apps/01JN4HKQX0000000000000000/reviews"
                        ]
                    },
                    "currency": {
                        "type": "string",
                        "description": "Base-currency ISO code (ISO 4217), present only on money series and\ndeclared once for every row in data.",
                        "examples": [
                            "USD"
                        ]
                    },
                    "page": {
                        "type": "integer",
                        "description": "Current page number (1-based).",
                        "examples": [
                            1
                        ]
                    },
                    "per_page": {
                        "type": "integer",
                        "description": "Rows per page.",
                        "examples": [
                            50
                        ]
                    },
                    "total_count": {
                        "type": "integer",
                        "description": "Total rows across every page.",
                        "examples": [
                            128
                        ]
                    },
                    "has_more": {
                        "type": "boolean",
                        "description": "Whether more pages follow this one.",
                        "examples": [
                            true
                        ]
                    },
                    "coverage": {
                        "type": "object",
                        "description": "Requested vs actually-covered date window for the series. Present on\ndate-windowed series only. `requested` echoes the asked-for range;\n`available` is the range actually covered by data, or null when\nnothing fell in range.",
                        "examples": [
                            {
                                "requested": {
                                    "start": "2026-05-01",
                                    "end": "2026-05-31"
                                },
                                "available": {
                                    "start": "2026-05-01",
                                    "end": "2026-05-28"
                                }
                            }
                        ],
                        "properties": {
                            "requested": {
                                "type": "object",
                                "properties": {
                                    "start": {
                                        "type": "string"
                                    },
                                    "end": {
                                        "type": "string"
                                    }
                                },
                                "required": [
                                    "start",
                                    "end"
                                ]
                            },
                            "available": {
                                "type": [
                                    "object",
                                    "null"
                                ],
                                "properties": {
                                    "start": {
                                        "type": "string"
                                    },
                                    "end": {
                                        "type": "string"
                                    }
                                },
                                "required": [
                                    "start",
                                    "end"
                                ]
                            }
                        },
                        "required": [
                            "requested",
                            "available"
                        ]
                    },
                    "metadata": {
                        "type": "object",
                        "description": "Endpoint-specific metadata \u2014 e.g. summary, echoed filters, or\nintegration sync status. Shape varies by endpoint.",
                        "examples": [
                            {
                                "partner_sync_status": "complete"
                            }
                        ],
                        "additionalProperties": {}
                    },
                    "data": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/ReviewResource"
                        }
                    }
                },
                "required": [
                    "object",
                    "url",
                    "page",
                    "per_page",
                    "total_count",
                    "has_more",
                    "data"
                ],
                "title": "ReviewsCollection"
            },
            "ScorecardResource": {
                "type": "object",
                "properties": {
                    "object": {
                        "type": "string",
                        "description": "Constant discriminator identifying this payload as a scorecard object.",
                        "examples": [
                            "scorecard"
                        ]
                    },
                    "overall_score": {
                        "type": "integer",
                        "description": "Weighted overall competitive health score, 0\u2013100.",
                        "examples": [
                            72
                        ]
                    },
                    "listing_quality": {
                        "type": "object",
                        "description": "Listing-quality sub-score (0\u2013100) plus its scoring breakdown:\n`characterUtilization` ({score, maxScore:40, averageUtilization,\nfields:{name|subtitle|introduction|details:{length,limit,utilization}},\nfeatureCount}), `antiPatterns` ({score, maxScore:30, count,\ndetails:{field:string[]}}) and `keywordPresence` ({score, maxScore:30,\nfound:string[], missing:string[], source:\"traffic\"|\"rankings\"|\"none\"}).",
                        "examples": [
                            {
                                "score": 68,
                                "breakdown": {
                                    "characterUtilization": {
                                        "score": 28,
                                        "maxScore": 40,
                                        "averageUtilization": 71.2,
                                        "fields": {
                                            "name": {
                                                "length": 28,
                                                "limit": 30,
                                                "utilization": 93.3
                                            },
                                            "subtitle": {
                                                "length": 60,
                                                "limit": 62,
                                                "utilization": 96.8
                                            },
                                            "introduction": {
                                                "length": 90,
                                                "limit": 100,
                                                "utilization": 90
                                            },
                                            "details": {
                                                "length": 320,
                                                "limit": 500,
                                                "utilization": 64
                                            }
                                        },
                                        "featureCount": 3
                                    },
                                    "antiPatterns": {
                                        "score": 25,
                                        "maxScore": 30,
                                        "count": 1,
                                        "details": {
                                            "details": [
                                                "Avoid superlatives like \"best\"."
                                            ]
                                        }
                                    },
                                    "keywordPresence": {
                                        "score": 15,
                                        "maxScore": 30,
                                        "found": [
                                            "inventory sync"
                                        ],
                                        "missing": [
                                            "stock alerts"
                                        ],
                                        "source": "traffic"
                                    }
                                }
                            }
                        ],
                        "properties": {
                            "score": {
                                "type": "integer"
                            },
                            "breakdown": {
                                "type": "object",
                                "additionalProperties": {}
                            }
                        },
                        "required": [
                            "score",
                            "breakdown"
                        ]
                    },
                    "keyword_performance": {
                        "type": "object",
                        "description": "Keyword-performance sub-score (0\u2013100) plus its breakdown:\n`keywordBreadth` ({score, maxScore:20, count}), `outrankingRatio`\n({score, maxScore:35, ratio, trackedWeightApplied}), `topTenDensity`\n({score, maxScore:30, count, total, ratio, trackedWeightApplied}),\n`keywordCoverage` ({score, maxScore:15, ratio}), the\n`outrankedKeywords` list ({keyword_id, keyword, yourRank,\nbestCompetitorRank, bestCompetitorAppName, tracked, installAttributed,\ntier, gap}), the `unrankedTrackedKeywords` list ({keyword_id, keyword,\ninstallAttributed}) and the `outrankedTrackedCount` /\n`unrankedTrackedCount` totals.",
                        "examples": [
                            {
                                "score": 74,
                                "breakdown": {
                                    "keywordBreadth": {
                                        "score": 16,
                                        "maxScore": 20,
                                        "count": 41
                                    },
                                    "outrankingRatio": {
                                        "score": 22,
                                        "maxScore": 35,
                                        "ratio": 0.63,
                                        "trackedWeightApplied": true
                                    },
                                    "topTenDensity": {
                                        "score": 21,
                                        "maxScore": 30,
                                        "count": 12,
                                        "total": 41,
                                        "ratio": 0.293,
                                        "trackedWeightApplied": true
                                    },
                                    "keywordCoverage": {
                                        "score": 11,
                                        "maxScore": 15,
                                        "ratio": 0.74
                                    },
                                    "outrankedKeywords": [
                                        {
                                            "keyword_id": 5012,
                                            "keyword": "stock alerts",
                                            "yourRank": 14,
                                            "bestCompetitorRank": 3,
                                            "bestCompetitorAppName": "Stocky",
                                            "tracked": true,
                                            "installAttributed": false,
                                            "tier": 2,
                                            "gap": 11
                                        }
                                    ],
                                    "unrankedTrackedKeywords": [
                                        {
                                            "keyword_id": 5099,
                                            "keyword": "low stock",
                                            "installAttributed": true
                                        }
                                    ],
                                    "outrankedTrackedCount": 4,
                                    "unrankedTrackedCount": 2
                                }
                            }
                        ],
                        "properties": {
                            "score": {
                                "type": "integer"
                            },
                            "breakdown": {
                                "type": "object",
                                "additionalProperties": {}
                            }
                        },
                        "required": [
                            "score",
                            "breakdown"
                        ]
                    },
                    "reviews_reputation": {
                        "type": "object",
                        "description": "Reviews & reputation sub-score (0\u2013100) plus its breakdown:\n`rating` ({score, maxScore:35, value, competitorAvg}), `volume`\n({score, maxScore:20, count, competitorAvg}), `sentiment` ({score,\nmaxScore:25, positiveRatio, distribution:{positive,neutral,negative}}),\n`recency` ({score, maxScore:20}) and the `competitorAdjustment`\ninteger (-5..+5).",
                        "examples": [
                            {
                                "score": 81,
                                "breakdown": {
                                    "rating": {
                                        "score": 30,
                                        "maxScore": 35,
                                        "value": 4.7,
                                        "competitorAvg": 4.5
                                    },
                                    "volume": {
                                        "score": 17,
                                        "maxScore": 20,
                                        "count": 312,
                                        "competitorAvg": 540
                                    },
                                    "sentiment": {
                                        "score": 22,
                                        "maxScore": 25,
                                        "positiveRatio": 0.91,
                                        "distribution": {
                                            "positive": 284,
                                            "neutral": 12,
                                            "negative": 16
                                        }
                                    },
                                    "recency": {
                                        "score": 12,
                                        "maxScore": 20
                                    },
                                    "competitorAdjustment": 1
                                }
                            }
                        ],
                        "properties": {
                            "score": {
                                "type": "integer"
                            },
                            "breakdown": {
                                "type": "object",
                                "additionalProperties": {}
                            }
                        },
                        "required": [
                            "score",
                            "breakdown"
                        ]
                    },
                    "visibility": {
                        "type": "object",
                        "description": "Visibility sub-score (0\u2013100) plus its breakdown:\n`categoriesRankedIn` ({score, maxScore:25, count,\ncategories:[{name, rank}]}), `bestPosition` ({score, maxScore:30,\nposition}), `avgPosition` ({score, maxScore:25, position}) and\n`categoryGaps` ({score, maxScore:20, gaps}).",
                        "examples": [
                            {
                                "score": 65,
                                "breakdown": {
                                    "categoriesRankedIn": {
                                        "score": 20,
                                        "maxScore": 25,
                                        "count": 4,
                                        "categories": [
                                            {
                                                "name": "Inventory management",
                                                "rank": 7
                                            },
                                            {
                                                "name": "Stock control",
                                                "rank": 18
                                            }
                                        ]
                                    },
                                    "bestPosition": {
                                        "score": 21,
                                        "maxScore": 30,
                                        "position": 7
                                    },
                                    "avgPosition": {
                                        "score": 13,
                                        "maxScore": 25,
                                        "position": 12.5
                                    },
                                    "categoryGaps": {
                                        "score": 11,
                                        "maxScore": 20,
                                        "gaps": 3
                                    }
                                }
                            }
                        ],
                        "properties": {
                            "score": {
                                "type": "integer"
                            },
                            "breakdown": {
                                "type": "object",
                                "additionalProperties": {}
                            }
                        },
                        "required": [
                            "score",
                            "breakdown"
                        ]
                    },
                    "is_provisional": {
                        "type": "boolean",
                        "description": "True when the scorecard was computed against a PROVISIONAL comparison\nset (embedding-similar \u2192 top-category apps) because the team follows\nno competitors yet.",
                        "examples": [
                            false
                        ]
                    },
                    "computed_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "When the scorecard was last computed (ISO-8601), or null if never.",
                        "examples": [
                            "2026-05-30T08:15:00+00:00"
                        ]
                    },
                    "improvement_opportunities": {
                        "type": "array",
                        "description": "Prioritised improvement opportunities (priority 1 = highest first).\nEach item: `type` (listing_quality|keyword_performance|\nreviews_reputation|visibility), `message`, `priority` (int),\n`current_value` / `target_value` (string|int|null), `link_to`\n(string|null), and optionally `keywords` (a list of\n{keyword, tracked, installAttributed} chips on keyword items).",
                        "examples": [
                            [
                                {
                                    "type": "keyword_performance",
                                    "message": "Competitors outrank you on 4 keywords you track: stock alerts, low stock. Improve your listing relevance for these.",
                                    "priority": 1,
                                    "current_value": "37% win rate",
                                    "target_value": "50%+",
                                    "link_to": "/competitors",
                                    "keywords": [
                                        {
                                            "keyword": "stock alerts",
                                            "tracked": true,
                                            "installAttributed": false
                                        }
                                    ]
                                },
                                {
                                    "type": "listing_quality",
                                    "message": "Your app details field is significantly underutilized. This is the most impactful field for conversions.",
                                    "priority": 1,
                                    "current_value": "320 chars",
                                    "target_value": "500 chars",
                                    "link_to": "/suggestions/listings"
                                }
                            ]
                        ],
                        "items": {
                            "type": "object",
                            "additionalProperties": {}
                        }
                    },
                    "competitor_comparison": {
                        "type": "array",
                        "description": "Head-to-head comparison against each followed competitor (empty when\nnone are followed). Each item: `id`, `name`, `slug`, `logo_url`, a\n`metrics` map (rating|reviews|keywords|categories|estInstalls \u2192\n{yours, theirs, winner:\"you\"|\"them\"|\"tie\"}) and `winsCount` (0\u20135).",
                        "examples": [
                            [
                                {
                                    "id": 4471,
                                    "name": "Stocky",
                                    "slug": "stocky",
                                    "logo_url": "https://cdn.shopify.com/app-store/listing/stocky/icon.png",
                                    "metrics": {
                                        "rating": {
                                            "yours": 4.7,
                                            "theirs": 4.5,
                                            "winner": "you"
                                        },
                                        "reviews": {
                                            "yours": 312,
                                            "theirs": 540,
                                            "winner": "them"
                                        },
                                        "keywords": {
                                            "yours": 41,
                                            "theirs": 38,
                                            "winner": "you"
                                        },
                                        "categories": {
                                            "yours": 4,
                                            "theirs": 3,
                                            "winner": "you"
                                        },
                                        "estInstalls": {
                                            "yours": 5200,
                                            "theirs": 9100,
                                            "winner": "them"
                                        }
                                    },
                                    "winsCount": 3
                                }
                            ]
                        ],
                        "items": {
                            "type": "object",
                            "additionalProperties": {}
                        }
                    }
                },
                "required": [
                    "object",
                    "overall_score",
                    "listing_quality",
                    "keyword_performance",
                    "reviews_reputation",
                    "visibility",
                    "is_provisional",
                    "computed_at",
                    "improvement_opportunities",
                    "competitor_comparison"
                ],
                "title": "ScorecardResource"
            },
            "ShopifyAppCatalogResource": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string"
                    },
                    "token": {
                        "type": "string"
                    },
                    "platform": {
                        "type": "string",
                        "const": "shopify"
                    },
                    "name": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "description": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "state": {
                        "type": "string",
                        "enum": [
                            "Active",
                            "Delisted",
                            "Deleted"
                        ]
                    },
                    "categories": {
                        "type": "object",
                        "additionalProperties": {}
                    },
                    "plans": {
                        "type": "array",
                        "items": {}
                    },
                    "installs": {
                        "type": [
                            "integer",
                            "null"
                        ]
                    },
                    "installs_30d": {
                        "type": "null"
                    },
                    "installs_90d": {
                        "type": "null"
                    },
                    "review_count": {
                        "type": "integer"
                    },
                    "reviews_30d": {
                        "type": "null"
                    },
                    "reviews_90d": {
                        "type": "null"
                    },
                    "average_rating": {
                        "type": [
                            "number",
                            "null"
                        ]
                    },
                    "vendor_name": {
                        "type": "string"
                    },
                    "vendor_email": {
                        "type": "null"
                    },
                    "vendor_website": {
                        "type": "string"
                    },
                    "app_store_url": {
                        "type": "string"
                    },
                    "icon_url": {
                        "type": "string"
                    },
                    "created_at": {
                        "type": "string"
                    },
                    "free_trial_days": {
                        "type": [
                            "integer",
                            "null"
                        ]
                    }
                },
                "required": [
                    "id",
                    "token",
                    "platform",
                    "name",
                    "description",
                    "state",
                    "installs",
                    "installs_30d",
                    "installs_90d",
                    "review_count",
                    "reviews_30d",
                    "reviews_90d",
                    "average_rating",
                    "vendor_email",
                    "app_store_url",
                    "icon_url",
                    "created_at"
                ],
                "title": "ShopifyAppCatalogResource"
            },
            "SubscriptionResource": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "Stable subscription id (primary key) \u2014 use this for MERGE / dedup.",
                        "examples": [
                            "48217"
                        ]
                    },
                    "shop": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "The merchant's .myshopify.com domain, or null when the shop is not resolved.",
                        "examples": [
                            "acme-store.myshopify.com"
                        ]
                    },
                    "plan": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Plan name as billed on Shopify, or null when unnamed.",
                        "examples": [
                            "Pro"
                        ]
                    },
                    "status": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Subscription status (active | cancelled | declined | expired | frozen).",
                        "examples": [
                            "active"
                        ]
                    },
                    "amount": {
                        "type": "number",
                        "description": "Recurring charge amount in the subscription's currency.",
                        "examples": [
                            19
                        ]
                    },
                    "currency": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "ISO 4217 currency code for `amount`, or null when not captured.",
                        "examples": [
                            "USD"
                        ]
                    },
                    "billing_interval": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Billing interval as reported by Shopify (e.g. EVERY_30_DAYS / ANNUAL), or null.",
                        "examples": [
                            "EVERY_30_DAYS"
                        ]
                    },
                    "activated_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "When the subscription was activated (ISO-8601), or null.",
                        "examples": [
                            "2026-01-14T09:32:11+00:00"
                        ]
                    },
                    "cancelled_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "When the subscription was cancelled (ISO-8601), or null when still active.",
                        "examples": [
                            "2026-04-02T18:10:55+00:00"
                        ]
                    },
                    "created_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "When Ranksy first recorded the row (ISO-8601), or null.",
                        "examples": [
                            "2026-01-14T09:35:00+00:00"
                        ]
                    }
                },
                "required": [
                    "id",
                    "shop",
                    "plan",
                    "status",
                    "amount",
                    "currency",
                    "billing_interval",
                    "activated_at",
                    "cancelled_at",
                    "created_at"
                ],
                "title": "SubscriptionResource"
            },
            "SubscriptionsCollection": {
                "type": "object",
                "properties": {
                    "object": {
                        "type": "string",
                        "description": "Always the literal string `list` \u2014 the envelope-type discriminator.",
                        "const": "list",
                        "examples": [
                            "list"
                        ]
                    },
                    "url": {
                        "type": "string",
                        "description": "Path of this list resource.",
                        "examples": [
                            "/api/v1/apps/01JN4HKQX0000000000000000/reviews"
                        ]
                    },
                    "currency": {
                        "type": "string",
                        "description": "Base-currency ISO code (ISO 4217), present only on money series and\ndeclared once for every row in data.",
                        "examples": [
                            "USD"
                        ]
                    },
                    "page": {
                        "type": "integer",
                        "description": "Current page number (1-based).",
                        "examples": [
                            1
                        ]
                    },
                    "per_page": {
                        "type": "integer",
                        "description": "Rows per page.",
                        "examples": [
                            50
                        ]
                    },
                    "total_count": {
                        "type": "integer",
                        "description": "Total rows across every page.",
                        "examples": [
                            128
                        ]
                    },
                    "has_more": {
                        "type": "boolean",
                        "description": "Whether more pages follow this one.",
                        "examples": [
                            true
                        ]
                    },
                    "coverage": {
                        "type": "object",
                        "description": "Requested vs actually-covered date window for the series. Present on\ndate-windowed series only. `requested` echoes the asked-for range;\n`available` is the range actually covered by data, or null when\nnothing fell in range.",
                        "examples": [
                            {
                                "requested": {
                                    "start": "2026-05-01",
                                    "end": "2026-05-31"
                                },
                                "available": {
                                    "start": "2026-05-01",
                                    "end": "2026-05-28"
                                }
                            }
                        ],
                        "properties": {
                            "requested": {
                                "type": "object",
                                "properties": {
                                    "start": {
                                        "type": "string"
                                    },
                                    "end": {
                                        "type": "string"
                                    }
                                },
                                "required": [
                                    "start",
                                    "end"
                                ]
                            },
                            "available": {
                                "type": [
                                    "object",
                                    "null"
                                ],
                                "properties": {
                                    "start": {
                                        "type": "string"
                                    },
                                    "end": {
                                        "type": "string"
                                    }
                                },
                                "required": [
                                    "start",
                                    "end"
                                ]
                            }
                        },
                        "required": [
                            "requested",
                            "available"
                        ]
                    },
                    "metadata": {
                        "type": "object",
                        "description": "Endpoint-specific metadata \u2014 e.g. summary, echoed filters, or\nintegration sync status. Shape varies by endpoint.",
                        "examples": [
                            {
                                "partner_sync_status": "complete"
                            }
                        ],
                        "additionalProperties": {}
                    },
                    "data": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/SubscriptionResource"
                        }
                    }
                },
                "required": [
                    "object",
                    "url",
                    "page",
                    "per_page",
                    "total_count",
                    "has_more",
                    "data"
                ],
                "title": "SubscriptionsCollection"
            },
            "TrafficKeywordResource": {
                "type": "object",
                "properties": {
                    "keyword": {
                        "type": "string",
                        "description": "The search keyword.",
                        "examples": [
                            "email marketing"
                        ]
                    },
                    "organic_installs": {
                        "type": "integer",
                        "description": "Installs attributed to organic (non-sponsored) appearances for this keyword.",
                        "examples": [
                            34
                        ]
                    },
                    "organic_pageviews": {
                        "type": "integer",
                        "description": "Listing page views from organic (non-sponsored) appearances for this keyword.",
                        "examples": [
                            512
                        ]
                    },
                    "avg_organic_rank": {
                        "type": [
                            "number",
                            "null"
                        ],
                        "description": "Average organic search rank for this keyword (1 = top), or null when never ranked organically.",
                        "examples": [
                            4.2
                        ]
                    },
                    "ad_installs": {
                        "type": "integer",
                        "description": "Installs attributed to sponsored (ad) appearances for this keyword.",
                        "examples": [
                            9
                        ]
                    },
                    "ad_pageviews": {
                        "type": "integer",
                        "description": "Listing page views from sponsored (ad) appearances for this keyword.",
                        "examples": [
                            140
                        ]
                    },
                    "avg_ad_rank": {
                        "type": [
                            "number",
                            "null"
                        ],
                        "description": "Average sponsored (ad) search rank for this keyword (1 = top), or null when never shown as an ad.",
                        "examples": [
                            2
                        ]
                    },
                    "total_installs": {
                        "type": "integer",
                        "description": "Total installs attributed to this keyword (organic + ad).",
                        "examples": [
                            43
                        ]
                    },
                    "organic_share": {
                        "type": "number",
                        "description": "Organic share of this keyword's installs, as a percentage (42.5 = 42.5%).",
                        "examples": [
                            79.1
                        ]
                    },
                    "ad_share": {
                        "type": "number",
                        "description": "Ad share of this keyword's installs, as a percentage (42.5 = 42.5%).",
                        "examples": [
                            20.9
                        ]
                    }
                },
                "required": [
                    "keyword",
                    "organic_installs",
                    "organic_pageviews",
                    "avg_organic_rank",
                    "ad_installs",
                    "ad_pageviews",
                    "avg_ad_rank",
                    "total_installs",
                    "organic_share",
                    "ad_share"
                ],
                "title": "TrafficKeywordResource"
            },
            "TrafficKeywordsCollection": {
                "type": "object",
                "properties": {
                    "object": {
                        "type": "string",
                        "description": "Always the literal string `list` \u2014 the envelope-type discriminator.",
                        "const": "list",
                        "examples": [
                            "list"
                        ]
                    },
                    "url": {
                        "type": "string",
                        "description": "Path of this list resource.",
                        "examples": [
                            "/api/v1/apps/01JN4HKQX0000000000000000/reviews"
                        ]
                    },
                    "currency": {
                        "type": "string",
                        "description": "Base-currency ISO code (ISO 4217), present only on money series and\ndeclared once for every row in data.",
                        "examples": [
                            "USD"
                        ]
                    },
                    "page": {
                        "type": "integer",
                        "description": "Current page number (1-based).",
                        "examples": [
                            1
                        ]
                    },
                    "per_page": {
                        "type": "integer",
                        "description": "Rows per page.",
                        "examples": [
                            50
                        ]
                    },
                    "total_count": {
                        "type": "integer",
                        "description": "Total rows across every page.",
                        "examples": [
                            128
                        ]
                    },
                    "has_more": {
                        "type": "boolean",
                        "description": "Whether more pages follow this one.",
                        "examples": [
                            true
                        ]
                    },
                    "coverage": {
                        "type": "object",
                        "description": "Requested vs actually-covered date window for the series. Present on\ndate-windowed series only. `requested` echoes the asked-for range;\n`available` is the range actually covered by data, or null when\nnothing fell in range.",
                        "examples": [
                            {
                                "requested": {
                                    "start": "2026-05-01",
                                    "end": "2026-05-31"
                                },
                                "available": {
                                    "start": "2026-05-01",
                                    "end": "2026-05-28"
                                }
                            }
                        ],
                        "properties": {
                            "requested": {
                                "type": "object",
                                "properties": {
                                    "start": {
                                        "type": "string"
                                    },
                                    "end": {
                                        "type": "string"
                                    }
                                },
                                "required": [
                                    "start",
                                    "end"
                                ]
                            },
                            "available": {
                                "type": [
                                    "object",
                                    "null"
                                ],
                                "properties": {
                                    "start": {
                                        "type": "string"
                                    },
                                    "end": {
                                        "type": "string"
                                    }
                                },
                                "required": [
                                    "start",
                                    "end"
                                ]
                            }
                        },
                        "required": [
                            "requested",
                            "available"
                        ]
                    },
                    "metadata": {
                        "type": "object",
                        "description": "Endpoint-specific metadata \u2014 e.g. summary, echoed filters, or\nintegration sync status. Shape varies by endpoint.",
                        "examples": [
                            {
                                "partner_sync_status": "complete"
                            }
                        ],
                        "additionalProperties": {}
                    },
                    "data": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/TrafficKeywordResource"
                        }
                    }
                },
                "required": [
                    "object",
                    "url",
                    "page",
                    "per_page",
                    "total_count",
                    "has_more",
                    "data"
                ],
                "title": "TrafficKeywordsCollection"
            },
            "TrafficSourcePointResource": {
                "type": "object",
                "properties": {
                    "start_date": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Inclusive start date of this period (YYYY-MM-DD), or null when there are no periods.",
                        "examples": [
                            "2026-05-01"
                        ]
                    },
                    "end_date": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Inclusive end date of this period (YYYY-MM-DD), or null when there are no periods.",
                        "examples": [
                            "2026-05-07"
                        ]
                    },
                    "sessions": {
                        "type": "integer",
                        "description": "Total listing sessions in this period across all sources.",
                        "examples": [
                            1240
                        ]
                    },
                    "page_views": {
                        "type": "integer",
                        "description": "Total listing page views in this period across all sources.",
                        "examples": [
                            1985
                        ]
                    },
                    "installs": {
                        "type": "integer",
                        "description": "Total installs attributed in this period across all sources.",
                        "examples": [
                            38
                        ]
                    },
                    "sources": {
                        "type": "array",
                        "description": "Classified per-source breakdown for this period.",
                        "examples": [
                            [
                                {
                                    "source": "Shopify App Store search",
                                    "sessions": 720,
                                    "installs": 22,
                                    "percentage": 57.9
                                }
                            ]
                        ],
                        "items": {
                            "type": "object",
                            "properties": {
                                "source": {
                                    "type": "string"
                                },
                                "sessions": {
                                    "type": "integer"
                                },
                                "installs": {
                                    "type": "integer"
                                },
                                "percentage": {
                                    "type": "number"
                                }
                            },
                            "required": [
                                "source",
                                "sessions",
                                "installs",
                                "percentage"
                            ]
                        }
                    }
                },
                "required": [
                    "start_date",
                    "end_date",
                    "sessions",
                    "page_views",
                    "installs",
                    "sources"
                ],
                "title": "TrafficSourcePointResource"
            },
            "TrafficSourcesCollection": {
                "type": "object",
                "properties": {
                    "object": {
                        "type": "string",
                        "description": "Always the literal string `list` \u2014 the envelope-type discriminator.",
                        "const": "list",
                        "examples": [
                            "list"
                        ]
                    },
                    "url": {
                        "type": "string",
                        "description": "Path of this list resource.",
                        "examples": [
                            "/api/v1/apps/01JN4HKQX0000000000000000/reviews"
                        ]
                    },
                    "currency": {
                        "type": "string",
                        "description": "Base-currency ISO code (ISO 4217), present only on money series and\ndeclared once for every row in data.",
                        "examples": [
                            "USD"
                        ]
                    },
                    "page": {
                        "type": "integer",
                        "description": "Current page number (1-based).",
                        "examples": [
                            1
                        ]
                    },
                    "per_page": {
                        "type": "integer",
                        "description": "Rows per page.",
                        "examples": [
                            50
                        ]
                    },
                    "total_count": {
                        "type": "integer",
                        "description": "Total rows across every page.",
                        "examples": [
                            128
                        ]
                    },
                    "has_more": {
                        "type": "boolean",
                        "description": "Whether more pages follow this one.",
                        "examples": [
                            true
                        ]
                    },
                    "coverage": {
                        "type": "object",
                        "description": "Requested vs actually-covered date window for the series. Present on\ndate-windowed series only. `requested` echoes the asked-for range;\n`available` is the range actually covered by data, or null when\nnothing fell in range.",
                        "examples": [
                            {
                                "requested": {
                                    "start": "2026-05-01",
                                    "end": "2026-05-31"
                                },
                                "available": {
                                    "start": "2026-05-01",
                                    "end": "2026-05-28"
                                }
                            }
                        ],
                        "properties": {
                            "requested": {
                                "type": "object",
                                "properties": {
                                    "start": {
                                        "type": "string"
                                    },
                                    "end": {
                                        "type": "string"
                                    }
                                },
                                "required": [
                                    "start",
                                    "end"
                                ]
                            },
                            "available": {
                                "type": [
                                    "object",
                                    "null"
                                ],
                                "properties": {
                                    "start": {
                                        "type": "string"
                                    },
                                    "end": {
                                        "type": "string"
                                    }
                                },
                                "required": [
                                    "start",
                                    "end"
                                ]
                            }
                        },
                        "required": [
                            "requested",
                            "available"
                        ]
                    },
                    "metadata": {
                        "type": "object",
                        "description": "Endpoint-specific metadata \u2014 e.g. summary, echoed filters, or\nintegration sync status. Shape varies by endpoint.",
                        "examples": [
                            {
                                "partner_sync_status": "complete"
                            }
                        ],
                        "additionalProperties": {}
                    },
                    "data": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/TrafficSourcePointResource"
                        }
                    }
                },
                "required": [
                    "object",
                    "url",
                    "page",
                    "per_page",
                    "total_count",
                    "has_more",
                    "data"
                ],
                "title": "TrafficSourcesCollection"
            },
            "TransactionResource": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "Stable transaction id (primary key) \u2014 use this for MERGE / dedup.",
                        "examples": [
                            "9912034"
                        ]
                    },
                    "type": {
                        "type": "string",
                        "description": "Raw Partner transaction type.",
                        "examples": [
                            "APP_SUBSCRIPTION_SALE"
                        ]
                    },
                    "type_label": {
                        "type": "string",
                        "description": "Human-readable label for `type`.",
                        "examples": [
                            "Subscription sale"
                        ]
                    },
                    "shop": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "The merchant's .myshopify.com domain, or null when not resolved.",
                        "examples": [
                            "acme-store.myshopify.com"
                        ]
                    },
                    "amount": {
                        "type": "number",
                        "description": "Gross transaction amount (alias of gross_amount), in the row's currency.",
                        "examples": [
                            19
                        ]
                    },
                    "gross_amount": {
                        "type": "number",
                        "description": "Gross amount before Shopify's revenue share, in the row's currency.",
                        "examples": [
                            19
                        ]
                    },
                    "net_amount": {
                        "type": "number",
                        "description": "Net payout after Shopify's revenue share, in the row's currency.",
                        "examples": [
                            15.2
                        ]
                    },
                    "shopify_fee": {
                        "type": "number",
                        "description": "Shopify's revenue-share cut (gross \u2212 net), in the row's currency.",
                        "examples": [
                            3.8
                        ]
                    },
                    "currency": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "ISO 4217 currency code for the amounts, or null when not captured.",
                        "examples": [
                            "USD"
                        ]
                    },
                    "processed_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "When Shopify processed the transaction (ISO-8601), or null.",
                        "examples": [
                            "2026-05-01T00:00:00+00:00"
                        ]
                    },
                    "created_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "When Ranksy first recorded the row (ISO-8601), or null.",
                        "examples": [
                            "2026-05-01T04:12:00+00:00"
                        ]
                    }
                },
                "required": [
                    "id",
                    "type",
                    "type_label",
                    "shop",
                    "amount",
                    "gross_amount",
                    "net_amount",
                    "shopify_fee",
                    "currency",
                    "processed_at",
                    "created_at"
                ],
                "title": "TransactionResource"
            },
            "TransactionsCollection": {
                "type": "object",
                "properties": {
                    "object": {
                        "type": "string",
                        "description": "Always the literal string `list` \u2014 the envelope-type discriminator.",
                        "const": "list",
                        "examples": [
                            "list"
                        ]
                    },
                    "url": {
                        "type": "string",
                        "description": "Path of this list resource.",
                        "examples": [
                            "/api/v1/apps/01JN4HKQX0000000000000000/reviews"
                        ]
                    },
                    "currency": {
                        "type": "string",
                        "description": "Base-currency ISO code (ISO 4217), present only on money series and\ndeclared once for every row in data.",
                        "examples": [
                            "USD"
                        ]
                    },
                    "page": {
                        "type": "integer",
                        "description": "Current page number (1-based).",
                        "examples": [
                            1
                        ]
                    },
                    "per_page": {
                        "type": "integer",
                        "description": "Rows per page.",
                        "examples": [
                            50
                        ]
                    },
                    "total_count": {
                        "type": "integer",
                        "description": "Total rows across every page.",
                        "examples": [
                            128
                        ]
                    },
                    "has_more": {
                        "type": "boolean",
                        "description": "Whether more pages follow this one.",
                        "examples": [
                            true
                        ]
                    },
                    "coverage": {
                        "type": "object",
                        "description": "Requested vs actually-covered date window for the series. Present on\ndate-windowed series only. `requested` echoes the asked-for range;\n`available` is the range actually covered by data, or null when\nnothing fell in range.",
                        "examples": [
                            {
                                "requested": {
                                    "start": "2026-05-01",
                                    "end": "2026-05-31"
                                },
                                "available": {
                                    "start": "2026-05-01",
                                    "end": "2026-05-28"
                                }
                            }
                        ],
                        "properties": {
                            "requested": {
                                "type": "object",
                                "properties": {
                                    "start": {
                                        "type": "string"
                                    },
                                    "end": {
                                        "type": "string"
                                    }
                                },
                                "required": [
                                    "start",
                                    "end"
                                ]
                            },
                            "available": {
                                "type": [
                                    "object",
                                    "null"
                                ],
                                "properties": {
                                    "start": {
                                        "type": "string"
                                    },
                                    "end": {
                                        "type": "string"
                                    }
                                },
                                "required": [
                                    "start",
                                    "end"
                                ]
                            }
                        },
                        "required": [
                            "requested",
                            "available"
                        ]
                    },
                    "metadata": {
                        "type": "object",
                        "description": "Endpoint-specific metadata \u2014 e.g. summary, echoed filters, or\nintegration sync status. Shape varies by endpoint.",
                        "examples": [
                            {
                                "partner_sync_status": "complete"
                            }
                        ],
                        "additionalProperties": {}
                    },
                    "data": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/TransactionResource"
                        }
                    }
                },
                "required": [
                    "object",
                    "url",
                    "page",
                    "per_page",
                    "total_count",
                    "has_more",
                    "data"
                ],
                "title": "TransactionsCollection"
            }
        },
        "responses": {
            "ValidationException": {
                "description": "Validation error",
                "content": {
                    "application/json": {
                        "schema": {
                            "type": "object",
                            "properties": {
                                "message": {
                                    "type": "string",
                                    "description": "Errors overview."
                                },
                                "errors": {
                                    "type": "object",
                                    "description": "A detailed description of each field that failed validation.",
                                    "additionalProperties": {
                                        "type": "array",
                                        "items": {
                                            "type": "string"
                                        }
                                    }
                                }
                            },
                            "required": [
                                "message",
                                "errors"
                            ]
                        }
                    }
                }
            },
            "AuthenticationException": {
                "description": "Unauthenticated",
                "content": {
                    "application/json": {
                        "schema": {
                            "type": "object",
                            "properties": {
                                "message": {
                                    "type": "string",
                                    "description": "Error overview."
                                }
                            },
                            "required": [
                                "message"
                            ]
                        }
                    }
                }
            },
            "ModelNotFoundException": {
                "description": "Not found",
                "content": {
                    "application/json": {
                        "schema": {
                            "type": "object",
                            "properties": {
                                "message": {
                                    "type": "string",
                                    "description": "Error overview."
                                }
                            },
                            "required": [
                                "message"
                            ]
                        }
                    }
                }
            }
        }
    }
}