Problem
Payments fail — expired cards, insufficient funds, fraud detection. We need to handle failures gracefully: retry a configurable number of times, notify the tenant, and eventually transition the subscription to PAST_DUE.
Proposed solution
Create PaymentFailureHandler that:
- Updates
payment_attempts.status to FAILED with provider error details
- If retry count < max retries (default 3):
- Schedule next retry with exponential backoff (1 day, 3 days, 7 days)
- Create new payment intent
- If retry count >= max retries:
- Transition subscription status to PAST_DUE
- Log for admin attention
- (Future: send notification to tenant)
Subscription statuses:
ACTIVE → (payment fails) → ACTIVE (retry 1)
→ (retry 2 fails) → ACTIVE (retry 2)
→ (retry 3 fails) → PAST_DUE
→ (payment succeeds later) → ACTIVE
API design (if applicable)
Internal handler. No new endpoints.
Alternatives considered
- Immediately cancel on first failure — rejected. Most failures are temporary (card expired, insufficient funds). Retries recover 60-80% of failed payments.
- Infinite retries — rejected. After 3 failures over 11 days, the payment is likely permanently failed. Manual intervention needed.
Additional context
Stripe has its own retry logic for payment intents. Our retry is on top — we create new payment intents after each failure, not re-attempt the same one.
Problem
Payments fail — expired cards, insufficient funds, fraud detection. We need to handle failures gracefully: retry a configurable number of times, notify the tenant, and eventually transition the subscription to PAST_DUE.
Proposed solution
Create
PaymentFailureHandlerthat:payment_attempts.statusto FAILED with provider error detailsSubscription statuses:
API design (if applicable)
Internal handler. No new endpoints.
Alternatives considered
Additional context
Stripe has its own retry logic for payment intents. Our retry is on top — we create new payment intents after each failure, not re-attempt the same one.