antiwork/gumroad · error · ChargeProcessorCardError

upi_recurring_authorization_required

upi_recurring_authorization_required

Error message

Your saved UPI payment method can no longer be used. Please update your payment method to continue your membership.

What it means

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.

Source

Thrown at app/business/payments/charging/implementations/stripe/stripe_chargeable_upi.rb:87

  def stripe_charge_params
    { customer: @customer_id, payment_method: payment_method_id }
  end

  def recurring_authorization_verified?
    @recurring_authorization_verified_at.present?
  end

  private
    def expected_stripe_account_id
      return unless StripeIntentChargeRouting.direct_charge_account?(@merchant_account)

      @merchant_account.charge_processor_merchant_id
    end

    def fail_payment_method_update!(reason)
      ErrorNotifier.notify("Saved UPI recurring payment method rejected before Stripe submit", reason:)
      raise ChargeProcessorCardError.new(
        PurchaseErrorCode::UPI_RECURRING_AUTHORIZATION_REQUIRED,
        StripeChargeProcessor::UPI_PAYMENT_METHOD_UPDATE_MESSAGE
      )
    end
end

View on GitHub (pinned to afeacbd394)

Solutions

  1. 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.
  2. 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.
  3. 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.
  4. After the buyer re-authorizes, verify recurring_authorization_verified_at is set on the chargeable before retrying the charge.

Example fix

// before: retrying the renewal with the same saved UPI chargeable
charge = ChargeProcessor::StripeChargeProcessor.charge(chargeable, purchase)
// after: gate on the verified flag and force re-auth otherwise
if chargeable.respond_to?(:recurring_authorization_verified?) && !chargeable.recurring_authorization_verified?
  return redirect_to_payment_method_update(code: :upi_recurring_authorization_required)
end
charge = ChargeProcessor::StripeChargeProcessor.charge(chargeable, purchase)
Defensive patterns

Strategy: try-catch

Validate before calling

# before charging a saved UPI method
chargeable = purchase.stripe_chargeable
if chargeable.respond_to?(:recurring_authorization_verified_at) && chargeable.recurring_authorization_verified_at.blank?
  return redirect_buyer_to_payment_method_update
end

Type guard

def upi_recurring_authorization_verified?(chargeable)
  chargeable.respond_to?(:recurring_authorization_verified_at) &&
    chargeable.recurring_authorization_verified_at.present?
end

Try / catch

begin
  charge = ChargeProcessor.charge(chargeable, purchase)
rescue ChargeProcessorCardError => e
  if e.error_code == PurchaseErrorCode::UPI_RECURRING_AUTHORIZATION_REQUIRED
    # terminal for this saved method: trigger buyer re-auth flow, do not retry the same chargeable
    notify_buyer_update_payment_method(purchase)
  else
    raise
  end
end

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of antiwork/gumroad@afeacbd394 (2026-08-21). Data as JSON: /api/errors/ebf7406a8b50ee4a. Report an issue: GitHub.