{"record":{"id":"ebf7406a8b50ee4a","repo":"antiwork/gumroad","slug":"upi-recurring-authorization-required-ebf740","errorCode":"upi_recurring_authorization_required","errorMessage":"Your saved UPI payment method can no longer be used. Please update your payment method to continue your membership.","messagePattern":"Your saved UPI payment method can no longer be used\\. Please update your payment method to continue your membership\\.","errorType":"exception","errorClass":"ChargeProcessorCardError","httpStatus":null,"severity":"error","filePath":"app/business/payments/charging/implementations/stripe/stripe_chargeable_upi.rb","lineNumber":87,"sourceCode":"\n  def stripe_charge_params\n    { customer: @customer_id, payment_method: payment_method_id }\n  end\n\n  def recurring_authorization_verified?\n    @recurring_authorization_verified_at.present?\n  end\n\n  private\n    def expected_stripe_account_id\n      return unless StripeIntentChargeRouting.direct_charge_account?(@merchant_account)\n\n      @merchant_account.charge_processor_merchant_id\n    end\n\n    def fail_payment_method_update!(reason)\n      ErrorNotifier.notify(\"Saved UPI recurring payment method rejected before Stripe submit\", reason:)\n      raise ChargeProcessorCardError.new(\n        PurchaseErrorCode::UPI_RECURRING_AUTHORIZATION_REQUIRED,\n        StripeChargeProcessor::UPI_PAYMENT_METHOD_UPDATE_MESSAGE\n      )\n    end\nend\n","sourceCodeStart":69,"sourceCodeEnd":93,"githubUrl":"https://github.com/antiwork/gumroad/blob/afeacbd394069a1cbf0c6c50ee8e900925050370/app/business/payments/charging/implementations/stripe/stripe_chargeable_upi.rb#L69-L93","documentation":"Raised as a ChargeProcessorCardError (code upi_recurring_authorization_required) by fail_payment_method_update! in StripeChargeableUpi before any Stripe API call. It means a saved UPI payment method being attached or re-used for a recurring charge has lost its verified recurring authorization (recurring_authorization_verified_at is blank or the pre-submit check concluded the mandate is unusable). Gumroad surfaces StripeChargeProcessor::UPI_PAYMENT_METHOD_UPDATE_MESSAGE because UPI Autopay mandates must be re-authorized by the buyer in their UPI app; there is no server-side fix.","triggerScenarios":"Calling charge on a Chargeable built from a saved UPI payment method whose recurring authorization was never verified or has since been revoked/expired; specifically when fail_payment_method_update!(reason) is invoked (e.g. stripe account/routing mismatch on expected_stripe_account_id, or a mandate-state check failing) during a membership renewal or payment-method update flow.","commonSituations":"Buyer revoked the Autopay mandate in their UPI app (GPay/Paytm) between sign-up and the next billing cycle; the mandate hit its RBI amount/validity cap; the merchant account (charge_processor_merchant_id) changed so the old mandate no longer applies; test cards/simulators without a recurring mandate.","solutions":["Surface the 'update your payment method' message to the buyer and route them to re-authenticate UPI (a fresh on-session mandate confirmation) — this error is terminal for the saved method.","Check the reason logged via ErrorNotifier.notify(\"Saved UPI recurring payment method rejected before Stripe submit\", reason:) in your error tracker to confirm whether it was mandate state or a stripe_account routing mismatch.","If the reason is an account mismatch (expected_stripe_account_id vs the charge's account), fix the merchant account routing so renewals hit the same connected account the mandate was created on.","After the buyer re-authorizes, verify recurring_authorization_verified_at is set on the chargeable before retrying the charge."],"exampleFix":"// before: retrying the renewal with the same saved UPI chargeable\ncharge = ChargeProcessor::StripeChargeProcessor.charge(chargeable, purchase)\n// after: gate on the verified flag and force re-auth otherwise\nif chargeable.respond_to?(:recurring_authorization_verified?) && !chargeable.recurring_authorization_verified?\n  return redirect_to_payment_method_update(code: :upi_recurring_authorization_required)\nend\ncharge = ChargeProcessor::StripeChargeProcessor.charge(chargeable, purchase)","handlingStrategy":"try-catch","validationCode":"# before charging a saved UPI method\nchargeable = purchase.stripe_chargeable\nif chargeable.respond_to?(:recurring_authorization_verified_at) && chargeable.recurring_authorization_verified_at.blank?\n  return redirect_buyer_to_payment_method_update\nend","typeGuard":"def upi_recurring_authorization_verified?(chargeable)\n  chargeable.respond_to?(:recurring_authorization_verified_at) &&\n    chargeable.recurring_authorization_verified_at.present?\nend","tryCatchPattern":"begin\n  charge = ChargeProcessor.charge(chargeable, purchase)\nrescue ChargeProcessorCardError => e\n  if e.error_code == PurchaseErrorCode::UPI_RECURRING_AUTHORIZATION_REQUIRED\n    # terminal for this saved method: trigger buyer re-auth flow, do not retry the same chargeable\n    notify_buyer_update_payment_method(purchase)\n  else\n    raise\n  end\nend","preventionTips":["Verify recurring_authorization_verified_at is present before every renewal charge on UPI.","Confirm renewals route to the same connected account (charge_processor_merchant_id) the mandate was created on.","Watch the ErrorNotifier reason values to catch account-mismatch causes distinct from true mandate revocation."],"tags":["stripe","upi","recurring-billing","india","payment-method"],"backgroundTag":"upi-recurring-mandate-invalid","analyzedSha":"afeacbd394069a1cbf0c6c50ee8e900925050370","analyzedAt":"2026-08-21T17:58:52.159Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}