When, if ever, is EXPIRED notification type actually sent?

I will admit I am rather frustrated with the performance and documentation of v2 server notifications for subscriptions, especially when compared to Google Play.

In particular, it appears that the EXPIRED notification type is not sent. In particular, if a user cancels rebilling, the only notification received is DID_CHANGE_RENEWAL_STATUS. However, when the expiration time actually does roll around, there is no corresponding EXPIRED notification sent.

This seems to contradict the documentation:

EXPIRED

A notification type that along with its subtype indicates that a subscription expired. If the subtype is VOLUNTARY, the subscription expired after the user disabled subscription renewal.

Is this a problem with the Sandbox, or will I forever wait in vain for an EXPIRED notification?

Been doing a little more testing, and here's what I think is happening in the Sandbox.

If you're like me and you use something like mitmproxy/ngrok/other reverse proxies, or are step-debugging your webhook handlers, it appears Apple is super sensitive to anything longer than a trivial timeout, and appears to drop the connection. Unlike other webhook integrations around the modern web, the retry is not in the minutes but hours, so you don't get an exponential back-off, either. In fact, it doesn't look like the Sandbox does retries at all. It appears that any failure (e.g., your step debugging hangs the request for a few seconds) means you won't get any of the expected follow-up webhook calls.

I was just able to successfully receive the expected EXPIRED webhook by not inspecting any of the traffic as it came across, and so the replies from my development environment were processed quickly enough for Apple.

I am expecting the production webhooks to be retried as advertised, but who knows...

brad-kinksters, thank you for looking into this more. Speaking to the retry policy in sandbox, we do not retry notifications in Sandbox as stated in our retry documentation https://developer.apple.com/documentation/appstoreservernotifications/responding_to_app_store_server_notifications. We have a few second timeout when sending the request. We generally recommend notification processing happen asynchronously from receipt, besides some basic checks. If you are manually breakpointing this call, it is likely you will exceed the timeout limit and experience the connection being closed on our end. If you feel this process could be improved, please file feedback in Feedback Assistant, we appreciate feedback on how to make our processes better.

Thanks for the response. The documentation is definitely lacking w/r/t the very short timeout.

I do think that I am running into an undocumented behavior, however.

Retry notifications are available only in the production environment. In the sandbox environment, the App Store server attempts to send the notification one time.

Not attempting a single notification is different from aborting all following notifications. E.g., you don't get an EXPIRED notification if any of the prior notifications failed. I will send feedback on this; the DX is pretty rough for testing.

When, if ever, is EXPIRED notification type actually sent?
 
 
Q