openapi: 3.0.1
info:
  title: Storefront APIs
  description: ''
servers:
  - url: https://loyalty-admin.appstle.com
tags:
  - name: Storefront APIs
    description: >-
      Customer-facing loyalty program APIs for storefront operations. These
      endpoints allow customers to manage their loyalty account, earn and redeem
      points, submit reviews, handle referrals, and track their rewards. All
      endpoints require customer authentication via JWT token.
paths:
  /loyalty/cp/api/update-customer-status:
    post:
      tags:
        - Storefront APIs
      summary: Update customer loyalty status
      description: >-
        Updates the loyalty program status for the authenticated customer.
        Allows customers to opt-in, opt-out, or exclude themselves from the
        loyalty program. Status changes are logged in the activity log with
        appropriate event types (CUSTOMER_EXCLUDED, CUSTOMER_INCLUDED). When a
        customer is excluded, they stop earning points but retain existing
        points and rewards.
      operationId: updateCustomerStatus
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CustomerBirthDateRequestVM'
        required: true
      responses:
        '200':
          description: Customer status updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Customer'
        '400':
          description: Invalid customer status
        '401':
          description: Customer not authenticated
  /loyalty/cp/api/update-customer-birth-date:
    post:
      tags:
        - Storefront APIs
      summary: Update customer birth date
      description: >-
        Updates the birth date for the authenticated customer and potentially
        awards birthday-related loyalty points. Once set, the customer may
        receive birthday rewards annually. The birth date is validated and
        stored in the customer's loyalty profile.
      operationId: addCustomerBirthDate
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CustomerBirthDateRequestVM'
        required: true
      responses:
        '200':
          description: Customer birth date updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Customer'
        '400':
          description: Invalid birth date format
        '401':
          description: Customer not authenticated
  /loyalty/cp/api/update-customer:
    post:
      tags:
        - Storefront APIs
      summary: Sync customer metafield data
      description: >-
        Synchronizes the authenticated customer's metafield data with Shopify.
        This endpoint triggers an immediate sync of customer loyalty information
        (points, tier, etc.) to Shopify metafields. Useful when customer data
        needs to be refreshed in Shopify for theme display or other
        integrations.
      operationId: updateCustomerMetafield
      responses:
        '200':
          description: Customer data synchronized successfully
        '401':
          description: Customer not authenticated
        '500':
          description: Error synchronizing customer data
  /loyalty/cp/api/submit-review:
    post:
      tags:
        - Storefront APIs
      summary: Submit product review
      description: >
        Submits a product review and potentially awards loyalty points.


        **Two ways to submit reviews:**


        **1. Order-linked review (recommended):**

        - Include uniqueId in request (unique identifier for purchased product)

        - Product details auto-filled from order

        - Verifies customer actually purchased the product

        - More trustworthy for other customers


        **2. General review:**

        - Omit uniqueId

        - Manually provide productId, productTitle, productImage

        - Customer can review any product

        - May not qualify for "verified purchase" points


        **Required fields:**

        - rating: 1-5 stars (integer)

        - title: Review headline (string)

        - body: Review content (string)

        - Either uniqueId OR (productId + productTitle)


        **Optional fields:**

        - productImage: URL to product image

        - reviewerName: Override customer name (defaults to account name)

        - images: Array of review image URLs

        - carouselStatus: Feature in carousel widget (boolean)

        - pinnedStatus: Pin to top of reviews (boolean)


        **Point earning:**

        - Points awarded based on "Product Review" earn rule

        - Points may be pending approval or immediate

        - Only first review per product typically earns points

        - Some merchants require review approval before points

        - Points processed asynchronously after submission


        **Review moderation:**

        - Reviews are published immediately by default

        - Can be configured to require admin approval

        - Check your loyalty settings for moderation rules

        - publishedStatus field controls visibility


        **Image support:**

        - Customers can attach images to reviews

        - Images must be publicly accessible URLs

        - Recommended to upload to your CDN first

        - Multiple images supported (array)


        **Review display features:**

        - carouselStatus=true: Shows in rotating carousel widget

        - pinnedStatus=true: Appears at top of product reviews

        - Both useful for highlighting exceptional reviews


        **Authentication:**

        Requires customer JWT token. The authenticated customer is the review
        author.


        **Validation rules:**

        - Rating must be 1, 2, 3, 4, or 5

        - Title and body cannot be empty

        - Product must exist in catalog

        - If uniqueId provided, must be from customer's orders

        - Customer cannot review same product multiple times (configurable)


        **Processing flow:**

        1. Validate review data

        2. Create review record in database

        3. Publish review (or queue for approval)

        4. Trigger async process for point calculation

        5. Award points if eligible

        6. Send confirmation email (if configured)

        7. Update product review statistics


        **Response:**

        Returns success message immediately.

        Points may take a few seconds to appear in account due to async
        processing.


        **Best practices:**

        1. Use uniqueId when available for verified purchases

        2. Encourage customers with point incentives

        3. Display point reward amount before review form

        4. Validate form data client-side before submission

        5. Show success message with expected point amount

        6. Explain points may take a moment to appear

        7. Provide preview of how review will look


        **Example review submission flow:**

        ```

        1. Customer views "Write a Review" page for product

        2. Form shows: "Earn 50 points for reviewing this product!"

        3. Customer fills out rating, title, body

        4. Optionally uploads images

        5. Clicks "Submit Review"

        6. Call this endpoint

        7. Show success: "Thank you! Your review has been submitted and 50
        points will be added to your account shortly."

        8. Redirect to product page or review confirmation page

        ```


        **Error handling:**

        - 400: Invalid data (missing fields, invalid rating, etc.)

        - 401: Not authenticated

        - 500: Server error (retry or contact support)
      operationId: submitReview
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ProductReview'
        required: true
      responses:
        '200':
          description: >-
            Review submitted successfully. Points will be awarded asynchronously
            if eligible.
          content:
            application/json:
              schema:
                type: string
              example: Review successfully submitted; it will reflect shortly.
        '400':
          description: Invalid review data or missing required fields
          content:
            application/json:
              schema:
                type: string
                example:
                  error: Invalid request
                  details: Rating must be between 1 and 5
        '401':
          description: Customer not authenticated
          content:
            application/json:
              schema:
                type: string
                example:
                  error: Authentication required
        '500':
          description: Error processing review submission
          content:
            application/json:
              schema:
                type: string
                example:
                  error: Failed to submit review. Please try again.
  /loyalty/cp/api/send-customer-referral-url:
    post:
      tags:
        - Storefront APIs
      summary: Send customer referral email
      description: >
        Sends a referral invitation email to a friend on behalf of the
        authenticated customer.


        **How referrals work:**

        1. Customer sends referral email to friend

        2. Friend receives email with unique referral link

        3. Friend clicks link and creates account/makes purchase

        4. Both customer (referrer) and friend (referee) may receive rewards

        5. Rewards based on referral rule configuration


        **Request body:**

        - email: Friend's email address (required, must be valid)

        - Can include additional fields like name, message (check your
        configuration)


        **Email content:**

        - Contains customer's unique referral link

        - Describes referral rewards (e.g., "You get $10 off, they get $10 off")

        - Uses your configured email template

        - Branded with your store logo and colors

        - Includes call-to-action button


        **Rate limiting:**

        - Default limit: 500 emails per shop per day

        - Prevents spam and abuse

        - 429 error if limit exceeded

        - Limit resets daily

        - Contact support to adjust limits if needed


        **Activity logging:**

        - Each send is logged for analytics

        - Track referral email performance

        - Monitor for fraudulent activity

        - View in admin dashboard


        **Referral tracking:**

        - Unique referral link embedded in email

        - Tracks when friend clicks link

        - Attributes purchase to referrer

        - Shows in customer's referral history


        **Authentication:**

        Requires customer JWT token. The authenticated customer is the referrer.


        **Validation:**

        - Email address format validation

        - Duplicate email checking (optional)

        - Customer must be enrolled in loyalty program

        - Referral program must be active

        - Customer not excluded from program


        **Best practices:**

        1. Allow customers to preview email before sending

        2. Show referral incentives clearly

        3. Provide email template customization

        4. Track success rate and optimize messaging

        5. Consider social sharing alternatives

        6. Display referral link prominently for manual sharing

        7. Limit sends per customer to prevent spam


        **Example UI flow:**

        ```

        1. Customer enters friend's email

        2. Optional: Add personal message

        3. Preview email content

        4. Click "Send Invitation"

        5. Call this endpoint

        6. Show success message

        7. Update referral count display

        8. Add to "Sent Invitations" list

        ```


        **Error scenarios:**

        - Invalid email format: 400 error

        - Rate limit exceeded: 429 error (show retry time)

        - Customer not enrolled: 400 error

        - Referral program inactive: 400 error

        - Email service failure: 500 error (retry)


        **Success response:**

        Returns 200 with no body. Email sent successfully.


        **Alternative sharing methods:**

        Instead of email, customers can also:

        - Copy referral link directly (GET referral URL first)

        - Share on social media

        - Use QR code

        - Share via SMS (if configured)
      operationId: sendCustomerReferralUrl
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SendReferralLinkEmail'
        required: true
      responses:
        '200':
          description: Referral email sent successfully
        '400':
          description: Invalid email address or missing email
          content:
            application/json:
              schema:
                type: string
                example:
                  error: Invalid email address
                  details: Please provide a valid email address
        '401':
          description: Customer not authenticated
          content:
            application/json:
              schema:
                type: string
                example:
                  error: Authentication required
        '429':
          description: Rate limit exceeded for sending referral emails
          content:
            application/json:
              schema:
                type: string
                example:
                  error: Rate limit exceeded
                  details: >-
                    Maximum 500 referral emails per day. Please try again
                    tomorrow.
                  retryAfter: '2025-01-30T00:00:00Z'
  /loyalty/cp/api/redeem-points:
    post:
      tags:
        - Storefront APIs
      summary: Redeem customer loyalty points
      description: >
        Allows the authenticated customer to redeem their loyalty points for
        rewards.


        **Redemption flow:**

        1. Customer selects a reward from available options

        2. Frontend calls this endpoint with redeemRuleId

        3. System validates customer has sufficient points

        4. Points are deducted from available balance

        5. Discount code is created in Shopify

        6. Reward record is created with status "UNUSED"

        7. Transaction is logged

        8. Updated loyalty info is returned

        9. Customer receives discount code to use at checkout


        **Request body fields:**

        - redeemRuleId: ID of reward to redeem (required)
          Get available options from GET /loyalty/cp/api/customer-loyalty
        - points: Override default points (optional)
          If not provided, uses the redemption rule's default point value
        - variantId: Required for product-specific rewards (optional)
          Shopify variant ID for "free product" type rewards

        **Authentication:**

        Requires customer JWT token. The authenticated customer is the one
        redeeming points.

        Cannot redeem points on behalf of another customer.


        **Validation checks:**

        - Customer is authenticated

        - Customer has sufficient availablePoints

        - Redemption rule exists and is active

        - For product rewards, variantId is provided

        - Customer is enrolled in loyalty program

        - Customer status is ACTIVE (not excluded)


        **What happens to points:**

        - Deducted from availablePoints immediately

        - Added to lifetime spending total

        - Transaction created with type "REDEEMED"

        - Cannot be undone (points deduction is final)


        **Discount code generation:**

        - For discounts: Creates Shopify discount code

        - Code is unique per customer

        - Has expiry date if configured

        - Minimum purchase amount if configured

        - Product/collection restrictions if configured


        **Store credit rewards:**

        - Adds value to storeCreditBalance instead of creating discount code

        - Can be used as payment method at checkout

        - Managed separately from Shopify discount codes


        **Error scenarios:**

        - Insufficient points: availablePoints < required points

        - Invalid rule: redeemRuleId doesn't exist or is inactive

        - Missing variantId: Required for product rewards

        - Customer not enrolled: Must enroll first

        - Customer excluded: EXCLUDED or EXCLUDED_BY_CUSTOMER status

        - System error: Shopify API failure, discount code creation failure


        **Best practices:**

        1. Check availablePoints before showing redemption options

        2. Display point cost clearly to customer

        3. Show expected reward (discount %, amount, etc.)

        4. Handle errors gracefully with clear messages

        5. After success, show discount code prominently

        6. Provide copy-to-clipboard functionality for code

        7. Explain when/how to use the discount code


        **Example response handling:**

        ```javascript

        // After successful redemption

        const response = await redeemPoints(ruleId);

        // Find the newly created reward

        const newReward = response.rewards.find(r => r.status === 'UNUSED');

        // Display to customer

        showDiscountCode(newReward.discountCode, newReward.expiryDate);

        ```


        **Common UI flow:**

        1. Display available redemption options with point costs

        2. Customer clicks "Redeem"

        3. Show confirmation dialog with point cost

        4. Call this endpoint

        5. On success: Show discount code in modal/banner

        6. Update points display with new balance

        7. Add code to "My Rewards" list
      operationId: redeemPoints
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CustomerLoyaltyRequestVM'
      responses:
        '200':
          description: >-
            Points redeemed successfully, returns updated customer loyalty
            information with new reward
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CustomerLoyaltyResponseVM'
              example:
                availablePoints: 150
                pendingPoints: 25
                creditedPoints: 500
                rewards:
                  - id: 12346
                    discountCode: LOYALTY15OFF
                    discountType: PERCENTAGE
                    discountValue: 15
                    status: UNUSED
                    expiryDate: '2025-06-30T23:59:59Z'
                    pointsRedeemed: 100
                    createAt: '2025-01-29T10:30:00Z'
                currentVipTier: Gold
        '400':
          description: Invalid redemption request or insufficient points
          content:
            application/json:
              schema:
                type: string
                example:
                  error: Insufficient points
                  availablePoints: 50
                  requiredPoints: 100
        '401':
          description: Customer not authenticated - JWT token missing or invalid
          content:
            application/json:
              schema:
                type: string
                example:
                  error: Authentication required
  /loyalty/cp/api/enroll-customer:
    post:
      tags:
        - Storefront APIs
      summary: Enroll customer in loyalty program
      description: >-
        Enrolls the authenticated customer in the loyalty program and optionally
        assigns them to a specific VIP tier. This endpoint activates all loyalty
        features for the customer, allowing them to earn and redeem points. If a
        VIP tier is specified, the customer is automatically placed in that tier
        upon enrollment. Creates necessary customer records and triggers any
        welcome rewards configured in the system.
      operationId: EnrollCustomer
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/EnrollCustomerRequestVM'
        required: true
      responses:
        '200':
          description: Customer enrolled successfully
          content:
            application/json:
              schema:
                type: string
              example: Customer added successfully.
        '400':
          description: Invalid VIP tier or enrollment failed
        '401':
          description: Customer not authenticated
  /loyalty/cp/api/enable-loyalty-program:
    post:
      tags:
        - Storefront APIs
      summary: Enable loyalty program for customer
      description: >-
        Enables the loyalty program for the authenticated customer, allowing
        them to earn and redeem points. This is a simplified version of the
        enroll-customer endpoint that doesn't require any request body. Useful
        for quick customer opt-in flows without tier assignment.
      operationId: EnrollCustomer_1
      responses:
        '200':
          description: Loyalty program enabled successfully
          content:
            application/json:
              schema:
                type: string
              example: Customer added successfully.
        '401':
          description: Customer not authenticated
        '500':
          description: Error enabling loyalty program
  /loyalty/cp/api/customer-visit-store:
    post:
      tags:
        - Storefront APIs
      summary: Track customer store visit
      description: >-
        Records a customer store visit and potentially awards loyalty points
        based on the shop's visit reward rules. This endpoint is typically
        called when a customer visits the storefront or specific pages. Includes
        rate limiting protection to prevent abuse - customers can only earn
        visit points up to a configured limit per day/period. The endpoint
        enforces a request limit (default 500) to prevent excessive API calls.
      operationId: customerVisitStore
      responses:
        '200':
          description: Store visit recorded successfully
        '401':
          description: Customer not authenticated
        '429':
          description: Rate limit exceeded for this customer
  /loyalty/cp/api/claim-social-media-points:
    post:
      tags:
        - Storefront APIs
      summary: Claim social media reward points
      description: >-
        Allows a customer to claim loyalty points for social media engagement
        (Facebook like, Instagram follow, etc.) based on the specified earn
        rule. Each social media action can typically only be claimed once per
        customer. The system tracks which social media rewards have been claimed
        to prevent duplicate claims.
      operationId: claimSocialMediaPoints
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SocialMediaPoints'
        required: true
      responses:
        '200':
          description: Social media points claimed successfully
        '400':
          description: Invalid earn rule ID or already claimed
        '401':
          description: Customer not authenticated
  /loyalty/cp/api/add-customer-referral-url:
    post:
      tags:
        - Storefront APIs
      summary: Generate customer referral URL
      description: >-
        Creates and stores a short referral URL for the authenticated customer
        to share with potential referrals. The referral link is typically
        generated once and then can be shared via email, social media, or other
        channels. When new customers use this link, both the referrer and
        referee may receive rewards.
      operationId: addCustomerReferalUrl
      responses:
        '200':
          description: Referral URL generated successfully
        '401':
          description: Customer not authenticated
        '500':
          description: Error generating referral URL
  /loyalty/cp/api/referral-rules/accept-offer:
    get:
      tags:
        - Storefront APIs
      summary: Accept referral offer (GET)
      description: >-
        Accepts a referral offer using the referral token and email address via
        query parameters. This is a convenience endpoint that provides the same
        functionality as the POST version but via GET request. Useful for simple
        referral link implementations where query parameters are easier to
        construct. Creates a new customer referral record and may generate a
        welcome discount code for the referee.
      operationId: acceptReferralOffer
      parameters:
        - name: token
          in: query
          description: Referral token received from the referrer
          required: true
          schema:
            type: string
          example: abc123referraltoken
        - name: email
          in: query
          description: Email address of the person accepting the referral
          required: true
          schema:
            type: string
          example: newcustomer@example.com
      responses:
        '201':
          description: Referral offer accepted successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReferralAcceptResponse'
              example:
                id: 12345
                message: Referral accepted successfully
                discountCode: WELCOME20
                status: SUCCESS
        '400':
          description: >-
            Invalid token or email, referral already accepted, or referral
            program not available
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReferralAcceptResponse'
    post:
      tags:
        - Storefront APIs
      summary: Accept referral offer (POST)
      description: |
        Accepts a referral offer when a new customer uses a referral link.

        **Referral flow overview:**
        1. Existing customer (referrer) shares referral link
        2. New customer (referee) clicks link
        3. Link contains unique token
        4. New customer signs up or browses
        5. Call this endpoint with token and email
        6. System creates referral record
        7. May generate welcome discount for referee
        8. Referrer gets points when referee makes purchase

        **Request body:**
        - token: Unique referral token from URL (required)
        - email: New customer's email address (required)

        **What this endpoint does:**
        1. Validates referral token is valid
        2. Checks referral program is active
        3. Verifies referee hasn't used a referral before
        4. Creates referral record linking referee to referrer
        5. Generates welcome discount code (if configured)
        6. May award immediate points to referee
        7. Tracks referral for future reward distribution
        8. Returns discount code for referee to use

        **Referral rewards configuration:**
        Different merchants configure different rewards:
        - Referee discount: Welcome discount for new customer
        - Referrer points: Points when referee makes purchase
        - Both rewards: Both parties get something
        - Tiered rewards: More for higher-value purchases

        **Token validation:**
        - Token must exist in system
        - Token must belong to active customer
        - Customer must have referral program enabled
        - Token has no expiration (typically)
        - Each token is unique per customer

        **Duplicate prevention:**
        - Email can only accept one referral
        - Cannot accept own referral
        - Cannot accept multiple referrals
        - First referral link used is the one that counts

        **Response includes:**
        - id: Referral record ID
        - message: Success or error message
        - discountCode: Welcome discount for referee (if applicable)
        - status: SUCCESS or ERROR

        **Integration points:**

        **Option 1: Signup page integration**
        ```javascript
        // During signup process
        const urlParams = new URLSearchParams(window.location.search);
        const referralToken = urlParams.get('token');
        if (referralToken) {
          // After customer enters email
          await acceptReferral(referralToken, customerEmail);
          // Show welcome discount to customer
        }
        ```

        **Option 2: Landing page integration**
        ```javascript
        // On referral landing page
        const token = getReferralToken();
        document.getElementById('claimButton').onclick = async () => {
          const email = document.getElementById('email').value;
          const response = await acceptReferral(token, email);
          showDiscountCode(response.discountCode);
        };
        ```

        **Referral tracking states:**
        - PENDING: Referral accepted, waiting for first purchase
        - COMPLETED: Referee made qualifying purchase, rewards distributed
        - EXPIRED: Referral expired before qualifying purchase

        **Best practices:**
        1. Call this endpoint early in customer journey
        2. Store referral token in cookie/session if email not available yet
        3. Show welcome discount prominently after acceptance
        4. Explain referral benefits clearly
        5. Handle already-accepted gracefully
        6. Track conversion rate of referrals
        7. A/B test referral incentives

        **Common error scenarios:**
        - Invalid token: Token doesn't exist or is malformed
        - Referral program inactive: Store disabled referrals
        - Already accepted: This email already used a referral
        - Self-referral: Customer trying to refer themselves
        - Token from excluded customer: Referrer is excluded from program

        **When rewards are distributed:**
        - Referee: Welcome discount immediately on acceptance
        - Referrer: Points awarded when referee makes first purchase
        - Both: May get additional rewards for repeat purchases
      operationId: acceptReferralOfferPost
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReferralAcceptRequest'
        required: true
      responses:
        '201':
          description: Referral offer accepted successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReferralAcceptResponse'
              example:
                id: 12345
                message: >-
                  Referral accepted successfully! Use code WELCOME20 for 20% off
                  your first order.
                discountCode: WELCOME20
                status: SUCCESS
        '400':
          description: >-
            Invalid token or email, referral already accepted, or referral
            program not available
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReferralAcceptResponse'
              example:
                id: null
                message: This email has already been referred by another customer
                discountCode: null
                status: ERROR
  /loyalty/cp/api/transaction-by-shop:
    get:
      tags:
        - Storefront APIs
      summary: Get customer point transaction history
      description: >-
        Retrieves paginated list of point transactions for the authenticated
        customer, ordered by ID descending (most recent first). Each transaction
        includes details about points earned or spent, transaction type, status
        (PENDING, APPROVED, REJECTED), associated order information, and
        timestamps. Useful for displaying transaction history to customers.
      operationId: getAllPointTransactionsByCustomer
      parameters:
        - name: pageable
          in: query
          description: Pagination parameters (page number, size, sort)
          required: true
          schema:
            $ref: '#/components/schemas/Pageable'
      responses:
        '200':
          description: >-
            Point transactions retrieved successfully with pagination headers
            (X-Total-Count, Link)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PointTransaction'
              example:
                - id: 12345
                  shop: example-store.myshopify.com
                  customerId: 67890
                  points: 50
                  pointType: EARNED
                  note: Points earned for purchase
                  status: APPROVED
                  transactionRule: ORDER_PLACED
                  createAt: '2025-01-15T10:30:00Z'
                  spentAmount: 99.99
        '401':
          description: Customer not authenticated
  /loyalty/cp/api/logged-in-customer:
    get:
      tags:
        - Storefront APIs
      summary: Get logged-in customer ID
      description: >-
        Retrieves the customer ID of the currently authenticated user. This
        endpoint is useful for obtaining the customer ID after authentication to
        use in other API calls.
      operationId: getLoggedInCustomer
      responses:
        '200':
          description: Customer ID retrieved successfully
          content:
            application/json:
              schema:
                type: integer
                format: int64
              example: 12345
        '401':
          description: Customer not authenticated
  /loyalty/cp/api/customer-referrals:
    get:
      tags:
        - Storefront APIs
      summary: Get customer referral history
      description: >-
        Retrieves paginated list of referrals made by the authenticated
        customer. Each entry includes the referred email, referral status
        (PENDING, COMPLETED, EXPIRED), associated points earned, and timestamps.
        Useful for displaying referral tracking dashboards.
      operationId: getAllCustomerReferrals
      parameters:
        - name: pageable
          in: query
          description: Pagination parameters (page number, size, sort)
          required: true
          schema:
            $ref: '#/components/schemas/Pageable'
      responses:
        '200':
          description: >-
            Customer referrals retrieved successfully with pagination headers
            (X-Total-Count, Link)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CustomerReferral'
              example:
                - id: 12345
                  shop: example-store.myshopify.com
                  customerId: 67890
                  referredEmailId: friend@example.com
                  description: Referred friend via email
                  referralRuleId: 1
                  status: PENDING
                  createAt: '2025-01-15T10:30:00Z'
        '401':
          description: Customer not authenticated
  /loyalty/cp/api/customer-loyalty:
    get:
      tags:
        - Storefront APIs
      summary: Get customer loyalty information
      description: >
        Retrieves comprehensive loyalty information for the currently
        authenticated customer.


        **Primary use case:**

        This is the main endpoint for displaying a customer's loyalty dashboard.
        Call this endpoint

        when a customer views their loyalty page to show all their points,
        rewards, and program status.


        **What you'll get:**

        - Current point balances (available, pending, total credited)

        - Store credit balance (if applicable)

        - VIP tier information and expiration

        - List of rewards/discount codes

        - Social media engagement tracking

        - Referral statistics and link

        - Account creation date

        - Customer status in loyalty program


        **Authentication:**

        Requires JWT token for the customer. The token identifies which
        customer's data to retrieve.

        Customer must be authenticated via Shopify customer login.


        **Filtering rewards by status:**

        Use the optional 'status' query parameter to filter rewards:

        - UNUSED: Show only unused discount codes

        - USED: Show only used/redeemed codes

        - EXPIRED: Show only expired codes

        - Multiple: "UNUSED,USED" for multiple statuses

        - Omit parameter to get all rewards regardless of status


        **Point balance fields explained:**

        - availablePoints: Points customer can redeem RIGHT NOW

        - pendingPoints: Points awaiting approval (e.g., from pending orders)

        - creditedPoints: Total points earned all-time (including spent points)

        - Relationship: creditedPoints = availablePoints + pendingPoints +
        spentPoints


        **VIP tier information:**

        - currentVipTier: Name of customer's current tier (null if not in a
        tier)

        - vipTierExpiredAt: When tier expires (null if permanent or not in tier)

        - achievableTierId: Next tier customer can reach


        **Social media tracking (boolean flags):**

        - rewardedForFacebook: Claimed Facebook like/follow points

        - rewardedForInstagram: Claimed Instagram follow points

        - rewardedForTwitter: Claimed Twitter follow points

        - rewardedForPinterest: Claimed Pinterest follow points

        - rewardedForYoutube: Claimed YouTube subscribe points

        - rewardedForTiktok: Claimed TikTok follow points

        - rewardedForNewsLetter: Claimed newsletter signup points

        - rewardedForSms: Claimed SMS subscription points

        - rewardedForCreatingAccount: Claimed account creation points

        - rewardedForSharingOnFacebook: Claimed Facebook share points

        - rewardedForSharingOnX: Claimed X (Twitter) share points


        **Referral information:**

        - referredCompleted: Number of successful referrals

        - referralLink: Unique URL for customer to share


        **Customer status values:**

        - ACTIVE: Actively enrolled in loyalty program

        - EXCLUDED: Excluded by admin

        - EXCLUDED_BY_CUSTOMER: Customer opted out


        **Common integration patterns:**

        1. Load loyalty dashboard: Call on page load

        2. After redemption: Call to get updated points and new reward

        3. After earning points: Call to show updated balance

        4. Real-time updates: Poll this endpoint or use webhooks


        **Performance tips:**

        - Cache response for 30-60 seconds on frontend

        - Don't call on every page view, only on loyalty pages

        - Use status parameter to reduce response size if needed
      operationId: getCustomerLoyalty
      parameters:
        - name: status
          in: query
          description: >-
            Filter rewards by status (comma-separated values). Allowed values:
            UNUSED, USED, EXPIRED
          required: false
          schema:
            type: string
          example: UNUSED,USED
      responses:
        '200':
          description: Customer loyalty information retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CustomerLoyaltyResponseVM'
              example:
                availablePoints: 150.5
                pendingPoints: 25
                creditedPoints: 175.5
                spentAmount: 299.99
                storeCreditBalance: 15
                currentVipTier: Gold
                vipTierExpiredAt: '2025-12-31T23:59:59Z'
                referredCompleted: 3
                referralLink: https://store.com/referral/abc123
                customerStatus: ACTIVE
                dob: '1990-05-15'
                rewardedForFacebook: true
                rewardedForInstagram: false
                rewards: []
        '400':
          description: Invalid status parameter
        '401':
          description: Customer not authenticated
  /loyalty/cp/api/product-review-details/{productId}:
    get:
      tags:
        - Storefront APIs
      summary: Get product reviews by product ID
      description: >-
        Retrieves paginated list of published product reviews for a specific
        product, with optional rating filtering. Only returns published and
        non-archived reviews to ensure quality content is displayed. Supports
        filtering by rating (1-5 stars) to allow customers to view reviews by
        satisfaction level. Reviews are returned with full details including
        reviewer name, rating, title, body, images, and timestamps.
      operationId: getAllProductReviewsByProductId
      parameters:
        - name: productId
          in: path
          description: ID of the product to get reviews for
          required: true
          schema:
            type: integer
            format: int64
          example: 12345
        - name: rating
          in: query
          description: Filter reviews by rating (1-5 stars)
          required: false
          schema:
            type: integer
            format: int32
          example: 5
        - name: page
          in: query
          description: Zero-based page index (0..N)
          required: false
          schema:
            minimum: 0
            type: integer
            default: 0
        - name: size
          in: query
          description: The size of the page to be returned
          required: false
          schema:
            minimum: 1
            type: integer
            default: 20
        - name: sort
          in: query
          description: >-
            Sorting criteria in the format: property,(asc|desc). Default sort
            order is ascending. Multiple sort criteria are supported.
          required: false
          schema:
            type: array
            items:
              type: string
      responses:
        '200':
          description: >-
            Product reviews retrieved successfully with pagination headers
            (X-Total-Count, Link)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProductReviewDTO'
              example:
                - title: Excellent product!
                  body: This product exceeded my expectations in every way.
                  rating: 5
                  publishedStatus: true
                  reviewerName: John Doe
                  productId: 12345
                  createAt: '2025-01-15T10:30:00Z'
                  productTitle: Premium Widget
                  productImage: https://cdn.shopify.com/image.jpg
        '400':
          description: Invalid product ID
components:
  schemas:
    CustomerBirthDateRequestVM:
      type: object
      properties:
        customerId:
          type: integer
          description: Unique identifier of the customer
          format: int64
          example: 0
        dob:
          type: string
          description: Customer date of birth
          format: date
          example: '2026-01-12'
        status:
          type: string
          description: Customer loyalty status
          enum:
            - ACTIVE
            - INACTIVE
            - EXCLUDED
            - EXCLUDED_BY_CUSTOMER
            - ACTIVE
            - INACTIVE
            - EXCLUDED
            - EXCLUDED_BY_CUSTOMER
      description: Customer birth date update request containing the date of birth
      example:
        customerId: 0
        dob: '2026-01-12'
        status: ACTIVE
    Customer:
      required:
        - availablePoints
        - createAt
        - customerId
        - pendingPoints
        - shop
      type: object
      properties:
        id:
          type: integer
          format: int64
        shop:
          type: string
        customerId:
          type: integer
          format: int64
        firstName:
          type: string
        lastName:
          type: string
        email:
          type: string
        status:
          type: string
          enum:
            - ACTIVE
            - INACTIVE
            - EXCLUDED
            - EXCLUDED_BY_CUSTOMER
        createAt:
          type: string
          format: date-time
        dob:
          type: string
          format: date
        enableEmail:
          type: boolean
        token:
          type: string
        redeemLimit:
          type: integer
          format: int64
        redeemLimitOnce:
          type: integer
          format: int64
        vipTier:
          type: string
        vipTierId:
          type: integer
          format: int64
        vipTierSummary:
          type: string
        availablePoints:
          type: number
          format: double
        pendingPoints:
          type: number
          format: double
        displayName:
          type: string
        vipTierExpiredAt:
          type: string
          format: date-time
        spentAmount:
          type: number
          format: double
        lastActivity:
          type: string
          format: date-time
        ordersCount:
          type: integer
          format: int32
        lastMonthlyReminderSentDate:
          type: string
          format: date-time
        redeemedPoints:
          type: number
          format: double
        lastRewardExpiryReminderSentDate:
          type: string
          format: date-time
        vipAssignType:
          type: string
          enum:
            - MANUAL
            - AUTO_RENEWAL
            - RENEWAL_ON_HIGHER_TIER
        phone:
          type: string
        loyaltyProgramEnabled:
          type: boolean
        emailSetting:
          type: string
        skipReview:
          type: boolean
        updatedSettings:
          type: string
        storeCreditAccountId:
          type: string
        emailBouncedOrFailed:
          type: boolean
        availableStoreCredits:
          type: number
          format: double
        isDeletedFromShopify:
          type: boolean
        enableEmailMarketing:
          type: boolean
        enableSmsMarketing:
          type: boolean
        tags:
          type: string
        vipTierAmount:
          type: number
          format: double
    ProductReview:
      required:
        - createAt
        - shop
      type: object
      properties:
        id:
          type: integer
          format: int64
        shop:
          type: string
        title:
          type: string
        body:
          type: string
        rating:
          type: integer
          format: int32
        publishedStatus:
          type: boolean
        reviewerName:
          type: string
        reviewerEmail:
          type: string
        productId:
          type: integer
          format: int64
        pinned:
          type: boolean
        archived:
          type: boolean
        createAt:
          type: string
          format: date-time
        replayBody:
          type: string
        replayDate:
          type: string
          format: date-time
        productTitle:
          type: string
        productHandle:
          type: string
        productImage:
          type: string
        originalReviewTitle:
          type: string
        originalReviewBody:
          type: string
        uniqueId:
          type: string
          format: uuid
        customerId:
          type: integer
          format: int64
        reviewEditReason:
          type: string
        carousel:
          type: boolean
        reviewSource:
          type: string
          enum:
            - WEB_PAGE
            - API
            - IMPORT
      description: >-
        Product review submission containing rating, title, body, product
        details, and optional uniqueId for order linking
    SendReferralLinkEmail:
      type: object
      properties:
        email:
          type: string
      description: Referral email request containing the recipient's email address
    CustomerLoyaltyRequestVM:
      required:
        - redeemRuleId
      type: object
      properties:
        customerId:
          type: integer
          description: >
            Shopify customer ID (numeric). Identifies which customer is
            redeeming points.

            Provide either customerId OR customerEmail, not both.

            Example: 67890
          format: int64
          nullable: true
          example: 67890
        customerEmail:
          type: string
          description: >
            Customer's email address. Alternative to customerId for identifying
            the customer.

            Provide either customerId OR customerEmail, not both.

            Must be a valid email address that exists in your Shopify store.

            Example: customer@example.com
          nullable: true
          example: customer@example.com
        redeemRuleId:
          type: integer
          description: >
            ID of the redemption rule to use. Determines what reward the
            customer receives.

            Use GET /api/external/point-redeem-rules to get available redemption
            options.

            Must be an active redemption rule configured in your loyalty
            program.

            Example: 5
          format: int64
          example: 5
        points:
          type: number
          description: >
            Number of points to redeem. Must be positive.

            If not provided, uses the default points value from the redemption
            rule.

            Customer must have at least this many available points.

            Example: 100.0
          format: double
          nullable: true
          example: 100
        variantId:
          type: integer
          description: >
            Shopify product variant ID. Required when redeeming for
            product-specific rewards (free product).

            Not required for discount codes or store credit rewards.

            Must be a valid variant ID from your Shopify catalog.

            Example: 12345678
          format: int64
          nullable: true
          example: 12345678
      description: >-
        Point redemption request details including redeem rule ID, points to
        redeem, and optional variant ID for product rewards
      example:
        customerId: 67890
        redeemRuleId: 5
        points: 100
        variantId: 12345678
    CustomerLoyaltyResponseVM:
      type: object
      properties:
        availablePoints:
          type: number
          format: double
        pendingPoints:
          type: number
          format: double
        creditedPoints:
          type: number
          format: double
        spentAmount:
          type: number
          format: double
        storeCreditBalance:
          type: number
          format: double
        achievableTierId:
          type: integer
          format: int64
        currentVipTier:
          type: string
        vipTierExpiredAt:
          type: string
          format: date-time
        createAt:
          type: string
          format: date-time
        rewardedForFacebook:
          type: boolean
        rewardedForPinterest:
          type: boolean
        rewardedForTwitter:
          type: boolean
        rewardedForInstagram:
          type: boolean
        rewardedForYoutube:
          type: boolean
        rewardedForTiktok:
          type: boolean
        rewardedForNewsLetter:
          type: boolean
        rewardedForSms:
          type: boolean
        referredCompleted:
          type: integer
          format: int64
        referralLink:
          type: string
        customerStatus:
          type: string
          enum:
            - ACTIVE
            - INACTIVE
            - EXCLUDED
            - EXCLUDED_BY_CUSTOMER
        dob:
          type: string
          format: date
        rewards:
          type: array
          items:
            $ref: '#/components/schemas/CustomerReward'
        rewardedForCreatingAccount:
          type: boolean
        rewardedForSharingOnFacebook:
          type: boolean
        rewardedForSharingOnX:
          type: boolean
    CustomerReward:
      required:
        - createAt
        - customerId
        - discountCode
        - shop
        - status
      type: object
      properties:
        id:
          type: integer
          format: int64
        shop:
          type: string
        customerId:
          type: integer
          format: int64
        description:
          type: string
        pointTransactionId:
          type: integer
          format: int64
        pointRedeemRuleId:
          type: integer
          format: int64
        discountCode:
          type: string
        usedAt:
          type: string
          format: date-time
        orderId:
          type: integer
          format: int64
        orderName:
          type: string
        status:
          type: string
          enum:
            - USED
            - UNUSED
            - REFUNDED
            - EXPIRED
            - SUBSCRIPTION_ACTIVE
        createAt:
          type: string
          format: date-time
        expireDate:
          type: string
          format: date-time
        variantId:
          type: integer
          format: int64
        discountCodeId:
          type: string
        productData:
          type: string
        usageCount:
          type: integer
          format: int64
        amount:
          type: number
          format: double
        rewardType:
          type: string
          enum:
            - STORE_CREDIT
            - DISCOUNT_CODE
            - POINTS
        lastExpiryReminderSentDate:
          type: string
          format: date-time
    EnrollCustomerRequestVM:
      type: object
      properties:
        vipTier:
          type: string
      description: Customer enrollment request, optionally containing VIP tier name
    SocialMediaPoints:
      type: object
      properties:
        earnRuleId:
          type: integer
          format: int64
      description: Social media points claim request with earn rule ID
    ReferralAcceptRequest:
      type: object
      properties:
        token:
          type: string
        email:
          type: string
      description: >-
        Referral acceptance request containing referral token and email address
        of the new customer
    ReferralAcceptResponse:
      type: object
      properties:
        id:
          type: integer
          format: int64
        message:
          type: string
        discountCode:
          type: string
        status:
          type: string
          enum:
            - SUCCESS
            - FAILED
    Pageable:
      type: object
      properties:
        page:
          minimum: 0
          type: integer
          format: int32
        size:
          minimum: 1
          type: integer
          format: int32
        sort:
          type: array
          items:
            type: string
    PointTransaction:
      required:
        - customerId
        - pointType
        - points
      type: object
      properties:
        id:
          type: integer
          format: int64
        shop:
          type: string
        customerId:
          type: integer
          format: int64
        points:
          type: number
          format: double
        pointType:
          type: string
          enum:
            - DEBIT
            - CREDIT
        note:
          type: string
        status:
          type: string
          enum:
            - APPROVED
            - PENDING
            - REJECTED
        transactionRule:
          type: string
          enum:
            - ADJUSTMENT
            - EARN_RULE
            - REDEEM_RULE
            - REFERRAL
        earnRuleId:
          type: integer
          format: int64
        earnRuleName:
          type: string
        redeemRuleRuleId:
          type: integer
          format: int64
        redeemRuleName:
          type: string
        autoApprovalDays:
          type: integer
          format: int32
        orderId:
          type: integer
          format: int64
        orderName:
          type: string
        createAt:
          type: string
          format: date-time
        imported:
          type: boolean
        spentAmount:
          type: number
          format: double
        contractId:
          type: string
        orderFinancialStatus:
          type: string
        orderFulfillmentStatus:
          type: string
        orderLineItemId:
          type: integer
          format: int64
        rewardType:
          type: string
          enum:
            - STORE_CREDIT
            - DISCOUNT_CODE
            - POINTS
        displayName:
          type: string
    CustomerReferral:
      required:
        - createAt
        - customerId
        - referredEmailId
        - shop
        - status
      type: object
      properties:
        id:
          type: integer
          format: int64
        shop:
          type: string
        customerId:
          type: integer
          format: int64
        referredEmailId:
          type: string
        description:
          type: string
        referralRuleId:
          type: integer
          format: int64
        claimAt:
          type: string
          format: date-time
        status:
          type: string
          enum:
            - PENDING
            - CLAIMED
            - RECURRING
        createAt:
          type: string
          format: date-time
        referralRewarded:
          type: boolean
        referredRewarded:
          type: boolean
        referralNote:
          type: string
        referredNote:
          type: string
        pixelData:
          type: string
    ProductReviewDTO:
      type: object
      properties:
        title:
          type: string
        body:
          type: string
        rating:
          type: integer
          format: int32
        publishedStatus:
          type: boolean
        reviewerName:
          type: string
        productId:
          type: integer
          format: int64
        pinned:
          type: boolean
        createAt:
          type: string
          format: date-time
        replayBody:
          type: string
        replayDate:
          type: string
          format: date-time
        productTitle:
          type: string
        productHandle:
          type: string
        productImage:
          type: string
