Post

Replies

Boosts

Views

Activity

Reply to 85% of Subscriptions are in Billing Retry State
With free trials specifically, a high billing retry rate usually means users signed up with payment methods that fail at the first real charge (prepaid cards, expired cards, insufficient funds). A few things that can help: first, make sure you're listening for DID_FAIL_TO_RENEW and BILLING_RECOVERY server notifications so you can message those users in-app and prompt them to update their payment method via showManageSubscriptions. Second, check if your trial length and pricing are attracting a lot of "tire kickers" who never intended to pay. Third, consider whether a shorter trial or an introductory offer instead of a free trial might filter for higher-intent users. Unfortunately Apple handles the actual retry logic on their end, so there's no way to control the retry cadence, but surfacing the payment issue to users early is the biggest lever you have.
Topic: App & System Services SubTopic: StoreKit Tags:
Apr ’26
Reply to Authentication Error with App Store Server API (NOT_AUTHORIZED) while Using JWT for Subscription Validation
The problem is almost certainly your aud claim. You're using "aud": "appstoreconnect-v1", which is the audience value for the App Store Connect API, not the App Store Server API. For the App Store Server API, the audience should be "appstoreconnect-v1" but the key itself needs to be an In-App Purchase key (generated under Users and Access > Integrations > In-App Purchase in App Store Connect), not an App Store Connect API key. Make sure you're generating the key from the correct section, because even though the JWT structure looks similar, the two key types are not interchangeable and using the wrong one will always return NOT_AUTHORIZED.
Apr ’26
Reply to Unexpected 401 Unauthorized response from production endpoint when using sandbox transactionId with Get Transaction Info API
To answer your follow-up questions: production API access unlocks once your app has been released on the App Store (option B), not just after approval. Your fallback approach is solid. For pre-release, catching 401 and retrying against the sandbox endpoint is the right move since App Review uses sandbox transactions. After your app is live and production access is unlocked, a sandbox transactionId sent to the production endpoint should indeed return 4040010 (TransactionIdNotFound) rather than 401, so you'd want your fallback to handle both 401 and 4040010 and retry on the sandbox endpoint in either case. That way your server works correctly during review and in production without needing to change the logic after launch.
Topic: App & System Services SubTopic: StoreKit Tags:
Apr ’26
Reply to Migration Subscription API returns 500 error
The 5000000 error code is a generic server-side error on Apple's end, so it's not something wrong with your request payload per se. A few things worth checking: make sure your sandbox account and the subscription you're migrating are both in a clean state (not expired or in billing retry), double-check that the generic product ID is properly configured and approved in App Store Connect for ACA, and confirm the storefront matches the sandbox account's region. If everything looks right and you're still hitting it, I'd recommend filing a Feedback Assistant ticket with your requestReferenceId so Apple engineering can trace the actual server-side failure.
Topic: App & System Services SubTopic: StoreKit Tags:
Apr ’26
Reply to prorated refund and upgrade of tier
This is actually a pretty well-known sandbox quirk. Prorated refunds and entitlement transitions for subscription upgrades don't always work correctly in sandbox, especially with the accelerated renewal timescales. In production, when a user upgrades, the original plan's entitlement should end right away and the new plan kicks in immediately, with the prorated refund handled behind the scenes. I'd suggest checking the expiresDate in the JWSTransactionDecodedPayload from the UPGRADE notification instead of relying on the current entitlement endpoint in sandbox, and try validating the full flow via TestFlight or production to confirm everything behaves as expected.
Topic: Community SubTopic: Apple Developers Tags:
Apr ’26
Reply to Apple Pay JS API - applePayCapabilities no longer working
This smells like a Safari-side change/regression in the capability probe, not in the payment sheet itself. Treat applePayCapabilities() as advisory only for now. Implement a graceful fallback: always show the button when Apple Pay is supported, then try to launch a session. Use canMakePayments() (and optionally canMakePaymentsWithActiveCard) only to influence prominence, not eligibility. This is consistent with Apple’s guidance and long-standing WebKit advice. File a bug with reproducibles via Feedback Assistant. Assume this is a Safari capability-probe issue (and possibly anti-fingerprinting collateral) rather than your integration. Don’t block Apple Pay on the probe; keep the button visible and let the session tell you the truth. This both fixes your users today and aligns you with Apple/WebKit’s recommended UX.
Topic: Safari & Web SubTopic: General Tags:
Oct ’25
Reply to How to modify the global window object in Safari Extensions?
I'll set aside if it will be approved for the public but you could use script injection. function injectScript() { const script = document.createElement('script'); script.textContent = ` // Store the original fetch const originalFetch = window.fetch; // Decorate fetch with your custom logic window.fetch = function(...args) { // Your custom logic here console.log('Fetch intercepted:', args[0]); // Example: Add custom headers if (args[1] && args[1].headers) { args[1].headers = { ...args[1].headers, 'X-Custom-Header': 'MyValue' }; } // Call original fetch with modified arguments return originalFetch.apply(this, args); }; `; // Inject script into webpage (document.head || document.documentElement).appendChild(script); // Clean up - remove the script tag after injection script.remove(); } // Execute the injection when content script loads injectScript();
Topic: Safari & Web SubTopic: General Tags:
Feb ’25
Reply to 85% of Subscriptions are in Billing Retry State
With free trials specifically, a high billing retry rate usually means users signed up with payment methods that fail at the first real charge (prepaid cards, expired cards, insufficient funds). A few things that can help: first, make sure you're listening for DID_FAIL_TO_RENEW and BILLING_RECOVERY server notifications so you can message those users in-app and prompt them to update their payment method via showManageSubscriptions. Second, check if your trial length and pricing are attracting a lot of "tire kickers" who never intended to pay. Third, consider whether a shorter trial or an introductory offer instead of a free trial might filter for higher-intent users. Unfortunately Apple handles the actual retry logic on their end, so there's no way to control the retry cadence, but surfacing the payment issue to users early is the biggest lever you have.
Topic: App & System Services SubTopic: StoreKit Tags:
Replies
Boosts
Views
Activity
Apr ’26
Reply to Authentication Error with App Store Server API (NOT_AUTHORIZED) while Using JWT for Subscription Validation
The problem is almost certainly your aud claim. You're using "aud": "appstoreconnect-v1", which is the audience value for the App Store Connect API, not the App Store Server API. For the App Store Server API, the audience should be "appstoreconnect-v1" but the key itself needs to be an In-App Purchase key (generated under Users and Access > Integrations > In-App Purchase in App Store Connect), not an App Store Connect API key. Make sure you're generating the key from the correct section, because even though the JWT structure looks similar, the two key types are not interchangeable and using the wrong one will always return NOT_AUTHORIZED.
Replies
Boosts
Views
Activity
Apr ’26
Reply to Unexpected 401 Unauthorized response from production endpoint when using sandbox transactionId with Get Transaction Info API
To answer your follow-up questions: production API access unlocks once your app has been released on the App Store (option B), not just after approval. Your fallback approach is solid. For pre-release, catching 401 and retrying against the sandbox endpoint is the right move since App Review uses sandbox transactions. After your app is live and production access is unlocked, a sandbox transactionId sent to the production endpoint should indeed return 4040010 (TransactionIdNotFound) rather than 401, so you'd want your fallback to handle both 401 and 4040010 and retry on the sandbox endpoint in either case. That way your server works correctly during review and in production without needing to change the logic after launch.
Topic: App & System Services SubTopic: StoreKit Tags:
Replies
Boosts
Views
Activity
Apr ’26
Reply to Migration Subscription API returns 500 error
The 5000000 error code is a generic server-side error on Apple's end, so it's not something wrong with your request payload per se. A few things worth checking: make sure your sandbox account and the subscription you're migrating are both in a clean state (not expired or in billing retry), double-check that the generic product ID is properly configured and approved in App Store Connect for ACA, and confirm the storefront matches the sandbox account's region. If everything looks right and you're still hitting it, I'd recommend filing a Feedback Assistant ticket with your requestReferenceId so Apple engineering can trace the actual server-side failure.
Topic: App & System Services SubTopic: StoreKit Tags:
Replies
Boosts
Views
Activity
Apr ’26
Reply to prorated refund and upgrade of tier
This is actually a pretty well-known sandbox quirk. Prorated refunds and entitlement transitions for subscription upgrades don't always work correctly in sandbox, especially with the accelerated renewal timescales. In production, when a user upgrades, the original plan's entitlement should end right away and the new plan kicks in immediately, with the prorated refund handled behind the scenes. I'd suggest checking the expiresDate in the JWSTransactionDecodedPayload from the UPGRADE notification instead of relying on the current entitlement endpoint in sandbox, and try validating the full flow via TestFlight or production to confirm everything behaves as expected.
Topic: Community SubTopic: Apple Developers Tags:
Replies
Boosts
Views
Activity
Apr ’26
Reply to How to choose between v1 & v2 for App Store Server Notifications
The version selector only appears after you enter (or when editing) a URL. Version 1 is deprecated, so Apple strongly encourages migrating to v2. The v2 format is more robust (cryptographically signed, includes more data like transaction/renewal info in JWS form, etc.).
Topic: App & System Services SubTopic: StoreKit Tags:
Replies
Boosts
Views
Activity
Apr ’26
Reply to Does WKWebview support encrypted DNS when using Network.framework PrivacyContext Api?
I don't think so. It only applies to network connections you make directly through that framework - WKWebView operates independently with its own networking stack.
Topic: Safari & Web SubTopic: General Tags:
Replies
Boosts
Views
Activity
Jan ’26
Reply to Apple Pay JS API - applePayCapabilities no longer working
This smells like a Safari-side change/regression in the capability probe, not in the payment sheet itself. Treat applePayCapabilities() as advisory only for now. Implement a graceful fallback: always show the button when Apple Pay is supported, then try to launch a session. Use canMakePayments() (and optionally canMakePaymentsWithActiveCard) only to influence prominence, not eligibility. This is consistent with Apple’s guidance and long-standing WebKit advice. File a bug with reproducibles via Feedback Assistant. Assume this is a Safari capability-probe issue (and possibly anti-fingerprinting collateral) rather than your integration. Don’t block Apple Pay on the probe; keep the button visible and let the session tell you the truth. This both fixes your users today and aligns you with Apple/WebKit’s recommended UX.
Topic: Safari & Web SubTopic: General Tags:
Replies
Boosts
Views
Activity
Oct ’25
Reply to iOS iPhone app for me and wife only
You will need a Developer account. Then, you can do: Ad Hoc Distribution (provide you iPhone UDIDs, Distribute via AirDrop, email) TestFlight both will last for 1year.
Replies
Boosts
Views
Activity
May ’25
Reply to information about a cellular network
Some of the information was previously available but then got stripped out a couple years back by new iOS versions.
Replies
Boosts
Views
Activity
Feb ’25
Reply to Fetching strategies - Do not fetch redundant data. ETags, Lastmodified, own API? Recommendations, practice?
that's what ETag is used for. Might be a bit fragile depending on how requests and responses are structured but no reason why ETag shouldn't work. Obviously implementing your own solution provides more flexibility.
Topic: App & System Services SubTopic: iCloud Tags:
Replies
Boosts
Views
Activity
Feb ’25
Reply to Handle subscription refund notification
The notificationType from Apple you are looking for is "REFUND". Expired will only be true after the time frame of theninapp/subscription. In your example REFUND is notified immediately (after the 3 months), EXPIRED occurs after the full term (1y).
Replies
Boosts
Views
Activity
Feb ’25
Reply to How to modify the global window object in Safari Extensions?
I'll set aside if it will be approved for the public but you could use script injection. function injectScript() { const script = document.createElement('script'); script.textContent = ` // Store the original fetch const originalFetch = window.fetch; // Decorate fetch with your custom logic window.fetch = function(...args) { // Your custom logic here console.log('Fetch intercepted:', args[0]); // Example: Add custom headers if (args[1] && args[1].headers) { args[1].headers = { ...args[1].headers, 'X-Custom-Header': 'MyValue' }; } // Call original fetch with modified arguments return originalFetch.apply(this, args); }; `; // Inject script into webpage (document.head || document.documentElement).appendChild(script); // Clean up - remove the script tag after injection script.remove(); } // Execute the injection when content script loads injectScript();
Topic: Safari & Web SubTopic: General Tags:
Replies
Boosts
Views
Activity
Feb ’25
Reply to App rejected due to 2.1.0 Performance: App Completeness
Apple Review Team doe indeed usually use iPads. If you're unable to recreate, I'd add logging to know where/when the issue happens.
Replies
Boosts
Views
Activity
Aug ’24
Reply to App store update check url changed after releasing to production
The url for your app is based on AppID and should never change, assuming it's the same app. Make sure you're not including the app name (which is editable) in the URL.
Replies
Boosts
Views
Activity
Dec ’23