openapi: 3.0.3
info:
  title: SwitchMall Public Statistics API
  version: 1.2.0
  description: Read-only public SwitchMall product reactions and merchant content view counts.
  contact:
    name: SwitchMall Developer Resources
    url: https://switchmall.ai/developers
externalDocs:
  description: SwitchMall Public API documentation
  url: https://switchmall.ai/developers/api
servers:
  - url: https://switchmall.ai
security: []
tags:
  - name: SwitchMall Products
    description: Read-only public information associated with SwitchMall product IDs.
  - name: SwitchMall Merchants
    description: Read-only product and offer view statistics associated with SwitchMall merchant IDs.
paths:
  /api/public/v1/products/{productId}/stats:
    get:
      operationId: getSwitchMallProductStats
      summary: Get SwitchMall product statistics
      description: Returns current view, like and dislike counts for a SwitchMall product ID. No authentication is required.
      security: []
      tags:
        - SwitchMall Products
      parameters:
        - name: productId
          in: path
          required: true
          description: Positive SwitchMall product ID.
          schema:
            type: integer
            format: int64
            minimum: 1
            maximum: 9007199254740991
          example: 1
      responses:
        "200":
          description: Current SwitchMall product statistics.
          headers:
            Cache-Control:
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProductStats"
              example:
                productId: 1
                viewsCount: 0
                likesCount: 0
                dislikesCount: 0
        "400":
          $ref: "#/components/responses/BadRequest"
        "405":
          $ref: "#/components/responses/MethodNotAllowed"
        "429":
          $ref: "#/components/responses/TooManyRequests"
        "500":
          $ref: "#/components/responses/ServerError"
  /api/public/v1/merchants/{merchantId}/stats:
    get:
      operationId: getSwitchMallMerchantStats
      summary: Get SwitchMall merchant view statistics
      description: Returns rolling 24-hour merchant totals, comparison with the latest previous 14:00 MSK snapshot, and per-product and per-offer view tables. No authentication is required.
      security: []
      tags:
        - SwitchMall Merchants
      parameters:
        - name: merchantId
          in: path
          required: true
          description: Positive integer merchant ID.
          schema:
            type: integer
            format: int64
            minimum: 1
            maximum: 9007199254740991
      responses:
        "200":
          description: Current merchant view statistics.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/MerchantStats"
        "400":
          $ref: "#/components/responses/BadMerchantRequest"
        "405":
          $ref: "#/components/responses/MethodNotAllowed"
        "429":
          $ref: "#/components/responses/TooManyRequests"
        "500":
          $ref: "#/components/responses/ServerError"
components:
  schemas:
    ProductStats:
      type: object
      required:
        - productId
        - viewsCount
        - likesCount
        - dislikesCount
      properties:
        productId:
          type: integer
          format: int64
          minimum: 1
          maximum: 9007199254740991
          description: SwitchMall product ID supplied in the request path.
        viewsCount:
          type: integer
          minimum: 0
          description: Recorded product view events.
        likesCount:
          type: integer
          minimum: 0
          description: Current positive reactions.
        dislikesCount:
          type: integer
          minimum: 0
          description: Current negative reactions.
      additionalProperties: false
    MerchantContentView:
      type: object
      required: [id, name, viewsCount, userViewsCount, agentViewsCount]
      properties:
        id: { type: integer, format: int64, minimum: 1 }
        name: { type: string }
        viewsCount: { type: integer, minimum: 0 }
        userViewsCount: { type: integer, minimum: 0 }
        agentViewsCount: { type: integer, minimum: 0 }
      additionalProperties: false
    ActivityComparison:
      type: object
      required: [count, previousCount, changePercent]
      properties:
        count: { type: integer, minimum: 0 }
        previousCount: { type: integer, minimum: 0 }
        changePercent:
          type: number
          nullable: true
          description: Percentage change, or null when the baseline is zero and the current count is positive.
      additionalProperties: false
    MerchantViewComparisons:
      type: object
      required: [productViews, productUserViews, productAgentViews, offerViews, totalViews]
      properties:
        productViews: { $ref: "#/components/schemas/ActivityComparison" }
        productUserViews: { $ref: "#/components/schemas/ActivityComparison" }
        productAgentViews: { $ref: "#/components/schemas/ActivityComparison" }
        offerViews: { $ref: "#/components/schemas/ActivityComparison" }
        totalViews: { $ref: "#/components/schemas/ActivityComparison" }
      additionalProperties: false
    MerchantStats:
      type: object
      required: [merchantId, merchantName, productViewsCount, productUserViewsCount, productAgentViewsCount, offerViewsCount, totalViewsCount, comparisons, products, offers, period, scheduledAt]
      properties:
        merchantId: { type: integer, format: int64, minimum: 1 }
        merchantName: { type: string }
        productViewsCount: { type: integer, minimum: 0 }
        productUserViewsCount: { type: integer, minimum: 0 }
        productAgentViewsCount: { type: integer, minimum: 0 }
        offerViewsCount: { type: integer, minimum: 0 }
        totalViewsCount: { type: integer, minimum: 0 }
        comparisons: { $ref: "#/components/schemas/MerchantViewComparisons" }
        period: { type: string, enum: [24h] }
        comparisonDate:
          type: string
          format: date
          description: Date of the latest previous 14:00 MSK snapshot; omitted until a baseline exists.
        scheduledAt: { type: string, enum: ["14:00 MSK"] }
        products:
          type: array
          items: { $ref: "#/components/schemas/MerchantContentView" }
        offers:
          type: array
          items: { $ref: "#/components/schemas/MerchantContentView" }
      additionalProperties: false
    Error:
      type: object
      required:
        - error
        - code
        - message
        - resolution
      properties:
        error:
          type: string
          description: Backward-compatible human-readable error message.
        code:
          type: string
          description: Stable machine-readable error code.
          enum:
            - INVALID_PRODUCT_ID
            - INVALID_MERCHANT_ID
            - METHOD_NOT_ALLOWED
            - RATE_LIMIT_EXCEEDED
            - INTERNAL_ERROR
            - API_ROUTE_NOT_FOUND
        message:
          type: string
          description: Human-readable explanation of the failure.
        resolution:
          type: string
          description: Concrete guidance for correcting or retrying the request.
      additionalProperties: false
  responses:
    BadRequest:
      description: Invalid SwitchMall product ID.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    BadMerchantRequest:
      description: Invalid merchant ID.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
          example:
            error: Merchant ID must be a positive integer
            code: INVALID_MERCHANT_ID
            message: Merchant ID must be a positive integer
            resolution: Provide a positive integer SwitchMall merchant ID in the URL path.
    MethodNotAllowed:
      description: Unsupported HTTP method.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
          example:
            error: Method not allowed
            code: METHOD_NOT_ALLOWED
            message: Method not allowed
            resolution: Call this endpoint with GET or OPTIONS.
    TooManyRequests:
      description: Public rate limit exceeded.
      headers:
        Retry-After:
          description: Seconds until another request may be attempted.
          schema:
            type: integer
            minimum: 1
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
          example:
            error: Rate limit exceeded
            code: RATE_LIMIT_EXCEEDED
            message: Rate limit exceeded
            resolution: Wait for the Retry-After interval before retrying.
    ServerError:
      description: Unexpected server error.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
          example:
            error: Internal server error
            code: INTERNAL_ERROR
            message: Internal server error
            resolution: Retry later or use the SwitchMall contact page if the problem continues.
