{"record":{"id":"57b1cb721d027abe","repo":"antiwork/gumroad","slug":"sorry-you-have-not-met-the-offer-code-s-minimum-a","errorCode":null,"errorMessage":"Sorry, you have not met the offer code's minimum amount.","messagePattern":"Sorry, you have not met the offer code's minimum amount\\.","errorType":"exception","errorClass":"Purchase::PurchaseInvalid","httpStatus":null,"severity":"error","filePath":"app/services/purchase/create_service.rb","lineNumber":107,"sourceCode":"\n        # Check for existing subscriptions (active or restartable)\n        if should_check_for_restartable_subscription?\n          existing_purchase, error, sca_response = handle_existing_subscription\n          return nil, nil, sca_response if sca_response.present?\n          return existing_purchase, error if existing_purchase.present? || error.present?\n        end\n      end\n\n      if purchase.offer_code&.minimum_amount_cents.present?\n        valid_items = params[:cart_items]\n        valid_items = if purchase.offer_code.universal\n          excluded_permalinks = purchase.offer_code.excluded_products.pluck(:unique_permalink)\n          valid_items.reject { excluded_permalinks.include?(_1[:permalink]) }\n        else\n          valid_items.filter { purchase.offer_code.products.find_by(unique_permalink: _1[:permalink]).present? }\n        end\n        if valid_items.map { _1[:price_cents].to_i }.sum < purchase.offer_code.minimum_amount_cents\n          raise Purchase::PurchaseInvalid, \"Sorry, you have not met the offer code's minimum amount.\"\n        end\n      end\n\n      if params[:accepted_offer].present?\n        upsell = Upsell.available_to_customers.find_by_external_id(params[:accepted_offer][:id])\n        raise Purchase::PurchaseInvalid, \"Sorry, this offer is no longer available.\" unless upsell.present?\n        if upsell.cross_sell?\n          if upsell.not_replace_selected_products?\n            cart_product_permalinks = params[:cart_items].reject { _1[:permalink] == product.unique_permalink }.map { _1[:permalink] }\n            if upsell.not_is_content_upsell? && (upsell.universal ? product.user.products : upsell.selected_products).where(unique_permalink: cart_product_permalinks).empty?\n              raise Purchase::PurchaseInvalid, \"The cart does not have any products to which the upsell applies.\"\n            end\n          end\n\n          # The original discount is retained if it is better than the upsell\n          # discount. The client can't automatically set the upsell discount\n          # because it doesn't have a \"code\". Thus, upsell discount should only\n          # be applied when the purchase does not already have a discount code.","sourceCodeStart":89,"sourceCodeEnd":125,"githubUrl":"https://github.com/antiwork/gumroad/blob/afeacbd394069a1cbf0c6c50ee8e900925050370/app/services/purchase/create_service.rb#L89-L125","documentation":"In Purchase::CreateService, when the applied offer code has minimum_amount_cents set, the eligible cart items' price_cents sum must reach it or Purchase::PurchaseInvalid is raised. Eligible items are all cart items minus the code's excluded_products for universal codes, or only items whose permalink is in offer_code.products otherwise — so items outside the code's scope do not count toward the minimum.","triggerScenarios":"Applying a '$10 off orders over $50' code to a $30 cart; removing an item after applying the code so the eligible total drops below the minimum; a universal code whose exclusions leave zero eligible items (sum 0 < minimum).","commonSituations":"Buyers trim the cart at the last step; codes scoped to specific products get applied to carts containing none of them; the minimum is per eligible items only, surprising users who included excluded products.","solutions":["Add eligible items (per the code's product scope/exclusions) until their total meets the minimum","Use a different code without a minimum, or applicable to the products actually in the cart","Compute the eligible-items total the same way — excluded products and non-code products do not count — before submitting payment"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"code = purchase.offer_code\nif code&.minimum_amount_cents.present?\n  eligible = params[:cart_items].select do |item|\n    code.universal ? !code.excluded_products.pluck(:unique_permalink).include?(item[:permalink]) : code.products.exists?(unique_permalink: item[:permalink])\n  end\n  raise 'below minimum' if eligible.sum { _1[:price_cents].to_i } < code.minimum_amount_cents\nend","typeGuard":"def cart_meets_offer_minimum?(cart_items, offer_code)\n  return true unless offer_code&.minimum_amount_cents.present?\n  eligible = cart_items.select do |i|\n    offer_code.universal ? !offer_code.excluded_products.pluck(:unique_permalink).include?(i[:permalink]) : offer_code.products.exists?(unique_permalink: i[:permalink])\n  end\n  eligible.sum { _1[:price_cents].to_i } >= offer_code.minimum_amount_cents\nend","tryCatchPattern":"begin\n  Purchase::CreateService.new(user: buyer, params: purchase_params).perform\nrescue Purchase::PurchaseInvalid => e\n  render json: { error: e.message }, status: :unprocessable_entity # message is buyer-safe\nend","preventionTips":["Re-validate the cart total against the code's minimum on every cart mutation, not just at apply time","Mirror the eligibility rules: excluded products and out-of-scope products do not count toward the minimum","Show the remaining amount needed when a code with minimum_amount_cents is applied"],"tags":["ruby","rails","offer-code","cart","checkout"],"backgroundTag":"discount-minimum-not-met","analyzedSha":"afeacbd394069a1cbf0c6c50ee8e900925050370","analyzedAt":"2026-08-21T17:58:52.159Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}