What does the App Store notification DID_CHANGE_RENEWAL_PREF mean?

The App Store notification DID_CHANGE_RENEWAL_PREF means the customer switched to a different subscription plan in the same group.

Quick facts#

Notification notificationType DID_CHANGE_RENEWAL_PREF
Where App Store Server Notifications v2 (responseBodyV2DecodedPayload)
Sent by The App Store server, to your notification URL
What Apple says The customer changed their subscription plan. UPGRADE takes effect immediately, DOWNGRADE at the next renewal date, and an empty subtype means the customer reverted to the current plan, cancelling a downgrade.

What triggers it#

  • Subtype UPGRADE: the upgrade takes effect at once and starts a new billing period. Apple gives the customer a prorated refund for the unused part of the old period.
  • Subtype DOWNGRADE: the change takes effect at the next renewal date and does not affect the active plan. A cross-grade to a different duration counts as a downgrade.
  • No subtype: the customer changed the renewal preference back to the current plan, which cancels a scheduled downgrade.

What your server should do#

  1. Verify the signedPayload with Apple's App Store Server Library (SignedDataVerifier.verifyAndDecodeNotification) before you act on anything in it.
  2. On UPGRADE, switch the entitlement now, to the product in the new transaction.
  3. On DOWNGRADE, keep the current plan and note the product in autoRenewProductId of the renewal info as the plan from the next renewal.
  4. With no subtype, clear the scheduled change.
  5. Answer HTTP 200 (any code from 200 to 206) once you have stored the notification. Apple retries other answers five times, at 1, 12, 24, 48 and 72 hours after the previous attempt, so make your handler safe to run twice (the payload carries a notificationUUID).

Example#

JavaScript
// Run on the decoded payload, after you verified Apple's signature.
const notification = {"notificationType":"DID_CHANGE_RENEWAL_PREF","subtype":"UPGRADE","data":{"environment":"Sandbox","bundleId":"com.example.app"}};

function decide(n) {
  if (n.notificationType !== "DID_CHANGE_RENEWAL_PREF") return "ignore";
  if (n.subtype === "UPGRADE") return "switch plan now";
  if (n.subtype === "DOWNGRADE") return "switch plan at the next renewal";
  return "clear the scheduled downgrade";
}

console.log(decide(notification));

Run-checked: npm run check:snippets runs this snippet with Node and compares its output with switch plan now (checked 2026-10-03).

How RevenueDot handles it#

RevenueDot verifies Apple's signature, checks the bundle ID, stores the notification and answers 200. A purchase RevenueDot has not seen is applied only when the app's Track new purchases from server-to-server notifications setting is on. The renewal info's autoRenewProductId is stored. A downgrade scheduled for the next renewal gives PRODUCT_CHANGE with new_product_id set to that product. An upgrade arrives as a transaction for the new product, which gives PRODUCT_CHANGE with product_id the old product, plus RENEWAL when the new product starts a new period.

Source#

Checked: 2026-10-03

Edit this page on GitHub ↗ View as Markdown Last updated