Skip to main content
Question

How do make deferred downgrades with paddle integration

  • April 7, 2026
  • 4 replies
  • 70 views

Forum|alt.badge.img

I'm using revenuecat with paddle integration, I would like to implement a subscription downgrade logic that calls the paddle API since revenuecat doesn't support paddle subscription upgrade/downgrades through its sdks (I have already asked about this on github months ago without any answer https://github.com/RevenueCat/purchases-js/issues/182#issuecomment-3519530263).

I was wandering if I make a PATCH request to https://api.paddle.com/subscriptions/{subscription_id} (check https://developer.paddle.com/build/subscriptions/replace-products-prices-upgrade-downgrade) with full_next_billing_period proration mode to downgrade, what webhooks revenuecat will trigger. And also, will revenuecat immediately change the user entitlement or wait until the current period ends since the user is only charged at the end of the current period with full_next_billing_period.

Basically, does revenuecat rely on paddle subscription state or transactions or both to manage entitlements/revenuecat customer subscription?

NOTE: making a patch request to the paddle subscription endpoint will only trigger the subscription.updated paddle webhook if proration method is full_next_billing_period, no transaction related webhooks.

4 replies

hussain
RevenueCat Staff
Forum|alt.badge.img+6
  • RevenueCat Staff
  • April 10, 2026

Hi ​@sitatech,

Thanks for reaching out. I’m happy to help.

RevenueCat relies on both Paddle's subscription state and transaction history to manage entitlements. When we receive a subscription.updated webhook, we fetch the latest subscription object and transaction history from Paddle's API to determine the current product and entitlements for the customer.

For your specific scenario using full_next_billing_period proration, RevenueCat will immediately change the user's entitlements when the subscription.updated webhook is processed. This is because Paddle updates the subscription's items to reflect the new product/price right away, even though billing is deferred to the next period. RevenueCat detects this product change on the subscription and updates entitlements accordingly, it does not wait until the current billing period ends. This means the user would lose access to their higher-tier features immediately, despite having paid for the full current period.

Our handling of Paddle's scheduled_change field currently only covers cancellations, pauses, and resumes, not deferred product or price changes. So there's no built-in mechanism to defer the entitlement change to the end of the billing period for this type of update.

Hope this helps, let me know if you have any other questions!

Best,

Hussain


Forum|alt.badge.img
  • Author
  • New Member
  • April 11, 2026

Hi ​@hussain,

Thanks for your answer,

Does RevenueCat send both the PRODUCT_CHANGE and RENEWAL/INITIAL_PURCHASE webhook events for paddle upgrade/downgrade? This is well documented for Android and iOS here, but I couldn’t find anything about Paddle.

Also, does the store_subscription_identifier from the customer subscriptions endpoint match Paddle’s subscription id or corresponding transaction id?


hussain
RevenueCat Staff
Forum|alt.badge.img+6
  • RevenueCat Staff
  • April 15, 2026

Hi ​@sitatech,

RevenueCat does send PRODUCT_CHANGE webhook events for Paddle upgrades/downgrades. The specific events you'll receive depend on the proration type:

  • For non-prorated changes (like full_next_billing_period): you'll receive only a PRODUCT_CHANGE event. Since Paddle doesn't create a new transaction in this case, only the existing transaction is updated with the new product, so no RENEWAL event fires at that point. A RENEWAL event would fire later when the actual renewal transaction occurs at the next billing period.

  • For prorated changes (where Paddle creates a new transaction, e.g. prorated_immediately): you'll receive a PRODUCT_CHANGE event, and you may also receive a RENEWAL event for the same transaction if it qualifies as a renewal (i.e., its billing period is different from the subscription's original start). Both events can fire for the same transaction.

  • INITIAL_PURCHASE is only sent for the very first transaction of a subscription, so it would not be triggered by an upgrade or downgrade.

The store_subscription_identifier from the customer subscriptions endpoint corresponds to the Paddle transaction ID (txn_*), specifically, the transaction ID of the latest/current period's transaction. It changes with each renewal as the latest transaction updates. It does not correspond to the Paddle subscription ID (sub_*).

The Paddle subscription ID (sub_*) maps to the original_transaction_id in webhook event payloads.

Hope that clears things up! Let me know if you have any other questions.

Best,

Hussain


Forum|alt.badge.img
  • Author
  • New Member
  • April 15, 2026

Thanks a lot ​@hussain,

In case this may help someone, here are the options I explored. I would also appreciate your input on this @hussain because you have a much better understanding of how RevenueCat and the Paddle integration work:

I considered 2 options to implement deferred downgrades with paddle (customer downgrade, they don’t get charged and keep the current entitlement until the next billing period then get charged only the new, lower plan’s price).

  1. When a user trigger a downgrade, we don’t call the paddle API directly, we store the user intent with the current period end date, and create a cron job than run every day and check for any scheduled downgrade with the period end date being today.
  2. When a user trigger a downgrade, we call the Paddle API and make the downgrade with do_not_bill proration mode (I realized that the full_next_billing_period will charge the user twice at the next billing period, 1 for the triggered change, 1 for the period renewal). When we receive the PRODUCT_CHANGE event we store the scheduled change in our DB and then when we receive the RENEWAL event we apply the change.

The first option is not very robust because Paddle may trigger the renewal before the exact recorded end of period date, for example Google can renew up 48 hours early to atone for any potential billing issue. Also whether Paddle trigger the renewal at the exact date, 10h, or 48h early isn’t part of the API, they can change that internally anytime. It maybe possible to apply the change 4-7 days early as a safety measure, but It's still not very reliable and applying the plan change up to 1 week before the user get charged for the new plan may confuse them.

I prefer the second option, although it also has its shortcomings. The major one being the inconstancy between RevenueCat entitlement and your DB, but this work for me because I’m already using our DB as the source of truth for subscription data, and using RevenueCat entitlement only for validation and potential fraud prevention. And adding the deferred change info in RevenueCat customer attributes also reduce the inconstancy. The other issue maybe the added complexity because if the user decides to restore their old plan or switch to a new one these need to be handled carefully and keeping in mind that any API call to Paddle that changes the subscription state will trigger a PRODUCT_CHANGE event.