Cannot Receive `EXPIRED` Notifications from App Store Server Notifications V2

Hello,

I am currently implementing server-side handling for in-app subscription payments and using App Store Server Notifications V2 to receive notifications with a TestFlight account.

However, I am not receiving EXPIRED notifications, although I am successfully receiving other notifications such as SUBSCRIBED, DID_RENEW, and DID_CHANGE_RENEWAL_PREF.

Here are some details of my observations:

  • Until a certain point, I was receiving EXPIRED notifications without any issues, but they stopped coming in after that point.
  • Each subscription renews every 3 minutes in TestFlight account, and I receive DID_RENEW notifications 7 to 12 times. According to the official documentation, the subscriptions should renew up to 12 times, but I am not receiving exactly 12 DID_RENEW notifications. This inconsistency might be related to the issue.
  • Other notifications (SUBSCRIBED, DID_RENEW, DID_CHANGE_RENEWAL_PREF) are received without any issues.

Could anyone provide insight into why this might be happening and suggest any alternative methods to handle subscription expirations in case the EXPIRED notifications are not reliable?

Thank you for your assistance.

Relevant Official Documentation

App Store Server Notifications V2

App Store Server Notifications V2_notificationType

Testing in-app purchases with sandbox

Current Server Implementation

Below is the Kotlin Spring Boot server code currently implemented for handling App Store Server Notifications V2:

@RestController
class ProductIosController(
	private val productIosService: ProductIosService,
	private val appStoreNotificationService: AppStoreNotificationService,
) : BaseController {

	@PostMapping("/api/v1/ios-products/app-store-notifications-v2")
	fun handleNotification(@RequestBody @Valid notification: AppStoreNotificationRequest): CustomResponse {
		appStoreNotificationService.processNotification(notification)
		return CustomResponse.ok()
	}
	
}

@Service
class AppStoreNotificationService(
	@Qualifier("appStoreClient") private val appStoreServerAPIClient: AppStoreServerAPIClient,
	@Qualifier("signedVerifier") private val signedDataVerifier: SignedDataVerifier,
) {

	@Transactional
	fun processNotification(notification: AppStoreNotificationRequest) {

		logger.info("signedPayload: ${notification.signedPayload}")
		val decodedPayload = verifyAndDecodeSignedPayload(notification.signedPayload)
		val notificationType = decodedPayload.notificationType

		val signedTransactionInfo = decodedPayload.data.signedTransactionInfo
		val transaction = signedDataVerifier.verifyAndDecodeTransaction(signedTransactionInfo)
		val (user, product) = fetchUserAndProduct(transaction)

		when (notificationType) {
			SUBSCRIBED -> processSubscriptionPurchase(user, product, decodedPayload, transaction)
			DID_CHANGE_RENEWAL_PREF -> processSubscriptionGradeChange(user, product, decodedPayload, transaction)
			DID_CHANGE_RENEWAL_STATUS -> processRenewalStatusChange(transaction)
			OFFER_REDEEMED -> processOfferRedeemed(transaction)
			DID_RENEW -> processSubscriptionRenewal(user, product, decodedPayload, transaction)
			EXPIRED -> processSubscriptionExpiration(user, product)
			DID_FAIL_TO_RENEW -> processFailedRenewal(transaction)
			GRACE_PERIOD_EXPIRED -> processSubscriptionGracePeriodExpiration(transaction)
			PRICE_INCREASE -> processPriceIncrease(transaction)
			REFUND -> processSubscriptionRefund(transaction)
			REFUND_DECLINED -> processRefundDeclined(transaction)
			CONSUMPTION_REQUEST -> processConsumptionRequest(transaction)
			RENEWAL_EXTENDED -> processRenewalExtension(transaction)
			REVOKE -> processSubscriptionRevocation(transaction)
			TEST -> processTestNotification(transaction)
			RENEWAL_EXTENSION -> processRenewalExtension(transaction)
			REFUND_REVERSED -> processRefundReversed(transaction)
			EXTERNAL_PURCHASE_TOKEN -> processExternalPurchaseToken(transaction)
			else -> logger.warn("Unsupported notification type: ${notificationType.value}")
		}
	}

@jwkim94 Could you please file a ticket in Feedback Assistant and post the FB number here? Include the account used, approximate time, etc. It will be easier to address your question with specific examples.

Cannot Receive `EXPIRED` Notifications from App Store Server Notifications V2
 
 
Q