# Redeem customer loyalty points 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 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 Endpoint: POST /loyalty/cp/api/redeem-points ## Request fields (application/json): - `customerId` (integer,null) Shopify customer ID (numeric). Identifies which customer is redeeming points. Provide either customerId OR customerEmail, not both. Example: 67890 Example: 67890 - `customerEmail` (string,null) 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 Example: "customer@example.com" - `redeemRuleId` (integer, required) 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 Example: 5 - `points` (number,null) 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 Example: 100 - `variantId` (integer,null) 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 Example: 12345678 ## Response 200 fields (application/json): - `availablePoints` (number) - `pendingPoints` (number) - `creditedPoints` (number) - `spentAmount` (number) - `storeCreditBalance` (number) - `achievableTierId` (integer) - `currentVipTier` (string) - `vipTierExpiredAt` (string) - `createAt` (string) - `rewardedForFacebook` (boolean) - `rewardedForPinterest` (boolean) - `rewardedForTwitter` (boolean) - `rewardedForInstagram` (boolean) - `rewardedForYoutube` (boolean) - `rewardedForTiktok` (boolean) - `rewardedForNewsLetter` (boolean) - `rewardedForSms` (boolean) - `referredCompleted` (integer) - `referralLink` (string) - `customerStatus` (string) Enum: "ACTIVE", "INACTIVE", "EXCLUDED", "EXCLUDED_BY_CUSTOMER" - `dob` (string) - `rewards` (array) - `rewards.id` (integer) - `rewards.shop` (string, required) - `rewards.customerId` (integer, required) - `rewards.description` (string) - `rewards.pointTransactionId` (integer) - `rewards.pointRedeemRuleId` (integer) - `rewards.discountCode` (string, required) - `rewards.usedAt` (string) - `rewards.orderId` (integer) - `rewards.orderName` (string) - `rewards.status` (string, required) Enum: "USED", "UNUSED", "REFUNDED", "EXPIRED", "SUBSCRIPTION_ACTIVE" - `rewards.expireDate` (string) - `rewards.variantId` (integer) - `rewards.discountCodeId` (string) - `rewards.productData` (string) - `rewards.usageCount` (integer) - `rewards.amount` (number) - `rewards.rewardType` (string) Enum: "STORE_CREDIT", "DISCOUNT_CODE", "POINTS" - `rewards.lastExpiryReminderSentDate` (string) - `rewardedForCreatingAccount` (boolean) - `rewardedForSharingOnFacebook` (boolean) - `rewardedForSharingOnX` (boolean)