If you ship a subscription app on iOS, your backend eventually has to answer a question the app itself can't: is this user still entitled to the paid tier right now? The device knows what it last saw. Apple knows what's actually true. App Store Server Notifications V2 are the bridge between those two views, and once you've run a subscription product for a while, they stop feeling optional.

The short version: V2 notifications are webhook events Apple posts to a URL you configure in App Store Connect whenever something changes about a subscription. Renewals, cancellations, refunds, billing retry entering and exiting, price increase consent, grace period changes, and more each arrive as their own notification type, with a subtype where relevant. Each payload is a signed JWS, so your server can verify it came from Apple by checking the signature chain, without making a separate call back to Apple to confirm.

That signing property is the part that's easy to underestimate. It means the notification is self-contained proof of what happened. You don't have to treat the webhook as a hint that then triggers a lookup. You can parse the signed transaction and renewal info out of the payload, verify the chain up to Apple's root, and act on it directly. In practice we still call the Server API for some flows, because there are cases where you want the full transaction history rather than a single event, but the notification itself is trustworthy on its own terms.

Why the backend has to care

The reason V2 exists, and the reason we wire it up on day one at Olnesta Ltd, is that a subscription's state can change entirely outside your app. A user can cancel from Settings on their phone. They can request a refund through Apple's support flow days or weeks after the purchase. Their card can fail and enter billing retry while they're not opening the app at all. Apple can refund a charge you never saw a support ticket about. If your backend's only source of truth is what the app told it at last launch, all of these are invisible until the user comes back, and sometimes they don't come back precisely because they got refunded and moved on.

Without the webhook, the failure mode is quiet and expensive in both directions. You keep granting entitlement to people who no longer have it, which is a real revenue and licensing problem if your paid tier costs you anything per active user. You also fail to notice churn signals early, because a cancellation that happens in Settings looks identical to a happy renewing user right up until the renewal date passes. V2 collapses that whole gap. The event lands on your server within a short window of the state change, and your entitlement table updates without the user having to do anything.

What we actually do with them

Our handler is deliberately boring. It accepts the POST, verifies the JWS signature against Apple's certificate chain, decodes the signed payload, and writes the notification to a durable log before doing anything else. Only then do we branch on notificationType and subtype to update the user's entitlement record. Writing the raw signed payload first has saved us more than once, because when a bug shows up months later you want the original evidence, not your interpretation of it.

A few things are worth knowing before you turn this on. Apple retries failed deliveries, so your endpoint has to be idempotent. The same notification can and will arrive twice, and you need the second one to be a no-op. Notifications carry a UUID you can use as the dedupe key. You'll also want to handle unknown notification types gracefully rather than rejecting them, because Apple has added types over time and will keep doing so; logging and acknowledging an unfamiliar type is safer than 500-ing and triggering a retry storm. And you should configure both the production and sandbox URLs separately, because sandbox notifications arrive from a different environment and it's easy to spend an afternoon wondering why nothing is firing before realizing you only set one.

The official documentation for the notification types, payload structure, and the response format your endpoint should return is on Apple's developer site under App Store Server Notifications, and it's worth reading end to end at least once. It's shorter than you'd expect.

The practical takeaway for a small team about to add subscriptions: budget the webhook work into the first release, not a later cleanup pass. Retrofitting an entitlement model that assumed the client was authoritative is more painful than starting with a server that listens. Once the handler is in place and idempotent, subscriptions stop being a thing that surprises you, and start being a thing your backend already knew about before the user opened the app again.