Skip to content
Back to Blog
·6 min read

App Store Server Notifications not arriving: a V2 checklist

Server notifications V2 not reaching you? Check the App Store Connect URLs, TLS 1.2, the port and an HTTP 200 reply, then ask Apple for a test notification.

When App Store Server Notifications V2 don't reach your server, stop guessing and ask Apple what happened: call Request a Test Notification in the App Store Server API, then Get Test Notification Status with the token it returns. The status lists each send attempt with a result such as TLS_ISSUE, TIMED_OUT or UNSUCCESSFUL_HTTP_RESPONSE_CODE, which points at the cause. The usual causes are on Apple's own setup pages: no URL (or only a sandbox URL) in App Store Connect, a server without TLS 1.2 or later, a port other than 443 or 1024 and up, a firewall that blocks Apple's 17.0.0.0/8 range, or a reply that isn't HTTP 200 to 206.

What Apple sends and what it expects back

The App Store sends each notification as an HTTP POST with a JSON body. For version 2 the body is responseBodyV2, whose signedPayload is signed by the App Store in JWS format. Your server answers with a status code:

  • HTTP 200, or any code from 200 to 206, means success.
  • HTTP 40x or 50x asks the App Store to retry. Apple counts all other codes as unsuccessful.
  • You don't have to return a body.

If the first attempt doesn't get a success response, Apple retries version 2 notifications five times, at 1, 12, 24, 48 and 72 hours after the previous attempt. Retries happen only in production. In the sandbox, Apple says the App Store server tries once.

Version 1 notifications are deprecated; Apple says to implement the V2 endpoint instead.

Check the setup, in this order

  1. The URL is in App Store Connect. In Apps, select the app, then App Information under General, then App Store Server Notifications. Set the Production Server URL and, for testing, the Sandbox Server URL, and choose Version 2 for each. Apple's help page lists the roles that can do this: Account Holder, Admin, App Manager or Marketing.
  2. You understand which URL gets what. Apple's help page says that without a sandbox URL, sandbox and production notifications both go to the production URL, and that if you provide only a sandbox URL, no notifications are sent in production. You may use the same URL for both.
  3. TLS 1.2 or later. Apple states your server "must support the Transport Layer Security (TLS) 1.2 protocol or later". The TLS_ISSUE result also mentions a certificate that can't be validated.
  4. The port. If the URL names a port, it must be 443 or 1024 and up.
  5. The firewall. If your server only accepts listed IP addresses, add 17.0.0.0/8. Apple says this covers both sandbox and production.
  6. The reply. Return 200 as soon as you've received the post. The TIMED_OUT result tells you to "check that your server isn't processing messages in line", so store the body and process it afterwards. Apple doesn't publish a timeout value.
  7. The environment you're testing. A sandbox purchase sends one notification, with no retries, to the sandbox URL (or to production if there is no sandbox URL).

Apple doesn't say how long a newly saved URL takes to start receiving notifications.

How to check: test notification, status, history

The App Store Server API needs a JSON Web Token signed with an In-App Purchase key. Generate the key in App Store Connect under Users and Access > Integrations > In-App Purchase; Apple lets you download the private key only once. Use the sandbox host for the sandbox URL and the production host for the production URL.

1. Ask for a TEST notification.

curl -X POST -H "Authorization: Bearer $JWT" \
  https://api.storekit-sandbox.apple.com/inApps/v1/notifications/test
# {"testNotificationToken": "..."}

Apple sends the TEST notification to your sandbox URL when you call the sandbox host, and to your production URL when you call api.storekit.apple.com.

2. Read what Apple recorded.

curl -H "Authorization: Bearer $JWT" \
  https://api.storekit-sandbox.apple.com/inApps/v1/notifications/test/$TOKEN

The response has a sendAttempts array (up to six: the first attempt and up to five retries), each with an attemptDate and a sendAttemptResult, plus the signedPayload Apple tried to send. You can check a token for up to six months. What the results mean, from Apple's list:

sendAttemptResultApple's description, shortenedLook at
SUCCESSApple got a success response.Your code after the reply.
TLS_ISSUENo TLS session, or the certificate couldn't be validated.Certificate chain, TLS 1.2+.
UNSUCCESSFUL_HTTP_RESPONSE_CODENo HTTP 200 response.Auth middleware, routing, status code.
TIMED_OUTNo response before the timeout.Reply first, process later.
NO_RESPONSENo valid HTTP response.Server or proxy.
CIRCULAR_REDIRECTA redirect loop.Redirect rules (http to https, trailing slash).
PREMATURE_CLOSEThe connection closed during the send.Proxy, load balancer.
SOCKET_ISSUEA network error.DNS, firewall, port.
INVALID_RESPONSEAn invalid response.The response your server writes.
UNSUPPORTED_CHARSETA charset Apple doesn't support.Response headers.
OTHERAnother error.All of the above.

3. Find real notifications you missed. Get Notification History (POST /inApps/v1/notifications/history) returns the version 2 notifications Apple attempted to send, with their send attempts. Send startDate and endDate in UNIX milliseconds; add "onlyFailures": true to see only the ones that didn't reach you, including those still being retried. History covers 180 days in production and 30 days in the sandbox, 20 records per response.

curl -X POST -H "Authorization: Bearer $JWT" -H "Content-Type: application/json" \
  -d '{"startDate": 1761955200000, "endDate": 1762041600000, "onlyFailures": true}' \
  https://api.storekit.apple.com/inApps/v1/notifications/history

Apple notes that history records show the purchase as it was when the notification was sent. For the current state, call Get All Subscription Statuses or Get Transaction History.

4. Read the payload. To see what a notification contains, paste the signedPayload (or the whole body) into the App Store JWS decoder. Apple's steps: split the JWS into header, payload and signature, Base64URL-decode the payload to get the notification type and data, then decode signedTransactionInfo and signedRenewalInfo the same way. On your server, validate each signature with the algorithm named in the header's alg.

FAQ

Production notifications arrive but sandbox ones don't. Why?

Check that the sandbox URL is set and uses Version 2, then call Request a Test Notification on the sandbox host. Remember that the sandbox makes a single attempt, so one failure is final; Get Notification History in the sandbox goes back 30 days.

The test notification works but real ones don't. What next?

Call Get Notification History with onlyFailures for the period of the purchase. If nothing is listed, Apple did not attempt a notification for that event; check the notification types Apple documents for it. If attempts are listed, their sendAttemptResult tells you why they failed.

My server got the notification but Apple keeps retrying. Why?

Apple only counts 200 to 206 as success. A 401 from an auth layer, a redirect, or a slow reply that times out all count as failures, and in production Apple retries up to five times over several days.

I configured Version 1. Will I get the test notification?

Yes. Apple sends TEST in the version 2 format whether your URL is set to version 1 or version 2. Version 1 is deprecated, so switch to version 2 after testing it in the sandbox.

My server was down for a day. Are those notifications lost?

In production Apple retries five times, at 1, 12, 24, 48 and 72 hours after each previous attempt, so a one-day outage may be covered by a later retry. Get Notification History also returns notifications from the last 180 days, so you can fetch the ones you missed.

Sources

All read on 1 November 2026.

Apple's endpoints and limits change; check the pages above for current behaviour.

Written by

Building local-first Mac & iOS productivity apps at Obelisk Club. About the author →