Short answer: what you’re seeing is expected behavior.
1) PATCH /subscriptions/{id} behavior
- Changing
product_iddoes NOT charge immediately - It updates the subscription for the next billing cycle
- No proration, no immediate invoice is generated
That’s why:
- Customer paid $1.01 only
- Dashboard still shows old amount
- User gets upgraded benefits immediately (entitlement is on you to control)
2) Immediate upgrade with charge (correct flow)
Dodo currently does not auto-prorate on subscription update
To charge immediately, you must:
- Calculate the upgrade amount on your side
- Create a one-time payment / invoice for the difference
- After successful payment:
- Then update the subscription to the new product
3) Prevent “free upgrades”
Right now your system:
- Grants PRO access immediately after PATCH ❌
Instead:
- Gate access:
- Only upgrade entitlements after successful payment
- Treat
PATCHas future plan change, not payment event
4) Webhook behavior
- Expected: webhook still shows old
product_id - Reason: change is scheduled, not applied immediately
- New product reflects:
- At next billing cycle
- Or after subscription renew event
5) Recommended upgrade pattern
- Step 1: User selects upgrade
- Step 2: Calculate price difference
- Step 3: Create one-time charge
- Step 4: On success:
- Update subscription (PATCH)
- Upgrade user access
Key takeaway
PATCH subscription= schedule change- It is not a billing action
If you want, I can sketch the exact API sequence for invoice + upgrade flow.