Files
shopify-ai-backup/DODO_PLAN_CHANGE_FIX.md

6.2 KiB

Dodo Payments Plan Change & Cancellation Fix

Summary

Fixed the subscription management system to properly handle plan changes and cancellations using the correct Dodo Payments API endpoints.

Issues Fixed

1. Paid-to-Paid Plan Changes

  • Problem: When users switched between paid plans (e.g., Starter → Professional), the app was creating a new checkout session instead of using Dodo's Change Plan API
  • Solution: Implemented changeDodoSubscriptionPlan() function that uses POST /subscriptions/{subscription_id}/change-plan with difference_immediately proration mode
  • Behavior:
    • Upgrades: Charges the price difference for the current billing period
    • Downgrades: Applies remaining value as credit to future renewals
    • No service interruption during the change

2. Paid-to-Free Downgrades

  • Problem: Downgrading to the free "Hobby" plan wasn't properly cancelling the Dodo subscription
  • Solution: Enhanced the logic to call cancelDodoSubscription() when switching from a paid plan to hobby
  • Behavior: Subscription is cancelled with Dodo, user downgraded to free tier immediately

3. Cancel Button

  • Problem: Cancel button was calling general account update endpoint which may not have properly cancelled the Dodo subscription
  • Solution: Already uses dedicated /api/subscription/cancel endpoint which properly calls cancelDodoSubscription()
  • Behavior: Cancels subscription at Dodo and marks billing status as cancelled

Technical Implementation

Server-Side Changes (server.js)

1. New Function: changeDodoSubscriptionPlan()

async function changeDodoSubscriptionPlan(user, newPlan, billingCycle, currency)
  • Uses Dodo's official Change Plan API endpoint
  • Handles proration automatically
  • Proper error handling and logging
  • Updates subscription product while maintaining continuity

2. Updated: handleAccountSettingsUpdate()

Enhanced to handle three scenarios:

  • Paid → Paid: Calls changeDodoSubscriptionPlan() with Dodo API
  • Paid → Free: Calls cancelDodoSubscription() and downgrades to hobby
  • Free → Paid: Returns error requiring checkout flow (correct behavior)

Frontend Changes (settings.html)

Updated: saveAccount() Function

Completely restructured to handle different plan change scenarios:

  1. Paid-to-Paid Changes:

    • Calls /api/account which uses Change Plan API
    • Shows appropriate confirmation with proration explanation
    • Immediate update without checkout
  2. Paid-to-Free Downgrades:

    • Warns user about feature loss
    • Cancels subscription via /api/account
    • Immediate downgrade
  3. Free-to-Paid Upgrades:

    • Redirects to checkout flow (correct)
    • Uses /api/subscription/checkout
  4. Other Settings:

    • Simple account updates (email, currency)

Dodo Payments API Integration

Change Plan API

Endpoint: POST /subscriptions/{subscription_id}/change-plan

Request Body:

{
  "product_id": "prod_xxx",
  "quantity": 1,
  "proration_billing_mode": "difference_immediately"
}

Proration Mode: difference_immediately

  • Upgrades: Immediate charge for price difference
  • Downgrades: Credit applied to subscription for future renewals
  • Benefits: Simple, fair billing without complex proration calculations

Cancel Subscription API

Endpoints Used:

  1. DELETE /subscriptions/{subscription_id} (immediate cancellation)
  2. PATCH /subscriptions/{subscription_id} with cancel_at_next_billing_date: true (fallback)

The implementation tries immediate cancellation first, then falls back to end-of-period cancellation if needed.

User Experience Improvements

Clear Messaging

  • Upgrade messages explain immediate charges
  • Downgrade messages explain credit application
  • Free plan changes warn about feature loss

Seamless Transitions

  • Paid-to-paid changes happen instantly without checkout
  • No service interruption during plan changes
  • Proper proration handled by Dodo

Confirmation Dialogs

  • All plan changes require explicit confirmation
  • Different messages for upgrades vs downgrades
  • Warning icons for cancellations and downgrades

Testing Checklist

  • Upgrade (Starter → Professional): Verify immediate charge for difference
  • Downgrade (Professional → Starter): Verify credit applied to account
  • Cancel (any paid → hobby): Verify Dodo subscription cancelled
  • Free to Paid (hobby → starter): Verify checkout flow triggered
  • Cancel Button: Verify subscription cancelled at Dodo
  • Webhook Handling: Verify subscription.plan_changed webhook updates user plan

Environment Variables Required

All existing Dodo environment variables remain the same:

  • DODO_PAYMENTS_API_KEY
  • DODO_PAYMENTS_ENV (test/live)
  • Subscription product IDs for each plan/cycle/currency combination

API Endpoints Modified

POST /api/account

Now handles three plan change scenarios differently:

  1. Paid→Paid: Uses Change Plan API
  2. Paid→Free: Cancels subscription
  3. Free→Paid: Returns error requiring checkout

POST /api/subscription/cancel

Already working correctly - cancels Dodo subscription properly

Webhook Events

The system now properly responds to:

  • subscription.plan_changed: Confirms plan change succeeded
  • subscription.canceled: Confirms cancellation
  • payment.succeeded: Confirms upgrade payment
  • subscription.on_hold: Handles failed plan change payments

Documentation References

Notes

  • The difference_immediately proration mode is ideal for most SaaS applications
  • Credits from downgrades are automatically applied by Dodo to future renewals
  • The Change Plan API uses existing payment method - no new payment collection needed
  • All plan changes are logged for audit purposes