openapi: 3.0.3
info:
  title: Wanich API
  version: v1
  description: |
    Versioned API reference for Wanich storefront, seller support flows, logistics,
    marketplaces, affiliate operations, and authenticated user endpoints.

    This first OpenAPI document focuses on route discovery and operational coverage.
    Request and response schemas can be enriched incrementally without changing the
    documentation host.
servers:
  - url: https://api.wanich.co/api/v1
    description: Production API
tags:
  - name: Payments
  - name: Auth
  - name: Settings
  - name: Logistics
  - name: Marketplace
  - name: Catalog
  - name: Products
  - name: Cart
  - name: Checkout
  - name: Addresses
  - name: User
  - name: Conversations
  - name: Wallet
  - name: Club Points
  - name: Refunds
  - name: Affiliate
  - name: Seller Scope
  - name: Delivery Boy
  - name: Shops
  - name: Security
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
  schemas:
    GenericSuccessResponse:
      type: object
      properties:
        success:
          type: boolean
          example: true
        status:
          type: integer
          example: 200
        message:
          type: string
          example: Successful operation
    GenericMessageResponse:
      type: object
      properties:
        success:
          type: boolean
          example: true
        message:
          type: string
          example: Operation completed successfully.
    ErrorResponse:
      type: object
      properties:
        success:
          type: boolean
          example: false
        status:
          type: integer
          nullable: true
          example: 401
        message:
          type: string
          example: Unauthenticated
        data:
          nullable: true
    AuthUser:
      type: object
      properties:
        id:
          type: integer
          example: 14
        balance:
          type: number
          format: float
          example: 1250
        name:
          type: string
          example: Arnon Hongklay
        email:
          type: string
          format: email
          nullable: true
          example: arnon@example.com
        phone:
          type: string
          nullable: true
          example: "0812345678"
        user_type:
          type: string
          example: customer
        avatar:
          type: string
          format: uri
          nullable: true
          example: https://wanich.co/public/uploads/all/avatar.png
    AuthTokenResponse:
      type: object
      properties:
        success:
          type: boolean
          example: true
        access_token:
          type: string
          example: eyJ0eXAiOiJKV1QiLCJhbGciOi...
        token_type:
          type: string
          example: Bearer
        verified:
          type: boolean
          example: true
        expires_at:
          type: string
          format: date-time
        user:
          $ref: "#/components/schemas/AuthUser"
        message:
          type: string
          example: Successfully logged in
        followed_shops:
          type: array
          items:
            type: integer
          example: [12, 18]
    VerificationPendingResponse:
      type: object
      properties:
        success:
          type: boolean
          example: true
        verified:
          type: boolean
          example: false
        email_verified:
          type: boolean
          nullable: true
          example: false
        phone_verified:
          type: boolean
          nullable: true
          example: false
        message:
          type: string
          example: Please verify your account
    TempCartResponse:
      type: object
      properties:
        result:
          type: boolean
          example: true
        temp_user_id:
          type: string
          example: 8b03c8d2-52df-4b4f-bf16-a1c34e8eb774
        message:
          type: string
          example: Temp cart id generated
    BannerLink:
      type: object
      properties:
        img:
          type: string
          format: uri
          nullable: true
        link:
          type: string
          nullable: true
      additionalProperties: false
    MenuMap:
      type: object
      additionalProperties:
        type: string
      example:
        About Us: /about-us
        Contact: /contact
    HeaderSettingsResponse:
      type: object
      properties:
        top_banner:
          $ref: "#/components/schemas/BannerLink"
        mobile_app_links:
          type: object
          properties:
            show_play_store:
              type: string
              example: "on"
            play_store:
              type: string
              nullable: true
            show_app_store:
              type: string
              example: "off"
            app_store:
              type: string
              nullable: true
        show_language_switcher:
          type: string
          example: "on"
        helpline:
          type: string
          nullable: true
          example: "+66 2 123 4567"
        header_menu:
          $ref: "#/components/schemas/MenuMap"
    FooterLinkGroup:
      type: object
      properties:
        title:
          type: string
          nullable: true
        menu:
          $ref: "#/components/schemas/MenuMap"
    FooterSettingsResponse:
      type: object
      properties:
        current_version:
          type: string
          nullable: true
          example: "1.0.0"
        footer_logo:
          type: string
          format: uri
          nullable: true
        footer_link_one:
          $ref: "#/components/schemas/FooterLinkGroup"
        footer_link_two:
          $ref: "#/components/schemas/FooterLinkGroup"
        contact_info:
          type: object
          properties:
            contact_address:
              type: string
              nullable: true
            contact_email:
              type: string
              nullable: true
            contact_phone:
              type: string
              nullable: true
        mobile_app_links:
          type: object
          properties:
            play_store:
              type: string
              nullable: true
            app_store:
              type: string
              nullable: true
        footer_menu:
          $ref: "#/components/schemas/MenuMap"
        copyright_text:
          type: string
          nullable: true
        social_link:
          type: object
          additionalProperties:
            nullable: true
            type: string
    HomeSectionResponse:
      type: object
      properties:
        success:
          type: boolean
          example: true
        data:
          nullable: true
          description: Section-specific payload. Shape changes by requested section.
          oneOf:
            - type: object
            - type: array
              items:
                type: object
            - type: string
    CategoryItem:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        banner:
          type: string
          format: uri
          nullable: true
        icon:
          type: string
          format: uri
          nullable: true
        slug:
          type: string
    CategoryCollectionResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/CategoryItem"
        success:
          type: boolean
          example: true
        status:
          type: integer
          example: 200
    BrandItem:
      type: object
      properties:
        id:
          type: integer
        slug:
          type: string
        name:
          type: string
        logo:
          type: string
          format: uri
          nullable: true
    BrandCollectionResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/BrandItem"
        success:
          type: boolean
          example: true
        status:
          type: integer
          example: 200
    AttributeValueItem:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
    AttributeValueCollection:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/AttributeValueItem"
        success:
          type: boolean
          example: true
        status:
          type: integer
          example: 200
    AttributeItem:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        values:
          $ref: "#/components/schemas/AttributeValueCollection"
    AttributeCollectionResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/AttributeItem"
        success:
          type: boolean
          example: true
        status:
          type: integer
          example: 200
    ProductVariationOption:
      type: object
      description: Variation or option payload returned by the product resources. Keys vary by product type.
      additionalProperties: true
    ProductListItem:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        slug:
          type: string
        thumbnail_image:
          type: string
          format: uri
          nullable: true
        base_price:
          type: number
          format: float
        base_discounted_price:
          type: number
          format: float
        stock:
          type: integer
        unit:
          type: string
          nullable: true
        min_qty:
          type: integer
        max_qty:
          type: integer
        rating:
          type: number
          format: float
        earn_point:
          type: number
          format: float
        is_variant:
          type: integer
        variations:
          type: array
          items:
            $ref: "#/components/schemas/ProductVariationOption"
        is_digital:
          type: boolean
        for_pickup:
          type: boolean
    ProductListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/ProductListItem"
        success:
          type: boolean
          example: true
        status:
          type: integer
          example: 200
    ProductDetail:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        slug:
          type: string
        metaTitle:
          type: string
          nullable: true
        brand:
          type: object
          properties:
            id:
              type: integer
              nullable: true
            name:
              type: string
              nullable: true
            slug:
              type: string
              nullable: true
            logo:
              type: string
              format: uri
              nullable: true
        photos:
          type: array
          items:
            type: string
            format: uri
        thumbnail_image:
          type: string
          format: uri
          nullable: true
        tags:
          type: array
          items:
            type: string
        featured:
          type: integer
        stock:
          type: integer
        min_qty:
          type: integer
        max_qty:
          type: integer
        unit:
          type: string
          nullable: true
        discount:
          nullable: true
          oneOf:
            - type: number
            - type: string
        discount_type:
          type: string
          nullable: true
        base_price:
          type: number
          format: float
        highest_price:
          type: number
          format: float
        base_discounted_price:
          type: number
          format: float
        highest_discounted_price:
          type: number
          format: float
        standard_delivery_time:
          type: integer
        express_delivery_time:
          type: integer
        is_variant:
          type: integer
        has_warranty:
          nullable: true
          oneOf:
            - type: boolean
            - type: integer
        for_pickup:
          type: boolean
        review_summary:
          type: object
          properties:
            average:
              type: number
              format: float
            total_count:
              type: integer
            count_5:
              type: integer
            count_4:
              type: integer
            count_3:
              type: integer
            count_2:
              type: integer
            count_1:
              type: integer
        description:
          type: string
        variations:
          type: array
          items:
            $ref: "#/components/schemas/ProductVariationOption"
        variation_options:
          type: array
          items:
            $ref: "#/components/schemas/ProductVariationOption"
        shop:
          type: object
          properties:
            name:
              type: string
            logo:
              type: string
              format: uri
              nullable: true
            rating:
              type: number
              format: float
            review_count:
              type: integer
            slug:
              type: string
            isVarified:
              type: boolean
        earn_point:
          type: number
          format: float
        is_digital:
          type: boolean
        available_countries:
          type: array
          items:
            type: object
            additionalProperties: true
        country_pricing:
          type: array
          items:
            type: object
            additionalProperties: true
        selected_country:
          type: string
          nullable: true
    ProductDetailResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/ProductDetail"
        success:
          type: boolean
          example: true
        status:
          type: integer
          example: 200
    ProductSearchResponse:
      type: object
      properties:
        success:
          type: boolean
          example: true
        categoryMetaTitle:
          type: string
          nullable: true
        categoryMetaDescription:
          type: string
          nullable: true
        brandMetaTitle:
          nullable: true
          oneOf:
            - type: string
            - type: object
        brandMetaDescription:
          nullable: true
          oneOf:
            - type: string
            - type: object
        products:
          $ref: "#/components/schemas/ProductListResponse"
        totalPage:
          type: integer
        currentPage:
          type: integer
        total:
          type: integer
        parentCategory:
          nullable: true
          allOf:
            - $ref: "#/components/schemas/CategoryItem"
        currentCategory:
          nullable: true
          allOf:
            - $ref: "#/components/schemas/CategoryItem"
        childCategories:
          nullable: true
          allOf:
            - $ref: "#/components/schemas/CategoryCollectionResponse"
        rootCategories:
          $ref: "#/components/schemas/CategoryCollectionResponse"
        allBrands:
          $ref: "#/components/schemas/BrandCollectionResponse"
        attributes:
          $ref: "#/components/schemas/AttributeCollectionResponse"
    AddressItem:
      type: object
      properties:
        id:
          type: integer
        user_id:
          type: integer
          nullable: true
        address:
          type: string
        country:
          type: string
        city:
          type: string
        state:
          type: string
        postal_code:
          type: string
          nullable: true
        phone:
          type: string
          nullable: true
        default_shipping:
          type: integer
        default_billing:
          type: integer
    AddressCollectionResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/AddressItem"
        success:
          type: boolean
          example: true
        status:
          type: integer
          example: 200
    AddressMutationRequest:
      type: object
      required: [address, country, state, city, phone]
      properties:
        id:
          type: integer
          description: Required when updating an existing address.
        guest_user_id:
          type: string
          nullable: true
        address:
          type: string
        country:
          type: integer
        state:
          type: integer
        city:
          type: integer
        postal_code:
          type: string
          nullable: true
        phone:
          type: string
    AddressMutationResponse:
      type: object
      properties:
        success:
          type: boolean
          example: true
        message:
          type: string
        data:
          oneOf:
            - $ref: "#/components/schemas/AddressItem"
            - type: array
              items:
                $ref: "#/components/schemas/AddressItem"
    CartItem:
      type: object
      properties:
        cart_id:
          type: integer
        product_id:
          type: integer
        shop_id:
          type: integer
        earn_point:
          type: number
          format: float
        variation_id:
          type: integer
        name:
          type: string
        combinations:
          type: array
          items:
            type: object
            additionalProperties: true
        thumbnail:
          type: string
          format: uri
          nullable: true
        regular_price:
          type: number
          format: float
        dicounted_price:
          type: number
          format: float
        tax:
          type: number
          format: float
        stock:
          type: integer
        min_qty:
          type: integer
        max_qty:
          type: integer
        standard_delivery_time:
          type: integer
        express_delivery_time:
          type: integer
        qty:
          type: integer
        is_digital:
          oneOf:
            - type: boolean
            - type: integer
        for_pickup:
          oneOf:
            - type: boolean
            - type: integer
    ShopListItem:
      type: object
      properties:
        id:
          type: integer
        slug:
          type: string
        name:
          type: string
        logo:
          type: string
          format: uri
          nullable: true
        banner:
          type: string
          format: uri
          nullable: true
        rating:
          type: number
          format: float
        min_order:
          type: number
          format: float
        categories:
          $ref: "#/components/schemas/CategoryCollectionResponse"
        top_3_products:
          oneOf:
            - $ref: "#/components/schemas/ProductListResponse"
            - type: array
              items: {}
        reviews_count:
          type: integer
        products_count:
          type: integer
        since:
          type: string
        isVarified:
          type: boolean
    ShopCollectionResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/ShopListItem"
        success:
          type: boolean
          example: true
        status:
          type: integer
          example: 200
    CartStateResponse:
      type: object
      properties:
        success:
          type: boolean
          example: true
        cart_items:
          $ref: "#/components/schemas/CartCollectionResponse"
        shops:
          $ref: "#/components/schemas/ShopCollectionResponse"
    CartCollectionResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/CartItem"
        success:
          type: boolean
          example: true
        status:
          type: integer
          example: 200
    CartAddRequest:
      type: object
      required: [variation_id, qty]
      properties:
        variation_id:
          type: integer
        qty:
          type: integer
          minimum: 1
        temp_user_id:
          type: string
          nullable: true
        country_code:
          type: string
          nullable: true
          example: TH
    CartAddResponse:
      type: object
      properties:
        success:
          type: boolean
          example: true
        data:
          $ref: "#/components/schemas/CartItem"
        cart_items:
          $ref: "#/components/schemas/CartCollectionResponse"
        shop:
          type: object
          additionalProperties: true
        message:
          type: string
    CartChangeQuantityRequest:
      type: object
      required: [cart_id, type]
      properties:
        cart_id:
          type: integer
        type:
          type: string
          enum: [plus, minus]
        temp_user_id:
          type: string
          nullable: true
    CartDestroyRequest:
      type: object
      required: [cart_id]
      properties:
        cart_id:
          type: integer
        temp_user_id:
          type: string
          nullable: true
    ShippingCostResponse:
      type: object
      properties:
        success:
          type: boolean
          example: true
        message:
          type: string
          nullable: true
        standard_delivery_cost:
          type: number
          format: float
        express_delivery_cost:
          type: number
          format: float
        country_code:
          type: string
          nullable: true
          example: TH
        disallowed_items:
          type: array
          items:
            type: object
            properties:
              product_id:
                type: integer
              shop_id:
                type: integer
              name:
                type: string
        blocked_payment_gateways:
          type: array
          items:
            type: string
        blocked_payment_channels:
          type: array
          items:
            type: string
        logistics_providers:
          type: array
          items:
            type: object
            additionalProperties: true
        preferred_logistics_provider:
          type: object
          nullable: true
          additionalProperties: true
    OrderUserSummary:
      type: object
      properties:
        name:
          type: string
        email:
          type: string
          nullable: true
        phone:
          type: string
          nullable: true
        avatar:
          type: string
          format: uri
          nullable: true
    OrderProductItem:
      type: object
      properties:
        id:
          type: integer
          nullable: true
        name:
          type: string
        thumbnail:
          type: string
          format: uri
          nullable: true
        combinations:
          type: array
          items:
            type: object
            additionalProperties: true
        price:
          type: number
          format: float
        tax:
          type: number
          format: float
        total:
          type: number
          format: float
        quantity:
          type: integer
        order_detail_id:
          type: integer
        product_variation_id:
          type: integer
          nullable: true
    OrderProductCollectionResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/OrderProductItem"
        success:
          type: boolean
          example: true
        status:
          type: integer
          example: 200
    OrderItem:
      type: object
      properties:
        id:
          type: integer
        code:
          type: string
        shop:
          type: object
          properties:
            name:
              type: string
            slug:
              type: string
        payment_type:
          type: string
          nullable: true
        manual_payment:
          nullable: true
          oneOf:
            - type: boolean
            - type: integer
        manual_payment_data:
          nullable: true
          oneOf:
            - type: object
              additionalProperties: true
            - type: array
              items:
                type: object
                additionalProperties: true
        delivery_type:
          type: string
          nullable: true
        type_of_delivery:
          type: string
          nullable: true
        pickup_point:
          type: object
          nullable: true
          additionalProperties: true
        delivery_status:
          type: string
          nullable: true
        payment_status:
          type: string
          nullable: true
        coupon_discount:
          type: number
          format: float
        shipping_cost:
          type: number
          format: float
        grand_total:
          type: number
          format: float
        subtotal:
          type: number
          format: float
        tax:
          type: number
          format: float
        products:
          $ref: "#/components/schemas/OrderProductCollectionResponse"
        created_at:
          type: integer
          description: Unix timestamp.
        has_refund_request:
          type: boolean
        courier_name:
          type: string
          nullable: true
        tracking_number:
          type: string
          nullable: true
        tracking_url:
          type: string
          nullable: true
    OrderListItem:
      type: object
      properties:
        id:
          type: integer
        code:
          type: string
        user:
          $ref: "#/components/schemas/OrderUserSummary"
        shipping_address:
          type: object
          nullable: true
          additionalProperties: true
        billing_address:
          type: object
          nullable: true
          additionalProperties: true
        grand_total:
          type: number
          format: float
        orders:
          type: array
          items:
            $ref: "#/components/schemas/OrderItem"
        date:
          type: string
    OrderListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/OrderListItem"
        links:
          type: object
          nullable: true
          additionalProperties: true
        meta:
          type: object
          nullable: true
          additionalProperties: true
        success:
          type: boolean
          example: true
        status:
          type: integer
          example: 200
    OrderDetailResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            id:
              type: integer
            code:
              type: string
            user:
              $ref: "#/components/schemas/OrderUserSummary"
            shipping_address:
              type: object
              nullable: true
              additionalProperties: true
            billing_address:
              type: object
              nullable: true
              additionalProperties: true
            grand_total:
              type: number
              format: float
            orders:
              type: array
              items:
                $ref: "#/components/schemas/OrderItem"
            date:
              type: string
        success:
          type: boolean
          example: true
        status:
          type: integer
          example: 200
    InvoiceResponse:
      type: object
      properties:
        success:
          type: boolean
        message:
          type: string
        invoice_url:
          type: string
          nullable: true
          format: uri
        invoice_name:
          type: string
          nullable: true
    DownloadedProductItem:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        image:
          type: string
          format: uri
          nullable: true
        file_path:
          type: string
          format: uri
    DownloadedProductCollectionResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/DownloadedProductItem"
        links:
          type: object
          nullable: true
          additionalProperties: true
        meta:
          type: object
          nullable: true
          additionalProperties: true
        success:
          type: boolean
          example: true
        status:
          type: integer
          example: 200
    WalletHistoryItem:
      type: object
      properties:
        id:
          type: integer
        date:
          type: string
        amount:
          type: number
          format: float
        payment_method:
          type: string
          nullable: true
        type:
          type: string
          nullable: true
        details:
          nullable: true
          oneOf:
            - type: string
            - type: object
              additionalProperties: true
            - type: array
              items:
                type: object
                additionalProperties: true
        receipt:
          type: string
          nullable: true
          format: uri
    WalletHistoryResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/WalletHistoryItem"
        links:
          type: object
          nullable: true
          additionalProperties: true
        meta:
          type: object
          nullable: true
          additionalProperties: true
        success:
          type: boolean
          example: true
        status:
          type: integer
          example: 200
    WalletRechargeRequest:
      type: object
      required: [amount, payment_method]
      properties:
        amount:
          type: number
          format: float
          minimum: 1
        payment_method:
          type: string
          example: stripe
        redirect_to:
          type: string
          nullable: true
          example: /user/wallet
    AffiliateBalanceResponse:
      type: object
      properties:
        affiliate_balance:
          type: string
          example: ฿1,250.00
        status:
          type: integer
          example: 200
    AffiliateReferralCodeResponse:
      type: object
      properties:
        referral_code:
          type: string
          format: uri
        status:
          type: integer
          example: 200
    AffiliateStatPayload:
      type: object
      properties:
        click:
          type: integer
        item:
          type: integer
        delivered:
          type: integer
        cancel:
          type: integer
    AffiliateUserCheckResponse:
      type: object
      properties:
        affiliated_user:
          type: boolean
        user_referral_code:
          type: string
          nullable: true
        affiliate_option:
          type: boolean
        shop_id:
          type: integer
          nullable: true
        status:
          type: integer
          example: 200
    AffiliateLevelItem:
      type: object
      properties:
        level:
          type: integer
        commission:
          type: number
          format: float
        downline_count:
          type: integer
    AffiliateCommissionPanelResponse:
      type: object
      properties:
        program:
          type: object
          properties:
            status:
              type: boolean
            plan_type:
              type: string
              nullable: true
        binary:
          type: object
          additionalProperties: true
        unilevel:
          type: object
          properties:
            enabled:
              type: boolean
            commission_type:
              type: string
              nullable: true
            max_levels:
              type: integer
            total_downline:
              type: integer
            levels:
              type: array
              items:
                $ref: "#/components/schemas/AffiliateLevelItem"
        rank_bonus:
          type: object
          additionalProperties: true
        hybrid:
          type: object
          additionalProperties: true
        enabled:
          type: boolean
        plan_type:
          type: string
          nullable: true
        commission_type:
          type: string
          nullable: true
        max_levels:
          type: integer
        total_downline:
          type: integer
        levels:
          type: array
          items:
            $ref: "#/components/schemas/AffiliateLevelItem"
        status:
          type: integer
          example: 200
    AffiliateTreeNode:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        level:
          type: integer
        commission:
          type: number
          format: float
          nullable: true
        children:
          type: array
          items:
            $ref: "#/components/schemas/AffiliateTreeNode"
    AffiliateNetworkTreeResponse:
      type: object
      properties:
        enabled:
          type: boolean
        plan_type:
          type: string
          nullable: true
        commission_type:
          type: string
          nullable: true
        max_levels:
          type: integer
        tree:
          $ref: "#/components/schemas/AffiliateTreeNode"
        status:
          type: integer
          example: 200
    AffiliateWithdrawRequestItem:
      type: object
      properties:
        amount:
          type: number
          format: float
        date:
          type: string
        status:
          type: integer
    AffiliatePaymentHistoryItem:
      type: object
      properties:
        amount:
          type: number
          format: float
        date:
          type: string
        payment_method:
          type: string
          nullable: true
    AffiliateEarningHistoryItem:
      type: object
      properties:
        referral_user:
          type: string
        amount:
          type: number
          format: float
        order_id:
          type: string
          nullable: true
        referrel_type:
          type: string
          nullable: true
        product:
          type: string
          nullable: true
        date:
          type: string
    AffiliateCollectionResponse:
      type: object
      properties:
        data:
          type: array
          items:
            type: object
            additionalProperties: true
        links:
          type: object
          nullable: true
          additionalProperties: true
        meta:
          type: object
          nullable: true
          additionalProperties: true
  responses:
    Ok:
      description: Successful operation
    Accepted:
      description: Request accepted
    Unauthorized:
      description: Authentication is required or the bearer token is invalid.
    ValidationError:
      description: Request validation failed.
paths:
  /payment/{gateway}/pay:
    post:
      tags: [Payments]
      summary: Initialize a payment for an authenticated API user
      security:
        - bearerAuth: []
      parameters:
        - name: gateway
          in: path
          required: true
          schema: { type: string }
      responses:
        "200": { $ref: "#/components/responses/Ok" }
        "401": { $ref: "#/components/responses/Unauthorized" }

  /auth/login:
    post:
      tags: [Auth]
      summary: Log in a customer and receive an API token
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [password]
              properties:
                email:
                  type: string
                  format: email
                  description: Required when logging in with email.
                phone:
                  type: string
                  description: Required when logging in with phone.
                password:
                  type: string
                  format: password
                form_type:
                  type: string
                  description: Must match the target panel role. Customer mobile apps normally send customer.
                  example: customer
                temp_user_id:
                  type: string
                  nullable: true
                  description: Guest cart ID to merge after login.
      responses:
        "200":
          description: Login result, verification gate, or business-rule failure.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: "#/components/schemas/AuthTokenResponse"
                  - $ref: "#/components/schemas/VerificationPendingResponse"
                  - $ref: "#/components/schemas/ErrorResponse"
        "422": { $ref: "#/components/responses/ValidationError" }
  /auth/signup:
    post:
      tags: [Auth]
      summary: Register a new customer account
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name, email, phone, password]
              properties:
                name:
                  type: string
                email:
                  type: string
                  format: email
                phone:
                  type: string
                password:
                  type: string
                  format: password
                temp_user_id:
                  type: string
                  nullable: true
      responses:
        "200":
          description: Signup result. Depending on OTP settings the account may be immediately logged in or require verification.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: "#/components/schemas/AuthTokenResponse"
                  - $ref: "#/components/schemas/VerificationPendingResponse"
                  - $ref: "#/components/schemas/ErrorResponse"
        "422": { $ref: "#/components/responses/ValidationError" }
  /auth/verify:
    post:
      tags: [Auth]
      summary: Verify account registration or OTP flow
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [code]
              properties:
                email:
                  type: string
                  format: email
                phone:
                  type: string
                code:
                  type: string
                  example: "123456"
      responses:
        "200":
          description: Successful verification returns a bearer token. Incorrect or expired codes return a business error payload.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: "#/components/schemas/AuthTokenResponse"
                  - $ref: "#/components/schemas/ErrorResponse"
        "422": { $ref: "#/components/responses/ValidationError" }
        "429":
          description: Too many invalid OTP attempts.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /auth/resend-code:
    post:
      tags: [Auth]
      summary: Resend the verification code
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                email:
                  type: string
                  format: email
                phone:
                  type: string
      responses:
        "200":
          description: Verification code dispatch result.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: "#/components/schemas/VerificationPendingResponse"
                  - $ref: "#/components/schemas/ErrorResponse"
  /auth/password/create:
    post:
      tags: [Auth]
      summary: Start password reset flow
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                email:
                  type: string
                  format: email
                phone:
                  type: string
      responses:
        "200":
          description: Password reset code dispatch result.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: "#/components/schemas/GenericMessageResponse"
                  - $ref: "#/components/schemas/ErrorResponse"
  /auth/password/reset:
    post:
      tags: [Auth]
      summary: Complete password reset flow
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [code, password]
              properties:
                email:
                  type: string
                  format: email
                phone:
                  type: string
                code:
                  type: string
                password:
                  type: string
                  format: password
      responses:
        "200":
          description: Password reset result.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: "#/components/schemas/GenericMessageResponse"
                  - $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: Too many invalid OTP attempts.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /auth/logout:
    post:
      tags: [Auth]
      summary: Log out the current authenticated API user
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Logout success message.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GenericMessageResponse"
  /auth/user:
    get:
      tags: [Auth]
      summary: Return the current authenticated API user
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Authenticated user profile.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AuthUser"
        "401": { $ref: "#/components/responses/Unauthorized" }

  /temp-id-cart:
    post:
      tags: [Cart]
      summary: Create or refresh a guest temp cart identifier
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                temp_user_id:
                  type: string
                  nullable: true
                  description: Reuse an existing guest cart ID if the client already has one.
      responses:
        "200":
          description: Temp cart ID result.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TempCartResponse"
  /temp-id-cart-update:
    post:
      tags: [Cart]
      summary: Update a guest temp cart identifier
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [temp_user_id]
              properties:
                temp_user_id:
                  type: string
      responses:
        "200":
          description: Guest cart merge result.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GenericMessageResponse"

  /locale/{language_code}:
    get:
      tags: [Settings]
      summary: Get translated locale strings
      parameters:
        - name: language_code
          in: path
          required: true
          schema: { type: string }
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /setting/home/{section}:
    get:
      tags: [Settings]
      summary: Get a home page section configuration
      parameters:
        - name: section
          in: path
          required: true
          schema:
            type: string
            enum:
              - sliders
              - popular_categories
              - product_section_one
              - product_section_two
              - product_section_three
              - product_section_four
              - product_section_five
              - product_section_six
              - banner_section_one
              - banner_section_two
              - banner_section_three
              - banner_section_four
              - home_about_text
              - shop_section_one
              - shop_banner_section_one
              - shop_section_two
              - shop_banner_section_two
              - shop_section_three
              - shop_section_four
              - shop_section_five
              - shop_banner_section_three
      responses:
        "200":
          description: Home page section payload. The `data` property changes shape by section.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/HomeSectionResponse"
  /setting/footer:
    get:
      tags: [Settings]
      summary: Get footer settings
      responses:
        "200":
          description: Footer configuration used by the storefront.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/FooterSettingsResponse"
  /setting/header:
    get:
      tags: [Settings]
      summary: Get header settings
      responses:
        "200":
          description: Header configuration used by the storefront.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/HeaderSettingsResponse"
  /subscribe:
    post:
      tags: [Settings]
      summary: Subscribe an email address to updates
      responses:
        "200": { $ref: "#/components/responses/Ok" }

  /logistics/countries:
    get:
      tags: [Logistics]
      summary: List supported logistics countries
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /logistics/providers:
    get:
      tags: [Logistics]
      summary: List logistics providers
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /logistics/recommendations:
    get:
      tags: [Logistics]
      summary: Return logistics recommendations
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /logistics/webhook/{providerSlug}:
    post:
      tags: [Logistics]
      summary: Receive logistics provider webhooks
      parameters:
        - name: providerSlug
          in: path
          required: false
          schema: { type: string }
      responses:
        "200": { $ref: "#/components/responses/Accepted" }

  /marketplace/webhook/{platform}:
    get:
      tags: [Marketplace]
      summary: Verify a marketplace webhook
      parameters:
        - name: platform
          in: path
          required: true
          schema: { type: string, enum: [facebook, tiktok, shopee, lazada] }
      responses:
        "200": { $ref: "#/components/responses/Ok" }
    post:
      tags: [Marketplace]
      summary: Receive marketplace webhook events
      parameters:
        - name: platform
          in: path
          required: true
          schema: { type: string, enum: [facebook, tiktok, shopee, lazada] }
      responses:
        "200": { $ref: "#/components/responses/Accepted" }

  /all-categories:
    get:
      tags: [Catalog]
      summary: List all categories
      responses:
        "200":
          description: Category listing used by storefront filters and menus.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CategoryCollectionResponse"
  /categories/first-level:
    get:
      tags: [Catalog]
      summary: List first-level categories
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /all-brands:
    get:
      tags: [Catalog]
      summary: List all brands
      responses:
        "200":
          description: Brand listing used by storefront filters.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BrandCollectionResponse"
  /all-offers:
    get:
      tags: [Catalog]
      summary: List current offers
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /offer/{slug}:
    get:
      tags: [Catalog]
      summary: Get offer details
      parameters:
        - name: slug
          in: path
          required: true
          schema: { type: string }
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /page/{slug}:
    get:
      tags: [Catalog]
      summary: Get a custom page
      parameters:
        - name: slug
          in: path
          required: true
          schema: { type: string }
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /all-blog-categories:
    get:
      tags: [Catalog]
      summary: List blog categories
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /all-blogs/search:
    get:
      tags: [Catalog]
      summary: Search blog entries
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /blog/details/{blog_slug}:
    get:
      tags: [Catalog]
      summary: Get blog details
      parameters:
        - name: blog_slug
          in: path
          required: true
          schema: { type: string }
      responses:
        "200": { $ref: "#/components/responses/Ok" }

  /product/details/{product_slug}:
    get:
      tags: [Products]
      summary: Get product details
      parameters:
        - name: product_slug
          in: path
          required: true
          schema: { type: string }
        - name: country_code
          in: query
          required: false
          schema:
            type: string
          description: Optional ISO-like country code for country-scoped stock and pricing.
      responses:
        "200":
          description: Full product detail payload used by the storefront PDP.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: "#/components/schemas/ProductDetailResponse"
                  - $ref: "#/components/schemas/ErrorResponse"
  /product/get-by-ids:
    post:
      tags: [Products]
      summary: Get products by a list of IDs
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [product_ids]
              properties:
                product_ids:
                  type: array
                  items:
                    type: integer
      responses:
        "200":
          description: Product list by IDs.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: "#/components/schemas/ProductListResponse"
                  - $ref: "#/components/schemas/ErrorResponse"
  /product/search:
    get:
      tags: [Products]
      summary: Search products
      parameters:
        - name: keyword
          in: query
          required: false
          schema:
            type: string
        - name: category_slug
          in: query
          required: false
          schema:
            type: string
        - name: brand_ids
          in: query
          required: false
          schema:
            type: string
          description: Comma-separated brand IDs.
        - name: min_price
          in: query
          required: false
          schema:
            type: number
            format: float
        - name: max_price
          in: query
          required: false
          schema:
            type: number
            format: float
        - name: attribute_values
          in: query
          required: false
          schema:
            type: string
          description: Comma-separated attribute value IDs.
        - name: sort_by
          in: query
          required: false
          schema:
            type: string
            enum: [latest, oldest, highest_price, lowest_price]
      responses:
        "200":
          description: Search result set with facets, categories, and pagination metadata.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProductSearchResponse"
  /product/related/{product_id}:
    get:
      tags: [Products]
      summary: Get related products
      parameters:
        - name: product_id
          in: path
          required: true
          schema: { type: integer }
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /product/bought-together/{product_id}:
    get:
      tags: [Products]
      summary: Get bought-together products
      parameters:
        - name: product_id
          in: path
          required: true
          schema: { type: integer }
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /product/random/{limit}/{product_id}:
    get:
      tags: [Products]
      summary: Get random products
      parameters:
        - name: limit
          in: path
          required: true
          schema: { type: integer }
        - name: product_id
          in: path
          required: false
          schema: { type: integer }
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /product/latest/{limit}:
    get:
      tags: [Products]
      summary: Get latest products
      parameters:
        - name: limit
          in: path
          required: true
          schema: { type: integer }
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /product/reviews/{product_id}:
    get:
      tags: [Products]
      summary: Get product reviews
      parameters:
        - name: product_id
          in: path
          required: true
          schema: { type: integer }
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /compared-list:
    post:
      tags: [Products]
      summary: Get compared product list
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /search.ajax/{keyword}:
    get:
      tags: [Products]
      summary: Product search autocomplete
      parameters:
        - name: keyword
          in: path
          required: true
          schema: { type: string }
      responses:
        "200": { $ref: "#/components/responses/Ok" }

  /all-countries:
    get:
      tags: [Addresses]
      summary: List all countries
      responses:
        "200":
          description: Enabled countries available for address selection.
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  data:
                    type: array
                    items:
                      type: object
                      additionalProperties: true
  /states/{country_id}:
    get:
      tags: [Addresses]
      summary: List states by country ID
      parameters:
        - name: country_id
          in: path
          required: true
          schema: { type: integer }
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /cities/{state_id}:
    get:
      tags: [Addresses]
      summary: List cities by state ID
      parameters:
        - name: state_id
          in: path
          required: true
          schema: { type: integer }
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /addresses:
    get:
      tags: [Addresses]
      summary: List current shipping addresses
      parameters:
        - name: temp_user
          in: query
          required: false
          schema:
            type: string
          description: Guest temp user ID when requesting addresses before login.
      responses:
        "200":
          description: Current address list for authenticated or guest checkout.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AddressCollectionResponse"
  /address/create:
    post:
      tags: [Addresses]
      summary: Create a shipping address
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AddressMutationRequest"
      responses:
        "200":
          description: Address creation result.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AddressMutationResponse"
        "401": { $ref: "#/components/responses/Unauthorized" }
  /address/update:
    post:
      tags: [Addresses]
      summary: Update a shipping address
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AddressMutationRequest"
      responses:
        "200":
          description: Address update result.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AddressMutationResponse"
        "401": { $ref: "#/components/responses/Unauthorized" }
  /pickup-points:
    get:
      tags: [Addresses]
      summary: List pickup points
      responses:
        "200": { $ref: "#/components/responses/Ok" }

  /carts:
    post:
      tags: [Cart]
      summary: Get current cart state
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                temp_user_id:
                  type: string
                  nullable: true
                country_code:
                  type: string
                  nullable: true
      responses:
        "200":
          description: Cart items grouped with participating shops.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CartStateResponse"
  /carts/add:
    post:
      tags: [Cart]
      summary: Add item to cart
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CartAddRequest"
      responses:
        "200":
          description: Cart add result with refreshed cart state.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CartAddResponse"
  /carts/change-quantity:
    post:
      tags: [Cart]
      summary: Change cart item quantity
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CartChangeQuantityRequest"
      responses:
        "200":
          description: Quantity change result. The API returns a message-only payload.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: "#/components/schemas/GenericMessageResponse"
                  - $ref: "#/components/schemas/ErrorResponse"
        "401": { $ref: "#/components/responses/Unauthorized" }
  /carts/destroy:
    post:
      tags: [Cart]
      summary: Remove an item from cart
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CartDestroyRequest"
      responses:
        "200":
          description: Cart deletion result with refreshed cart items.
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  cart_items:
                    $ref: "#/components/schemas/CartCollectionResponse"
                  message:
                    type: string
        "401": { $ref: "#/components/responses/Unauthorized" }
  /order/invoice-download/{order_id}:
    get:
      tags: [Cart]
      summary: Download order invoice
      security:
        - bearerAuth: []
      parameters:
        - name: order_id
          in: path
          required: true
          schema: { type: integer }
      responses:
        "200": { $ref: "#/components/responses/Ok" }

  /checkout/guest/order/store:
    post:
      tags: [Checkout]
      summary: Place an order as a guest
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /checkout/get-shipping-cost/{address_id}:
    get:
      tags: [Checkout]
      summary: Calculate shipping cost for an address
      parameters:
        - name: address_id
          in: path
          required: true
          schema: { type: integer }
        - name: temp_user_id
          in: query
          required: false
          schema:
            type: string
          description: Required for guest checkout when the caller is not authenticated.
        - name: cart_item_ids
          in: query
          required: false
          schema:
            oneOf:
              - type: string
                example: 14,15,16
              - type: array
                items:
                  type: integer
          description: Optional cart item IDs to scope the shipping calculation.
      responses:
        "200":
          description: Shipping and payment-availability result for the selected address.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ShippingCostResponse"
        "401": { $ref: "#/components/responses/Unauthorized" }
        "404":
          description: Address not found for the current customer or guest checkout flow.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /checkout/coupon/apply:
    post:
      tags: [Checkout]
      summary: Apply a coupon during checkout
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /checkout/order/store:
    post:
      tags: [Checkout]
      summary: Place an order as an authenticated customer
      security:
        - bearerAuth: []
      responses:
        "200": { $ref: "#/components/responses/Ok" }

  /user/addresses:
    get:
      tags: [User]
      summary: List user addresses
      security:
        - bearerAuth: []
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /user/address/create:
    post:
      tags: [User]
      summary: Create a user address
      security:
        - bearerAuth: []
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /user/address/update:
    post:
      tags: [User]
      summary: Update a user address
      security:
        - bearerAuth: []
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /user/address/delete/{id}:
    post:
      tags: [User]
      summary: Delete a user address
      security:
        - bearerAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema: { type: integer }
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /user/address/default-shipping/{id}:
    post:
      tags: [User]
      summary: Set default shipping address
      security:
        - bearerAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema: { type: integer }
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /user/address/default-billing/{id}:
    post:
      tags: [User]
      summary: Set default billing address
      security:
        - bearerAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema: { type: integer }
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /user/pickup-points:
    get:
      tags: [User]
      summary: List pickup points for the current user
      security:
        - bearerAuth: []
      responses:
        "200": { $ref: "#/components/responses/Ok" }

  /user/notification:
    get:
      tags: [User]
      summary: Get unread notification summary
      security:
        - bearerAuth: []
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /user/all-notification:
    get:
      tags: [User]
      summary: Get all notifications
      security:
        - bearerAuth: []
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /user/dashboard:
    get:
      tags: [User]
      summary: Get customer dashboard data
      security:
        - bearerAuth: []
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /user/chats:
    get:
      tags: [Conversations]
      summary: List customer chat threads
      security:
        - bearerAuth: []
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /user/chats/send:
    post:
      tags: [Conversations]
      summary: Send a customer chat message
      security:
        - bearerAuth: []
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /user/chats/new-messages:
    get:
      tags: [Conversations]
      summary: Poll for new customer chat messages
      security:
        - bearerAuth: []
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /user/info:
    get:
      tags: [User]
      summary: Get customer profile info
      security:
        - bearerAuth: []
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /user/info/update:
    post:
      tags: [User]
      summary: Update customer profile info
      security:
        - bearerAuth: []
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /user/coupons:
    get:
      tags: [User]
      summary: List customer coupons
      security:
        - bearerAuth: []
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /user/orders:
    get:
      tags: [User]
      summary: List customer orders
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Paginated customer order history.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/OrderListResponse"
  /user/re-order/{orderCode}:
    get:
      tags: [User]
      summary: Re-order a previous order
      security:
        - bearerAuth: []
      parameters:
        - name: orderCode
          in: path
          required: true
          schema: { type: string }
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /user/orders/downloads:
    get:
      tags: [User]
      summary: List downloadable order items
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Paginated purchased digital products available for download.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DownloadedProductCollectionResponse"
  /user/orders/product/download/{id}:
    get:
      tags: [User]
      summary: Download a purchased digital product
      security:
        - bearerAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema: { type: integer }
      responses:
        "200":
          description: Binary file download response.
          content:
            application/octet-stream:
              schema:
                type: string
                format: binary
        "403":
          description: The current customer has not purchased this digital product.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /user/order/cancel/{order_id}:
    post:
      tags: [User]
      summary: Cancel an order
      security:
        - bearerAuth: []
      parameters:
        - name: order_id
          in: path
          required: true
          schema: { type: integer }
      responses:
        "200":
          description: Cancellation result.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: "#/components/schemas/GenericMessageResponse"
                  - $ref: "#/components/schemas/ErrorResponse"
  /user/review/check/{product_id}:
    get:
      tags: [User]
      summary: Check whether a product review can be submitted
      security:
        - bearerAuth: []
      parameters:
        - name: product_id
          in: path
          required: true
          schema: { type: integer }
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /user/review/submit:
    post:
      tags: [User]
      summary: Submit a product review
      security:
        - bearerAuth: []
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /user/wishlists:
    get:
      tags: [User]
      summary: List wishlist items
      security:
        - bearerAuth: []
      responses:
        "200": { $ref: "#/components/responses/Ok" }
    post:
      tags: [User]
      summary: Add a wishlist item
      security:
        - bearerAuth: []
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /user/wishlists/{wishlist}:
    delete:
      tags: [User]
      summary: Remove a wishlist item
      security:
        - bearerAuth: []
      parameters:
        - name: wishlist
          in: path
          required: true
          schema: { type: integer }
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /user/follow:
    get:
      tags: [User]
      summary: List followed shops or entities
      security:
        - bearerAuth: []
      responses:
        "200": { $ref: "#/components/responses/Ok" }
    post:
      tags: [User]
      summary: Follow a shop or entity
      security:
        - bearerAuth: []
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /user/follow/{follow}:
    delete:
      tags: [User]
      summary: Unfollow a shop or entity
      security:
        - bearerAuth: []
      parameters:
        - name: follow
          in: path
          required: true
          schema: { type: integer }
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /user/querries:
    get:
      tags: [Conversations]
      summary: List customer support queries
      security:
        - bearerAuth: []
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /user/new-query:
    post:
      tags: [Conversations]
      summary: Create a new support query
      security:
        - bearerAuth: []
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /user/querries/{id}:
    get:
      tags: [Conversations]
      summary: Get support query details
      security:
        - bearerAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema: { type: integer }
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /user/new-message-query:
    post:
      tags: [Conversations]
      summary: Send a message to a support query
      security:
        - bearerAuth: []
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /user/wallet/recharge:
    post:
      tags: [Wallet]
      summary: Recharge wallet balance
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/WalletRechargeRequest"
      responses:
        "200":
          description: Payment gateway initialization result for wallet top-up. Payload shape depends on the selected gateway.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
  /user/wallet/history:
    get:
      tags: [Wallet]
      summary: Get wallet recharge history
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Paginated wallet top-up history.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WalletHistoryResponse"
  /user/earning/history:
    get:
      tags: [Club Points]
      summary: Get club point earning history
      security:
        - bearerAuth: []
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /user/convert-point-into-wallet:
    post:
      tags: [Club Points]
      summary: Convert club points into wallet balance
      security:
        - bearerAuth: []
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /user/refund-requests:
    get:
      tags: [Refunds]
      summary: List refund requests
      security:
        - bearerAuth: []
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /user/refund-request/create/{order_id}:
    get:
      tags: [Refunds]
      summary: Get refund request creation context
      security:
        - bearerAuth: []
      parameters:
        - name: order_id
          in: path
          required: true
          schema: { type: integer }
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /user/refund-request/store:
    post:
      tags: [Refunds]
      summary: Submit a refund request
      security:
        - bearerAuth: []
      responses:
        "200": { $ref: "#/components/responses/Ok" }

  /user/affiliate/convert-request:
    post:
      tags: [Affiliate]
      summary: Convert affiliate balance to wallet
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [amount]
              properties:
                amount:
                  type: number
                  format: float
                  minimum: 1
      responses:
        "200":
          description: Affiliate-to-wallet conversion result.
          content:
            application/json:
              schema:
                type: object
                properties:
                  result:
                    type: boolean
                  success:
                    type: boolean
                  data:
                    type: number
                    format: float
                    nullable: true
                  message:
                    type: string
  /user/affiliate/withdraw-request:
    post:
      tags: [Affiliate]
      summary: Create an affiliate withdraw request
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [amount]
              properties:
                amount:
                  type: number
                  format: float
                  minimum: 1
      responses:
        "200":
          description: Withdraw request creation result.
          content:
            application/json:
              schema:
                type: object
                properties:
                  result:
                    type: boolean
                  data:
                    type: number
                    format: float
                    nullable: true
                  message:
                    type: string
    get:
      tags: [Affiliate]
      summary: List affiliate withdraw requests
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Paginated affiliate withdraw requests.
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/AffiliateWithdrawRequestItem"
                  links:
                    type: object
                    nullable: true
                    additionalProperties: true
                  meta:
                    type: object
                    nullable: true
                    additionalProperties: true
  /user/affiliate/payment-history:
    get:
      tags: [Affiliate]
      summary: Get affiliate payment history
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Paginated affiliate payout history.
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/AffiliatePaymentHistoryItem"
                  links:
                    type: object
                    nullable: true
                    additionalProperties: true
                  meta:
                    type: object
                    nullable: true
                    additionalProperties: true
  /user/affiliate/earning-history:
    get:
      tags: [Affiliate]
      summary: Get affiliate earning history
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Paginated affiliate earnings history.
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/AffiliateEarningHistoryItem"
                  links:
                    type: object
                    nullable: true
                    additionalProperties: true
                  meta:
                    type: object
                    nullable: true
                    additionalProperties: true
  /user/affiliate/payment-settings:
    post:
      tags: [Affiliate]
      summary: Update affiliate payment settings
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                paypalEmail:
                  type: string
                  format: email
                  nullable: true
                bankInformations:
                  type: string
                  nullable: true
      responses:
        "200":
          description: Payment settings update result.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GenericMessageResponse"
  /user/affiliate/balance:
    get:
      tags: [Affiliate]
      summary: Get affiliate balance
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Current formatted affiliate balance.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AffiliateBalanceResponse"
  /user/affiliate/referral-code:
    get:
      tags: [Affiliate]
      summary: Get affiliate referral code
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Affiliate referral link for the authenticated user.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AffiliateReferralCodeResponse"
  /user/affiliate/stats:
    get:
      tags: [Affiliate]
      summary: Get affiliate statistics
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Aggregate affiliate click/order/delivery metrics.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AffiliateStatPayload"
  /user/affiliate/user-check:
    get:
      tags: [Affiliate]
      summary: Validate affiliate user status
      security:
        - bearerAuth: []
      parameters:
        - name: shop_id
          in: query
          required: false
          schema:
            type: integer
        - name: shop_slug
          in: query
          required: false
          schema:
            type: string
      responses:
        "200":
          description: Affiliate eligibility and referral-code summary for the current user.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AffiliateUserCheckResponse"
  /user/affiliate/commission-panel:
    get:
      tags: [Affiliate]
      summary: Get affiliate commission panel data
      security:
        - bearerAuth: []
      parameters:
        - name: shop_id
          in: query
          required: false
          schema:
            type: integer
        - name: shop_slug
          in: query
          required: false
          schema:
            type: string
      responses:
        "200":
          description: Commission program overview including binary, unilevel, and rank-bonus data.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AffiliateCommissionPanelResponse"
  /user/affiliate/network-tree:
    get:
      tags: [Affiliate]
      summary: Get affiliate network tree
      security:
        - bearerAuth: []
      parameters:
        - name: shop_id
          in: query
          required: false
          schema:
            type: integer
        - name: shop_slug
          in: query
          required: false
          schema:
            type: string
      responses:
        "200":
          description: Affiliate downline tree for the authenticated user.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AffiliateNetworkTreeResponse"
  /user/affiliate/store:
    post:
      tags: [Affiliate]
      summary: Store affiliate details for authenticated user
      security:
        - bearerAuth: []
      responses:
        "200": { $ref: "#/components/responses/Ok" }

  /user/seller/shop/countries:
    get:
      tags: [Seller Scope]
      summary: Get current seller shop country availability
      security:
        - bearerAuth: []
      responses:
        "200": { $ref: "#/components/responses/Ok" }
    post:
      tags: [Seller Scope]
      summary: Update seller shop country availability
      security:
        - bearerAuth: []
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /user/seller/product/{productId}/countries:
    get:
      tags: [Seller Scope]
      summary: Get product country setup
      security:
        - bearerAuth: []
      parameters:
        - name: productId
          in: path
          required: true
          schema: { type: integer }
      responses:
        "200": { $ref: "#/components/responses/Ok" }
    post:
      tags: [Seller Scope]
      summary: Update product country setup
      security:
        - bearerAuth: []
      parameters:
        - name: productId
          in: path
          required: true
          schema: { type: integer }
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /user/seller/product/{productId}/country-pricing:
    post:
      tags: [Seller Scope]
      summary: Update product country-specific pricing
      security:
        - bearerAuth: []
      parameters:
        - name: productId
          in: path
          required: true
          schema: { type: integer }
      responses:
        "200": { $ref: "#/components/responses/Ok" }

  /delivery-boy/dashboard:
    get:
      tags: [Delivery Boy]
      summary: Get delivery boy dashboard data
      security:
        - bearerAuth: []
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /delivery-boy/collections-list:
    get:
      tags: [Delivery Boy]
      summary: Get delivery collections list
      security:
        - bearerAuth: []
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /delivery-boy/earnings-list:
    get:
      tags: [Delivery Boy]
      summary: Get delivery earnings list
      security:
        - bearerAuth: []
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /delivery-boy/assigned-deliveries:
    get:
      tags: [Delivery Boy]
      summary: Get assigned deliveries
      security:
        - bearerAuth: []
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /delivery-boy/cancel-deliveries:
    get:
      tags: [Delivery Boy]
      summary: Get canceled deliveries
      security:
        - bearerAuth: []
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /delivery-boy/completed-deliveries:
    get:
      tags: [Delivery Boy]
      summary: Get completed deliveries
      security:
        - bearerAuth: []
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /delivery-boy/pending-deliveries:
    get:
      tags: [Delivery Boy]
      summary: Get pending deliveries
      security:
        - bearerAuth: []
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /delivery-boy/picked-up-deliveries:
    get:
      tags: [Delivery Boy]
      summary: Get picked-up deliveries
      security:
        - bearerAuth: []
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /delivery-boy/on-the-way-deliveries:
    get:
      tags: [Delivery Boy]
      summary: Get on-the-way deliveries
      security:
        - bearerAuth: []
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /delivery-boy/update-delivery-status:
    post:
      tags: [Delivery Boy]
      summary: Update delivery status
      security:
        - bearerAuth: []
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /delivery-boy/cancel-request:
    post:
      tags: [Delivery Boy]
      summary: Submit a cancel request
      security:
        - bearerAuth: []
      responses:
        "200": { $ref: "#/components/responses/Ok" }

  /user/order/{order_code}:
    get:
      tags: [User]
      summary: Get customer order details
      security:
        - bearerAuth: []
      parameters:
        - name: order_code
          in: path
          required: true
          schema: { type: string }
      responses:
        "200": { $ref: "#/components/responses/Ok" }

  /shop/register:
    post:
      tags: [Shops]
      summary: Register a new shop
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /all-shops:
    get:
      tags: [Shops]
      summary: List all shops
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /shop/{slug}:
    get:
      tags: [Shops]
      summary: Get shop details
      parameters:
        - name: slug
          in: path
          required: true
          schema: { type: string }
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /shop/{slug}/home:
    get:
      tags: [Shops]
      summary: Get shop home data
      parameters:
        - name: slug
          in: path
          required: true
          schema: { type: string }
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /shop/{slug}/coupons:
    get:
      tags: [Shops]
      summary: Get shop coupons
      parameters:
        - name: slug
          in: path
          required: true
          schema: { type: string }
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /shop/{slug}/products:
    get:
      tags: [Shops]
      summary: Get shop products
      parameters:
        - name: slug
          in: path
          required: true
          schema: { type: string }
      responses:
        "200": { $ref: "#/components/responses/Ok" }

  /affiliate/store:
    post:
      tags: [Affiliate]
      summary: Register or update affiliate data
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /affiliate/registration-refferal-code:
    post:
      tags: [Affiliate]
      summary: Validate legacy affiliate registration referral code spelling
      deprecated: true
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /affiliate/registration-referral-code:
    post:
      tags: [Affiliate]
      summary: Validate affiliate registration referral code
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /affiliate/balance-check:
    get:
      tags: [Affiliate]
      summary: Check affiliate balance
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /product-refferal-code:
    post:
      tags: [Affiliate]
      summary: Generate or validate product referral code using legacy spelling
      deprecated: true
      responses:
        "200": { $ref: "#/components/responses/Ok" }
  /product-referral-code:
    post:
      tags: [Affiliate]
      summary: Generate or validate product referral code
      responses:
        "200": { $ref: "#/components/responses/Ok" }

  /recaptcha/verify:
    post:
      tags: [Security]
      summary: Verify a reCAPTCHA token
      responses:
        "200": { $ref: "#/components/responses/Ok" }
