Updated: May 2025
Apple recently expanded its App Store Server Notifications with powerful new NotificationType
events. These updates are critical for developers managing subscriptions, in-app purchases, refunds, and account state changes. This deep-dive covers the latest NotificationTypes introduced in 2025, their use cases, and how to handle them using Swift and server-side logic effectively.
π What Are NotificationTypes?
NotificationTypes are event triggers Apple sends to your server via HTTPS when something changes in a userβs app store relationship, including:
- New purchases
- Renewals
- Refunds
- Grace periods
- Billing issues
- Revocations
π New NotificationTypes in 2025 (iOS 17.5+):
NotificationType | Purpose |
---|---|
REFUND_DECLINED | Customer-initiated refund was denied |
GRACE_PERIOD_EXPIRED | Grace period ended, subscription not renewed |
OFFER_REDEEMED | User successfully redeemed a promotional offer |
PRE_ORDER_PURCHASED | A pre-ordered item was charged and made available |
AUTO_RENEW_DISABLED | Auto-renew toggle was turned off manually |
APP_TRANSACTION_REVOKED | App-level transaction was revoked due to violations or fraud |

π‘οΈ Why it matters: These help prevent fraud, enable smoother user communication, and allow tighter control of subscription logic.
βοΈ Sample Server Logic in Node.js
// Example: Express.js listener for Apple server notifications
app.post("/apple/notifications", (req, res) => {
const notification = req.body;
const type = notification.notificationType;
switch(type) {
case "OFFER_REDEEMED":
handleOfferRedemption(notification);
break;
case "GRACE_PERIOD_EXPIRED":
notifyUserToRenew(notification);
break;
case "APP_TRANSACTION_REVOKED":
revokeUserAccess(notification);
break;
default:
console.log("Unhandled notification type:", type);
}
res.status(200).send("OK");
});
π² Swift Example β Handle Subscription Cancellation Locally
func handleNotification(_ payload: [String: Any]) {
guard let type = payload["notificationType"] as? String else { return }
switch type {
case "AUTO_RENEW_DISABLED":
disableAutoRenewUI()
case "REFUND_DECLINED":
logRefundIssue()
default:
break
}
}
π Best Practices
- Always verify signed payloads from Apple using public keys
- Maintain a notification history for each user for audit/debug
- Use notifications to trigger user comms (email, in-app messages)
- Gracefully handle unexpected/unknown types