openapi: 3.1.0
info:
  title: ConsumerPricesService API
  version: 1.0.0
security:
  - WorldMonitorKey: []
  - ApiKeyHeader: []
servers:
  - url: https://api.worldmonitor.app
paths:
  /api/consumer-prices/v1/get-consumer-price-overview:
    get:
      tags:
        - ConsumerPricesService
      summary: GetConsumerPriceOverview
      description: >-
        GetConsumerPriceOverview retrieves headline basket indices and coverage
        metrics.
      operationId: GetConsumerPriceOverview
      parameters:
        - name: market_code
          in: query
          description: market_code is the ISO 3166-1 alpha-2 market identifier (e.g. "ae").
          required: false
          example: US
          schema:
            type: string
        - name: basket_slug
          in: query
          description: basket_slug selects which basket to use (e.g. "essentials-ae").
          required: false
          example: essentials-ae
          schema:
            type: string
        - name: jmespath
          in: query
          description: >-
            Optional JMESPath expression applied server-side to project or
            reduce the JSON response before it is returned (mirrors the MCP
            jmespath argument). Invalid expressions, expressions larger than
            1024 UTF-8 bytes, or projections that exceed the 256 KB output cap
            return HTTP 400 with a {_jmespath_error, original_keys} envelope.
            Grammar and worked examples:
            https://www.worldmonitor.app/docs/mcp-jmespath.
          required: false
          example: keys(@)
          schema:
            type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              example:
                asOf: '1717200000000'
                coveragePct: 1.5
                currencyCode: USD
                essentialsIndex: 1.5
                freshnessLagMin: 1
              schema:
                $ref: '#/components/schemas/GetConsumerPriceOverviewResponse'
        '400':
          description: Validation error
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/ValidationError'
                  - $ref: '#/components/schemas/JmespathProjectionError'
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedError'
        '403':
          description: >-
            API access requires an active subscription (the API key's
            subscription is inactive or expired).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenError'
        '429':
          description: Rate limit exceeded.
          headers:
            X-RateLimit-Limit:
              description: Maximum requests allowed in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Remaining:
              description: Requests remaining in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Reset:
              description: >-
                Unix epoch milliseconds when the active rate-limit window
                resets.
              schema:
                type: string
            Retry-After:
              description: Seconds to wait before retrying the request.
              schema:
                type: string
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/RateLimitError'
        default:
          description: Gateway or handler error response.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/GatewayError'
  /api/consumer-prices/v1/get-consumer-price-basket-series:
    get:
      tags:
        - ConsumerPricesService
      summary: GetConsumerPriceBasketSeries
      description: GetConsumerPriceBasketSeries retrieves the basket index time series.
      operationId: GetConsumerPriceBasketSeries
      parameters:
        - name: market_code
          in: query
          description: market_code is the ISO 3166-1 alpha-2 market identifier.
          required: false
          example: US
          schema:
            type: string
        - name: basket_slug
          in: query
          description: basket_slug selects the basket (e.g. "essentials-ae").
          required: false
          example: essentials-ae
          schema:
            type: string
        - name: range
          in: query
          description: range is one of "7d", "30d", "90d", "180d".
          required: false
          example: 7d
          schema:
            type: string
        - name: jmespath
          in: query
          description: >-
            Optional JMESPath expression applied server-side to project or
            reduce the JSON response before it is returned (mirrors the MCP
            jmespath argument). Invalid expressions, expressions larger than
            1024 UTF-8 bytes, or projections that exceed the 256 KB output cap
            return HTTP 400 with a {_jmespath_error, original_keys} envelope.
            Grammar and worked examples:
            https://www.worldmonitor.app/docs/mcp-jmespath.
          required: false
          example: keys(@)
          schema:
            type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              example:
                asOf: '1717200000000'
                basketSlug: essentials-ae
                currencyCode: USD
                essentialsSeries:
                  - date: '2026-01-15'
                    index: 1.5
                marketCode: US
              schema:
                $ref: '#/components/schemas/GetConsumerPriceBasketSeriesResponse'
        '400':
          description: Validation error
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/ValidationError'
                  - $ref: '#/components/schemas/JmespathProjectionError'
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedError'
        '403':
          description: >-
            API access requires an active subscription (the API key's
            subscription is inactive or expired).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenError'
        '429':
          description: Rate limit exceeded.
          headers:
            X-RateLimit-Limit:
              description: Maximum requests allowed in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Remaining:
              description: Requests remaining in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Reset:
              description: >-
                Unix epoch milliseconds when the active rate-limit window
                resets.
              schema:
                type: string
            Retry-After:
              description: Seconds to wait before retrying the request.
              schema:
                type: string
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/RateLimitError'
        default:
          description: Gateway or handler error response.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/GatewayError'
  /api/consumer-prices/v1/list-consumer-price-categories:
    get:
      tags:
        - ConsumerPricesService
      summary: ListConsumerPriceCategories
      description: >-
        ListConsumerPriceCategories retrieves category summaries with
        sparklines.
      operationId: ListConsumerPriceCategories
      parameters:
        - name: market_code
          in: query
          description: market_code is the ISO 3166-1 alpha-2 market identifier.
          required: false
          example: US
          schema:
            type: string
        - name: basket_slug
          in: query
          description: basket_slug selects the basket scope.
          required: false
          example: essentials-ae
          schema:
            type: string
        - name: range
          in: query
          description: range is one of "7d", "30d", "90d", "180d".
          required: false
          example: 7d
          schema:
            type: string
        - name: jmespath
          in: query
          description: >-
            Optional JMESPath expression applied server-side to project or
            reduce the JSON response before it is returned (mirrors the MCP
            jmespath argument). Invalid expressions, expressions larger than
            1024 UTF-8 bytes, or projections that exceed the 256 KB output cap
            return HTTP 400 with a {_jmespath_error, original_keys} envelope.
            Grammar and worked examples:
            https://www.worldmonitor.app/docs/mcp-jmespath.
          required: false
          example: keys(@)
          schema:
            type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              example:
                asOf: '1717200000000'
                categories:
                  - coveragePct: 1.5
                    currentIndex: 1.5
                    itemCount: 1
                    momPct: 1.5
                    name: WorldMonitor Analyst
                marketCode: US
                range: 7d
                upstreamUnavailable: true
              schema:
                $ref: '#/components/schemas/ListConsumerPriceCategoriesResponse'
        '400':
          description: Validation error
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/ValidationError'
                  - $ref: '#/components/schemas/JmespathProjectionError'
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedError'
        '403':
          description: >-
            API access requires an active subscription (the API key's
            subscription is inactive or expired).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenError'
        '429':
          description: Rate limit exceeded.
          headers:
            X-RateLimit-Limit:
              description: Maximum requests allowed in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Remaining:
              description: Requests remaining in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Reset:
              description: >-
                Unix epoch milliseconds when the active rate-limit window
                resets.
              schema:
                type: string
            Retry-After:
              description: Seconds to wait before retrying the request.
              schema:
                type: string
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/RateLimitError'
        default:
          description: Gateway or handler error response.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/GatewayError'
  /api/consumer-prices/v1/list-consumer-price-movers:
    get:
      tags:
        - ConsumerPricesService
      summary: ListConsumerPriceMovers
      description: >-
        ListConsumerPriceMovers retrieves the largest upward and downward item
        price moves.
      operationId: ListConsumerPriceMovers
      parameters:
        - name: market_code
          in: query
          description: market_code is the ISO 3166-1 alpha-2 market identifier.
          required: false
          example: US
          schema:
            type: string
        - name: range
          in: query
          description: range is one of "7d", "30d", "90d".
          required: false
          example: 7d
          schema:
            type: string
        - name: limit
          in: query
          description: limit caps the number of risers and fallers returned.
          required: true
          example: 25
          schema:
            type: integer
            format: int32
        - name: category_slug
          in: query
          description: category_slug filters to a single category when set.
          required: false
          example: cs.AI
          schema:
            type: string
        - name: jmespath
          in: query
          description: >-
            Optional JMESPath expression applied server-side to project or
            reduce the JSON response before it is returned (mirrors the MCP
            jmespath argument). Invalid expressions, expressions larger than
            1024 UTF-8 bytes, or projections that exceed the 256 KB output cap
            return HTTP 400 with a {_jmespath_error, original_keys} envelope.
            Grammar and worked examples:
            https://www.worldmonitor.app/docs/mcp-jmespath.
          required: false
          example: keys(@)
          schema:
            type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              example:
                asOf: '1717200000000'
                fallers:
                  - category: cs.AI
                    changePct: 1.5
                    currencyCode: USD
                    currentPrice: 75.25
                    productId: diesel
                marketCode: US
                range: 7d
                risers:
                  - category: cs.AI
                    changePct: 1.5
                    currencyCode: USD
                    currentPrice: 75.25
                    productId: diesel
              schema:
                $ref: '#/components/schemas/ListConsumerPriceMoversResponse'
        '400':
          description: Validation error
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/ValidationError'
                  - $ref: '#/components/schemas/JmespathProjectionError'
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedError'
        '403':
          description: >-
            API access requires an active subscription (the API key's
            subscription is inactive or expired).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenError'
        '429':
          description: Rate limit exceeded.
          headers:
            X-RateLimit-Limit:
              description: Maximum requests allowed in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Remaining:
              description: Requests remaining in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Reset:
              description: >-
                Unix epoch milliseconds when the active rate-limit window
                resets.
              schema:
                type: string
            Retry-After:
              description: Seconds to wait before retrying the request.
              schema:
                type: string
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/RateLimitError'
        default:
          description: Gateway or handler error response.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/GatewayError'
  /api/consumer-prices/v1/list-retailer-price-spreads:
    get:
      tags:
        - ConsumerPricesService
      summary: ListRetailerPriceSpreads
      description: >-
        ListRetailerPriceSpreads retrieves cheapest-basket comparisons across
        retailers.
      operationId: ListRetailerPriceSpreads
      parameters:
        - name: market_code
          in: query
          description: market_code is the ISO 3166-1 alpha-2 market identifier.
          required: false
          example: US
          schema:
            type: string
        - name: basket_slug
          in: query
          description: basket_slug selects which basket to compare across retailers.
          required: false
          example: essentials-ae
          schema:
            type: string
        - name: jmespath
          in: query
          description: >-
            Optional JMESPath expression applied server-side to project or
            reduce the JSON response before it is returned (mirrors the MCP
            jmespath argument). Invalid expressions, expressions larger than
            1024 UTF-8 bytes, or projections that exceed the 256 KB output cap
            return HTTP 400 with a {_jmespath_error, original_keys} envelope.
            Grammar and worked examples:
            https://www.worldmonitor.app/docs/mcp-jmespath.
          required: false
          example: keys(@)
          schema:
            type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              example:
                asOf: '1717200000000'
                basketSlug: essentials-ae
                currencyCode: USD
                marketCode: US
                retailers:
                  - basketTotal: 1
                    currencyCode: USD
                    deltaVsCheapest: 1.5
                    deltaVsCheapestPct: 1.5
                    freshnessMin: 1
              schema:
                $ref: '#/components/schemas/ListRetailerPriceSpreadsResponse'
        '400':
          description: Validation error
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/ValidationError'
                  - $ref: '#/components/schemas/JmespathProjectionError'
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedError'
        '403':
          description: >-
            API access requires an active subscription (the API key's
            subscription is inactive or expired).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenError'
        '429':
          description: Rate limit exceeded.
          headers:
            X-RateLimit-Limit:
              description: Maximum requests allowed in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Remaining:
              description: Requests remaining in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Reset:
              description: >-
                Unix epoch milliseconds when the active rate-limit window
                resets.
              schema:
                type: string
            Retry-After:
              description: Seconds to wait before retrying the request.
              schema:
                type: string
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/RateLimitError'
        default:
          description: Gateway or handler error response.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/GatewayError'
  /api/consumer-prices/v1/get-consumer-price-freshness:
    get:
      tags:
        - ConsumerPricesService
      summary: GetConsumerPriceFreshness
      description: >-
        GetConsumerPriceFreshness retrieves feed freshness and coverage health
        per retailer.
      operationId: GetConsumerPriceFreshness
      parameters:
        - name: market_code
          in: query
          description: market_code is the ISO 3166-1 alpha-2 market identifier.
          required: false
          example: US
          schema:
            type: string
        - name: jmespath
          in: query
          description: >-
            Optional JMESPath expression applied server-side to project or
            reduce the JSON response before it is returned (mirrors the MCP
            jmespath argument). Invalid expressions, expressions larger than
            1024 UTF-8 bytes, or projections that exceed the 256 KB output cap
            return HTTP 400 with a {_jmespath_error, original_keys} envelope.
            Grammar and worked examples:
            https://www.worldmonitor.app/docs/mcp-jmespath.
          required: false
          example: keys(@)
          schema:
            type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              example:
                asOf: '1717200000000'
                marketCode: US
                overallFreshnessMin: 1
                retailers:
                  - freshnessMin: 1
                    lastRunAt: '1717200000000'
                    name: WorldMonitor Analyst
                    parseSuccessRate: 75.25
                    slug: example
                stalledCount: 1
              schema:
                $ref: '#/components/schemas/GetConsumerPriceFreshnessResponse'
        '400':
          description: Validation error
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/ValidationError'
                  - $ref: '#/components/schemas/JmespathProjectionError'
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedError'
        '403':
          description: >-
            API access requires an active subscription (the API key's
            subscription is inactive or expired).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenError'
        '429':
          description: Rate limit exceeded.
          headers:
            X-RateLimit-Limit:
              description: Maximum requests allowed in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Remaining:
              description: Requests remaining in the active rate-limit window.
              schema:
                type: string
            X-RateLimit-Reset:
              description: >-
                Unix epoch milliseconds when the active rate-limit window
                resets.
              schema:
                type: string
            Retry-After:
              description: Seconds to wait before retrying the request.
              schema:
                type: string
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/RateLimitError'
        default:
          description: Gateway or handler error response.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/Error'
                  - $ref: '#/components/schemas/GatewayError'
components:
  securitySchemes:
    WorldMonitorKey:
      type: apiKey
      in: header
      name: X-WorldMonitor-Key
      description: User-issued WorldMonitor API key.
    ApiKeyHeader:
      type: apiKey
      in: header
      name: X-Api-Key
      description: Alias header for the WorldMonitor API key (X-WorldMonitor-Key).
  schemas:
    JmespathProjectionError:
      description: >-
        Returned when a REST jmespath projection is invalid or exceeds the
        expression/output byte limits.
      properties:
        _jmespath_error:
          description: Projection error discriminator and details.
          type: string
        original_keys:
          description: Top-level keys or shape of the unprojected response.
          items:
            type: string
          type: array
      required:
        - _jmespath_error
        - original_keys
      type: object
    UnauthorizedError:
      type: object
      properties:
        error:
          type: string
          description: Human-readable error message.
      required:
        - error
      description: >-
        Returned when the API key is missing, malformed, or lacks current API
        access.
    Error:
      type: object
      properties:
        message:
          type: string
          description: Error message (e.g., 'user not found', 'database connection failed')
      description: >-
        Error is returned when a handler encounters an error. It contains a
        simple error message that the developer can customize.
    InvalidRequestBodyError:
      type: object
      description: Returned when a JSON POST request body is empty or malformed.
      properties:
        message:
          type: string
          description: Invalid request body
      required:
        - message
    GatewayError:
      type: object
      description: >-
        Returned by gateway infrastructure errors before an RPC handler runs,
        such as origin, routing, method, authentication, or quota checks.
      properties:
        error:
          oneOf:
            - type: string
            - type: object
              additionalProperties: true
          description: Gateway error reason or structured gateway failure details.
      required:
        - error
    RateLimitError:
      type: object
      description: Returned when a gateway or handler rate limit rejects the request.
      properties:
        error:
          type: string
          description: Human-readable rate-limit failure reason.
      required:
        - error
    ForbiddenError:
      type: object
      properties:
        error:
          type: string
          description: Human-readable entitlement failure reason.
        requiredTier:
          type: integer
          format: int32
          description: Minimum entitlement tier required for this endpoint.
        currentTier:
          type: integer
          format: int32
          description: Caller entitlement tier when known.
        planKey:
          type: string
          description: Caller plan key when known.
      required:
        - error
      description: >-
        Returned when a PRO-gated endpoint denies access because the caller has
        no resolved authenticated user, entitlements cannot be verified, or the
        caller lacks the required entitlement tier.
    FieldViolation:
      type: object
      properties:
        field:
          type: string
          description: >-
            The field path that failed validation (e.g., 'user.email' for nested
            fields). For header validation, this will be the header name (e.g.,
            'X-API-Key')
        description:
          type: string
          description: >-
            Human-readable description of the validation violation (e.g., 'must
            be a valid email address', 'required field missing')
      required:
        - field
        - description
      description: FieldViolation describes a single validation error for a specific field.
    ValidationError:
      type: object
      properties:
        violations:
          type: array
          items:
            $ref: '#/components/schemas/FieldViolation'
          description: List of validation violations
      required:
        - violations
      description: >-
        ValidationError is returned when request validation fails. It contains a
        list of field violations describing what went wrong.
    GetConsumerPriceOverviewRequest:
      type: object
      properties:
        marketCode:
          type: string
          description: market_code is the ISO 3166-1 alpha-2 market identifier (e.g. "ae").
        basketSlug:
          type: string
          description: basket_slug selects which basket to use (e.g. "essentials-ae").
      description: GetConsumerPriceOverviewRequest parameters for the overview RPC.
    GetConsumerPriceOverviewResponse:
      type: object
      properties:
        marketCode:
          type: string
          description: market_code echoes the requested market.
        asOf:
          type: string
          format: int64
          description: as_of is the Unix millisecond timestamp of the snapshot.
        currencyCode:
          type: string
          description: currency_code is the ISO 4217 currency for price values.
        essentialsIndex:
          type: number
          format: double
          description: essentials_index is the fixed basket index value (base = 100).
        valueBasketIndex:
          type: number
          format: double
          description: value_basket_index is the value basket index value (base = 100).
        wowPct:
          type: number
          format: double
          description: >-
            wow_pct is the week-over-week percentage change in the essentials
            index.
        momPct:
          type: number
          format: double
          description: >-
            mom_pct is the month-over-month percentage change in the essentials
            index.
        retailerSpreadPct:
          type: number
          format: double
          description: >-
            retailer_spread_pct is the basket cost spread between cheapest and
            most expensive retailer.
        coveragePct:
          type: number
          format: double
          description: >-
            coverage_pct is the fraction of basket items with current
            observations.
        freshnessLagMin:
          type: integer
          format: int32
          description: >-
            freshness_lag_min is the average minutes since last observation
            across all retailers.
        topCategories:
          type: array
          items:
            $ref: '#/components/schemas/CategorySnapshot'
        upstreamUnavailable:
          type: boolean
          description: >-
            upstream_unavailable is true when the companion service could not be
            reached.
      description: >-
        GetConsumerPriceOverviewResponse contains headline basket and coverage
        metrics.
    CategorySnapshot:
      type: object
      properties:
        slug:
          type: string
          description: >-
            slug is the machine-readable category identifier (e.g. "eggs",
            "rice").
        name:
          type: string
          description: name is the human-readable category label.
        wowPct:
          type: number
          format: double
          description: wow_pct is the week-over-week percentage change.
        momPct:
          type: number
          format: double
          description: mom_pct is the month-over-month percentage change.
        currentIndex:
          type: number
          format: double
          description: current_index is the current price index value (base = 100).
        sparkline:
          type: array
          items:
            type: number
            format: double
            description: >-
              sparkline is an ordered sequence of index values for the selected
              range.
        coveragePct:
          type: number
          format: double
          description: >-
            coverage_pct is the percentage of basket items observed for this
            category.
        itemCount:
          type: integer
          format: int32
          description: item_count is the number of observed products in this category.
      description: CategorySnapshot holds price index data for a single product category.
    GetConsumerPriceBasketSeriesRequest:
      type: object
      properties:
        marketCode:
          type: string
          description: market_code is the ISO 3166-1 alpha-2 market identifier.
        basketSlug:
          type: string
          description: basket_slug selects the basket (e.g. "essentials-ae").
        range:
          type: string
          description: range is one of "7d", "30d", "90d", "180d".
      description: GetConsumerPriceBasketSeriesRequest parameters for time series data.
    GetConsumerPriceBasketSeriesResponse:
      type: object
      properties:
        marketCode:
          type: string
          description: market_code echoes the requested market.
        basketSlug:
          type: string
          description: basket_slug echoes the requested basket.
        asOf:
          type: string
          format: int64
          description: as_of is the Unix millisecond timestamp of the snapshot.
        currencyCode:
          type: string
          description: currency_code is the ISO 4217 currency code.
        range:
          type: string
          description: range echoes the requested range.
        essentialsSeries:
          type: array
          items:
            $ref: '#/components/schemas/BasketPoint'
        valueSeries:
          type: array
          items:
            $ref: '#/components/schemas/BasketPoint'
        upstreamUnavailable:
          type: boolean
          description: >-
            upstream_unavailable is true when the companion service could not be
            reached.
      description: >-
        GetConsumerPriceBasketSeriesResponse contains the basket index time
        series.
    BasketPoint:
      type: object
      properties:
        date:
          type: string
          description: date is the ISO 8601 date string (YYYY-MM-DD).
        index:
          type: number
          format: double
          description: index is the basket index value (base = 100).
      description: BasketPoint is a single data point in a basket index time series.
    ListConsumerPriceCategoriesRequest:
      type: object
      properties:
        marketCode:
          type: string
          description: market_code is the ISO 3166-1 alpha-2 market identifier.
        basketSlug:
          type: string
          description: basket_slug selects the basket scope.
        range:
          type: string
          description: range is one of "7d", "30d", "90d", "180d".
      description: ListConsumerPriceCategoriesRequest parameters for category listing.
    ListConsumerPriceCategoriesResponse:
      type: object
      properties:
        marketCode:
          type: string
          description: market_code echoes the requested market.
        asOf:
          type: string
          format: int64
          description: as_of is the Unix millisecond timestamp of the snapshot.
        range:
          type: string
          description: range echoes the requested range.
        categories:
          type: array
          items:
            $ref: '#/components/schemas/CategorySnapshot'
        upstreamUnavailable:
          type: boolean
          description: >-
            upstream_unavailable is true when the companion service could not be
            reached.
      description: >-
        ListConsumerPriceCategoriesResponse holds category-level price
        snapshots.
    ListConsumerPriceMoversRequest:
      type: object
      properties:
        marketCode:
          type: string
          description: market_code is the ISO 3166-1 alpha-2 market identifier.
        range:
          type: string
          description: range is one of "7d", "30d", "90d".
        limit:
          type: integer
          format: int32
          description: limit caps the number of risers and fallers returned.
        categorySlug:
          type: string
          description: category_slug filters to a single category when set.
      required:
        - limit
      description: ListConsumerPriceMoversRequest parameters for the movers RPC.
    ListConsumerPriceMoversResponse:
      type: object
      properties:
        marketCode:
          type: string
          description: market_code echoes the requested market.
        asOf:
          type: string
          format: int64
          description: as_of is the Unix millisecond timestamp of the snapshot.
        range:
          type: string
          description: range echoes the requested range.
        risers:
          type: array
          items:
            $ref: '#/components/schemas/PriceMover'
        fallers:
          type: array
          items:
            $ref: '#/components/schemas/PriceMover'
        upstreamUnavailable:
          type: boolean
          description: >-
            upstream_unavailable is true when the companion service could not be
            reached.
      description: ListConsumerPriceMoversResponse holds the top price movers.
    PriceMover:
      type: object
      properties:
        productId:
          type: string
          description: product_id is the retailer product identifier.
        title:
          type: string
          description: title is the normalized product title.
        category:
          type: string
          description: category is the product category slug.
        retailerSlug:
          type: string
          description: retailer_slug identifies the retailer where this move was observed.
        changePct:
          type: number
          format: double
          description: change_pct is the signed percentage change over the selected window.
        currentPrice:
          type: number
          format: double
          description: current_price is the latest observed price.
        currencyCode:
          type: string
          description: currency_code is the ISO 4217 currency code.
      description: >-
        PriceMover describes a product with a notable upward or downward price
        move.
    ListRetailerPriceSpreadsRequest:
      type: object
      properties:
        marketCode:
          type: string
          description: market_code is the ISO 3166-1 alpha-2 market identifier.
        basketSlug:
          type: string
          description: basket_slug selects which basket to compare across retailers.
      description: ListRetailerPriceSpreadsRequest parameters for the retailer spread RPC.
    ListRetailerPriceSpreadsResponse:
      type: object
      properties:
        marketCode:
          type: string
          description: market_code echoes the requested market.
        asOf:
          type: string
          format: int64
          description: as_of is the Unix millisecond timestamp of the snapshot.
        basketSlug:
          type: string
          description: basket_slug echoes the requested basket.
        currencyCode:
          type: string
          description: currency_code is the ISO 4217 currency code.
        retailers:
          type: array
          items:
            $ref: '#/components/schemas/RetailerSpread'
        spreadPct:
          type: number
          format: double
          description: >-
            spread_pct is the percentage difference between cheapest and most
            expensive retailer.
        upstreamUnavailable:
          type: boolean
          description: >-
            upstream_unavailable is true when the companion service could not be
            reached.
      description: ListRetailerPriceSpreadsResponse holds cheapest-basket rankings.
    RetailerSpread:
      type: object
      properties:
        slug:
          type: string
          description: slug is the retailer identifier.
        name:
          type: string
          description: name is the retailer display name.
        basketTotal:
          type: number
          format: double
          description: >-
            basket_total is the sum of matched basket item prices at this
            retailer.
        deltaVsCheapest:
          type: number
          format: double
          description: >-
            delta_vs_cheapest is the absolute price difference vs the cheapest
            retailer.
        deltaVsCheapestPct:
          type: number
          format: double
          description: >-
            delta_vs_cheapest_pct is the percentage difference vs the cheapest
            retailer.
        itemCount:
          type: integer
          format: int32
          description: item_count is the number of matched basket items observed.
        freshnessMin:
          type: integer
          format: int32
          description: >-
            freshness_min is minutes since the last successful scrape for this
            retailer.
        currencyCode:
          type: string
          description: currency_code is the ISO 4217 currency code.
      description: RetailerSpread holds the basket cost breakdown for one retailer.
    GetConsumerPriceFreshnessRequest:
      type: object
      properties:
        marketCode:
          type: string
          description: market_code is the ISO 3166-1 alpha-2 market identifier.
      description: GetConsumerPriceFreshnessRequest parameters for the freshness RPC.
    GetConsumerPriceFreshnessResponse:
      type: object
      properties:
        marketCode:
          type: string
          description: market_code echoes the requested market.
        asOf:
          type: string
          format: int64
          description: as_of is the Unix millisecond timestamp of the snapshot.
        retailers:
          type: array
          items:
            $ref: '#/components/schemas/RetailerFreshnessInfo'
        overallFreshnessMin:
          type: integer
          format: int32
          description: >-
            overall_freshness_min is the average freshness lag across all
            retailers.
        stalledCount:
          type: integer
          format: int32
          description: >-
            stalled_count is the number of retailers with no recent successful
            scrape.
        upstreamUnavailable:
          type: boolean
          description: >-
            upstream_unavailable is true when the companion service could not be
            reached.
      description: >-
        GetConsumerPriceFreshnessResponse describes feed health for all
        retailers.
    RetailerFreshnessInfo:
      type: object
      properties:
        slug:
          type: string
          description: slug is the retailer identifier.
        name:
          type: string
          description: name is the retailer display name.
        lastRunAt:
          type: string
          format: int64
          description: >-
            last_run_at is the Unix millisecond timestamp of the last successful
            scrape.
        status:
          type: string
          description: status is one of "ok", "stale", "failed", "unknown".
        parseSuccessRate:
          type: number
          format: double
          description: >-
            parse_success_rate is the fraction of pages parsed successfully
            (0–1).
        freshnessMin:
          type: integer
          format: int32
          description: freshness_min is minutes since last successful observation.
      description: >-
        RetailerFreshnessInfo describes the operational health of one retailer
        feed.
