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
ChargeProcessorCardError with PurchaseErrorCode::UPI_RECURRING_AUTHORIZATION_REQUIRED, raised by validate_upi_autopay_charge! before any Stripe call for UPI Autopay renewals. UPI exposes no reusable Mandate id (Stripe selects it from Customer + PaymentMethod), so the stored authorization is validated instead: the charge must be off-session, in INR, on a verified authorization whose stored currency is INR and whose max amount is positive, for an amount within both the stored cap and Stripe's UPI recurring limit (Checkout::PaymentMethodResolver::UPI_RECURRING_MAX_INR_CENTS). Any violation reports the precise reason via ErrorNotifier and raises with the buyer-facing 'update your payment method' message (UPI_PAYMENT_METHOD_UPDATE_MESSAGE).
Source
Thrown at app/business/payments/charging/implementations/stripe/stripe_charge_processor.rb:1434
if !off_session
"charge was not off-session"
elsif currency.to_s.downcase != Currency::INR
"charge currency was #{currency.inspect}"
elsif !chargeable.recurring_authorization_verified?
"authorization was not verified"
elsif chargeable.recurring_authorization_currency.to_s.downcase != Currency::INR
"stored authorization currency was #{chargeable.recurring_authorization_currency.inspect}"
elsif chargeable.recurring_authorization_max_amount_cents.to_i <= 0
"stored authorization maximum was missing"
elsif amount_cents > chargeable.recurring_authorization_max_amount_cents.to_i
"charge amount #{amount_cents} exceeded stored maximum #{chargeable.recurring_authorization_max_amount_cents}"
elsif amount_cents > Checkout::PaymentMethodResolver::UPI_RECURRING_MAX_INR_CENTS
"charge amount #{amount_cents} exceeded Stripe's UPI recurring limit"
end
return if reason.nil?
ErrorNotifier.notify("UPI Autopay renewal rejected before Stripe submit", reason:)
raise ChargeProcessorCardError.new(PurchaseErrorCode::UPI_RECURRING_AUTHORIZATION_REQUIRED, UPI_PAYMENT_METHOD_UPDATE_MESSAGE)
end
def get_mandate_id_from_chargeable(chargeable, merchant_account)
if chargeable.stripe_setup_intent_id
setup_intent = if merchant_migrated?(merchant_account)
Stripe::SetupIntent.retrieve(chargeable.stripe_setup_intent_id, { stripe_account: merchant_account.charge_processor_merchant_id })
else
Stripe::SetupIntent.retrieve(chargeable.stripe_setup_intent_id)
end
setup_intent.mandate
elsif chargeable.stripe_payment_intent_id
original_payment_intent = if merchant_migrated?(merchant_account)
Stripe::PaymentIntent.retrieve(chargeable.stripe_payment_intent_id, { stripe_account: merchant_account.charge_processor_merchant_id })
else
Stripe::PaymentIntent.retrieve(chargeable.stripe_payment_intent_id)
end
original_charge = if merchant_migrated?(merchant_account)
Stripe::Charge.retrieve(original_payment_intent.latest_charge, { stripe_account: merchant_account.charge_processor_merchant_id })View on GitHub (pinned to afeacbd394)
Solutions
- Ask the buyer to update their payment method — re-authorization creates a fresh mandate with a current cap.
- Identify which invariant fired: the ErrorNotifier report's reason string names it exactly (not verified / cap missing / over stored max / over Stripe limit).
- For price increases, run a re-authorization flow instead of charging above the stored cap.
- Verify recurring_authorization_* fields are persisted at UPI setup time and backfill where possible.
- Confirm the renewal amount is within Stripe's UPI recurring limit before scheduling the charge.
Example fix
# before: schedule the renewal at the new (higher) price
SubscriptionChargeJob.perform_later(subscription)
# after: only schedule when the stored UPI authorization covers the amount
if payment_method_upi?
max_cents = chargeable.recurring_authorization_max_amount_cents.to_i
if max_cents <= 0 || renewal_amount_cents > max_cents
require_upi_reauthorization!(subscription)
else
SubscriptionChargeJob.perform_later(subscription)
end
end Defensive patterns
Strategy: validation
Validate before calling
# Ruby, before charging a UPI renewal verified = chargeable.recurring_authorization_verified? within_stored_cap = renewal_amount_cents <= chargeable.recurring_authorization_max_amount_cents.to_i within_stripe_limit = renewal_amount_cents <= Checkout::PaymentMethodResolver::UPI_RECURRING_MAX_INR_CENTS inr = currency.to_s.downcase == "inr" if verified && within_stored_cap && within_stripe_limit && inr && off_session process_charge(...) else require_upi_reauthorization!(subscription) end
Try / catch
begin
process_charge(...)
rescue ChargeProcessorCardError => e
if e.code == PurchaseErrorCode::UPI_RECURRING_AUTHORIZATION_REQUIRED
notify_buyer_to_update_payment_method(purchase) # re-auth creates a fresh mandate with a current cap
else
raise
end
end Prevention
- Persist authorization currency and max amount at UPI setup and re-verify before every renewal.
- Trigger re-authorization on price increases instead of charging past the mandate cap.
- Treat 'UPI Autopay renewal rejected' ErrorNotifier reports as a queue of members needing re-auth, not noise.
- Keep the pre-submit guard — submitting anyway just converts a clear message into an issuer decline.
When it happens
Trigger: A membership renewal on a saved UPI method where: the stored authorization was never verified, recurring_authorization_max_amount_cents is 0/missing, the renewal amount exceeds the mandate's stored cap (e.g. a price increase), the amount exceeds Stripe's UPI recurring limit, the charge is not off-session, or the currency isn't INR.
Common situations: Seller raises a subscription price above the buyer's original UPI mandate cap; buyer cancelled the autopay mandate in their UPI app; legacy UPI subscriptions saved before authorization fields were persisted; currency drift away from INR.
Related errors
- india_card_mandate_missing
- upi_recurring_authorization_required
- upi_recurring_authorization_required
- india_card_mandate_missing
- We could not verify this card for recurring payments. Please
AI-assisted analysis of antiwork/gumroad@afeacbd394 (2026-08-21).
Data as JSON: /api/errors/16f918bfc503a206.
Report an issue: GitHub.