Post

Replies

Boosts

Views

Activity

Reply to How to identify free trial subscription transaction
In the JWS transaction payload (the one you get from Transaction.currentEntitlements client-side, or from Get Transaction Info server-side), there are two fields that together tell you unambiguously: offerType: an integer. 1 = introductory offer, 2 = promotional offer, 3 = offer code. Free trials are a form of introductory offer. offerDiscountType: a string enum. Values are FREE_TRIAL, PAY_AS_YOU_GO, or PAY_UP_FRONT. This is the one you probably actually want. If it equals FREE_TRIAL you're definitively in a trial. Important caveat: these fields are only populated while the transaction is in the promotional or intro period. Once the trial converts to paid, the subsequent renewal transaction won't have offerType set at all. So you can only detect "currently in free trial" from the currently-active transaction, not by looking at historical renewal transactions. If you need this server-side (not on device): Call the App Store Server API Get Transaction Info endpoint for the transactionId in question. Or parse the signedTransactionInfo JWS from your App Store Server Notifications webhook. The SUBSCRIBED notification with offerDiscountType = FREE_TRIAL on initial subscribe is your signal. Strong recommendation: use the App Store Server Library (available for Swift, Java, Python, Node, Go). It handles JWS verification and decoding for you, rather than rolling your own JWT parse which is easy to get subtly wrong around certificate chain validation. WWDC22 "Explore App Store server APIs" and WWDC23 "Meet StoreKit 2" both cover this.
2w
Reply to Apple Server Notifications Webhooks stopped retrying on HTTP 400
The retry policy is actually documented behavior, though enforcement seems to have gotten stricter around that date. Apple's webhook retry rules: 2xx response: success, no retry (as expected). 4xx response: treated as a permanent failure. Your server is effectively saying "this notification is malformed or not for me", so no retry because retrying won't help. 5xx response: treated as a temporary failure. Retries follow the documented schedule (5 attempts over roughly 3 days). No response or timeout: also treated as temporary failure, retried. If you want retries, return 5xx (or just let your server error naturally). Returning 400 tells Apple "I got your notification but I permanently cannot process it, don't bother sending again." Before that change, 4xx may have been getting retried in some cases, which wasn't the documented behavior. The March 2026 change likely aligned actual behavior with what the docs have always said. Two things I'd check: Why is your server returning 400 in the first place? If it's a decode failure on a malformed payload (JWS signature check failing, etc.), that might warrant returning 500 so you get retries and can investigate. If it's intentional validation rejection, 400 is fine but log it so you know what's being discarded. Use the App Store Server API requestTestNotification plus getTestNotificationStatus endpoints to verify your webhook end-to-end without waiting on real transactions.
Topic: App & System Services SubTopic: StoreKit Tags:
2w
Reply to Why Non-Consumable product has originalTransactionId?
This trips up a lot of people coming from the verifyReceipt world. Short version: transactionId is not stable for a non-consumable. It changes every time the purchase is "issued" to a device, which includes restore, re-download on a new device, Family Sharing additions, etc. originalTransactionId is the stable identifier. For one non-consumable purchase, reinstalled across multiple devices, you'll see: originalTransactionId: same value across all entries (the first purchase). transactionId: a new value for each issuance event. That's why querying Get Transaction Info with different transactionId values over time can return what looks like the same product ownership. Each one represents a separate re-issuance of the same underlying entitlement. Rules of thumb for backend storage: Use originalTransactionId as the stable "user owns this product" key in your database. Use transactionId only when you need a unique identifier for a specific issuance event, e.g. deduplication on your webhook. For Family Sharing, check inAppOwnershipType on each transaction: PURCHASED means the user bought it, FAMILY_SHARED means they received it via Family Sharing. They can share the same originalTransactionId but have different transactionIds. WWDC23 "Meet StoreKit 2" walks through this relationship visually if you want more context.
Topic: App & System Services SubTopic: StoreKit Tags:
2w
Reply to StoreKit Configuration Not Syncing to Xcode
The "Synced @ [time]" timestamp updating while content stays empty is one of those bugs where everything looks correct and nothing works. A few things that usually fix it: Most common cause: the subscriptions in App Store Connect aren't fully configured. The sync only pulls subscriptions that have localization, pricing, and review info all filled in for at least one language. If any single one of those is missing, that subscription gets silently skipped. Open each subscription in App Store Connect and look for red "Missing Metadata" warnings. The subscription group itself matters. Xcode pulls the group along with the subscriptions. If the group has no localization (display name, level), nothing under it comes across. Sign out and back into your Apple ID in Xcode > Settings > Accounts. The auth token for the App Store Connect API can go stale and the sync silently fails for one team while appearing to succeed. If none of that helps, just build the .storekit file manually. It's usually faster than fighting the sync. In the editor, click + and add each subscription with the same product ID as in App Store Connect. The IDs are all that need to match; the pricing in the file is only used by the local StoreKit simulator, not production. Did you try fetching products with Product.products(for:) at runtime (without a .storekit file) pointed at sandbox? If those also come back empty, the problem is on the App Store Connect side, not Xcode's sync.
Topic: App & System Services SubTopic: StoreKit Tags:
2w
Reply to Subscription Unavailable - Strange Behavior with StoreKit
Seen this one a lot. "Subscription is unavailable in the current storefront" almost always comes down to one of these, in order of likelihood: Paid Apps Agreement isn't in Active state for the team. Open App Store Connect > Agreements, Tax, and Banking. If the Paid Apps agreement shows anything other than Active (Action Required, missing bank info, missing tax forms, or a contact who's no longer on the team), every subscription rejects with this exact error until it's resolved. The subscription's price schedule doesn't include the user's storefront. Each subscription has pricing set per country. If you only configured prices for some countries, users outside that list get this error. Check the Price tab on the subscription and confirm the user's country is covered. The app and the subscription are in different availability regions. Even with pricing set, the app itself must also be available in that country. Check App Availability on the main app page. The subscription isn't actually in "Ready for Sale" state. After app approval, a subscription can still sit at "Ready to Submit" if it wasn't attached to the submission that got reviewed. It needs to have cleared review and be Ready for Sale. Easiest diagnostic: have a friend in a different country try it. Works there but not for you = storefront/availability issue. Fails universally = agreements issue. Three days of waiting is actually normal for storefront propagation the first time a subscription goes live, but only the first time. After that it should be immediate.
Topic: App & System Services SubTopic: StoreKit Tags:
2w
Reply to AppStore.sync() not restoring purchases
Classic StoreKit 1 to 2 migration pitfall. A few things worth checking: The sandbox account matters more than you'd expect. When you reinstall, make sure you're signed into the same sandbox Apple ID that actually made the SK1 purchase. If it's a fresh sandbox user or a different one, there's literally no transaction to restore. Settings > Developer > Sandbox Apple Account shows who's currently active. For a non-consumable originally purchased via SK1, after AppStore.sync() completes, the transaction shows up in Transaction.currentEntitlements with its original productID, but the id or originalID might be a legacy numeric identifier rather than a UUID. If you're filtering entitlements by anything other than productID, that could be why you don't see it. AppStore.sync() triggers an Apple ID password prompt. If the user cancels that prompt, it returns without throwing but also without actually syncing. Wrap it in try/catch and log so you can distinguish canceled vs successful vs failed. If this is a TestFlight build rather than a sandbox-signed build, TestFlight uses the production App Store Commerce backend. You won't be able to restore SK1 sandbox purchases across, only production purchases the TF user actually made. One more thing: check Transaction.all (not just currentEntitlements) after sync. If the old SK1 transactions show up there but not in currentEntitlements, it's a filtering issue on your side. If they don't appear in Transaction.all at all, the sync isn't reaching them, which usually points back to point 1.
Topic: App & System Services SubTopic: StoreKit Tags:
2w
Reply to StoreKit 2: Transaction.all and Transaction.currentEntitlements return empty for valid non-consumable purchases in production
Seen this pattern a few times. Transaction.all and Transaction.currentEntitlements both read from a local transaction cache that StoreKit 2 builds by syncing with Apple's servers. If that sync has never completed for the current user on the current device, both streams come back empty even when the purchase still exists server-side. Users who tend to land in this state: Restored the device from a backup and haven't re-signed into the Apple ID that owns the purchase. Family Sharing participants (not the original buyer). There's been a recurring regression on 26.x where family-shared non-consumables disappear from currentEntitlements after a restore. Changed their Apple ID on the device at some point. The unblock for all of these is AppStore.sync(). Gate it behind a "Restore Purchases" button (it prompts for Apple ID password, so never call it on launch), and re-read currentEntitlements after it completes. That's the officially documented recovery path for this exact scenario. If sync() doesn't recover them, the App Store Server API (GET /inApps/v1/history/{transactionId}) is still available server-side and will tell you whether Apple still recognises the purchase at all. That at least narrows it to a device-state issue vs. a server-side one worth escalating to DTS. Any pattern in the affected users? Recent device restores, family sharing, Apple ID changes?
Topic: App & System Services SubTopic: StoreKit Tags:
2w
Reply to Live Activity updates not received on iPhone 16 Pro Max when started via ActivityKit push
When "start arrives but updates don't" on one specific device, it's almost always one of three things. Walking through them: Wrong push token for updates. The start push uses apns-push-type: liveactivity plus your app's device token. But once the activity is running, each activity has its own token delivered via Activity.pushToken (or pushTokenUpdates as an async sequence). Every update has to go to that per-activity token, not the device token, and not a stale token from a previous activity. Worth logging and diffing the token you're actually sending between 16 Pro and 16 Pro Max. stale-date already in the past. iOS silently drops updates whose stale-date is before "now" on the device. Small clock drift or a timezone mismatch is enough. Try pushing with stale-date explicitly far in the future and see if that changes anything. content-state schema mismatch. If your ContentState decoder throws on the update payload (new field, wrong type, enum case removed), the update is dropped with no user-visible signal. Start payloads tend to be more forgiving than updates. Quickest way to know which of the three it is: install the ActivityKit logging profile from Apple's developer downloads and filter Console.app on liveactivities while pushing to the 16 Pro Max. The logs will tell you whether APNs delivered the payload and it got rejected, or it never arrived at all.
2w
Reply to Xcode 26 Causing StoreKit Fiasco for macOS?
Sounds like a frustrating regression. Before chalking it up to a bug, a few things worth trying: The transaction cache in Xcode's StoreKit environment gets into weird states after major version upgrades. From Xcode, open Debug > StoreKit > Manage Transactions, delete everything in there, then clean build folder (Shift-Cmd-K), nuke DerivedData, and restart Xcode. On the running target, delete the app entirely before re-running. Second, check your scheme's StoreKit configuration setting. The Xcode 16 to 26 migration has been resetting "StoreKit Configuration" to None on some projects. Edit Scheme > Run > Options, confirm your .storekit file is still selected. Third, when purchases silently fail without even showing the confirmation sheet, it's usually the store failing to resolve the product ID. Open the .storekit file, hit the refresh/sync icon, and confirm every product identifier matches what your code requests exactly (it's case-sensitive). Did macOS also update around the same time? When it's not Xcode, it's usually commercekit or storekitd on the host Mac. Console.app filtered by those processes while you try a purchase will tell you if the daemon is the actual culprit.
Topic: App & System Services SubTopic: StoreKit Tags:
2w
Reply to Is there a reliable way to check pending agreement status for multiple App Store Connect accounts via API?
Your analysis is correct. The /v1/agreements endpoint was deprecated and removed in newer API versions, which is why you get a 404 on some accounts (likely those using newer API keys or auth scopes). There is no dedicated "agreement status" endpoint, so the 403 gate is genuinely the only signal available via the API. The enforcement is progressive as you guessed: the UI shows the warning immediately, but the API only blocks once the grace period expires. One additional probe that tends to fail earlier than bundleIds/certificates is attempting to create or update an app store version via POST /v1/appStoreVersions or listing your apps with GET /v1/apps since those operations are more sensitive to agreement state. Not a perfect solution, but it might shrink the detection gap for your dashboard.
3w
Reply to Is there a way to pull Ratings data via API or other method?
The App Store Connect API doesn't expose standalone ratings (without reviews), but you can get aggregate ratings data through the App Analytics reports. Specifically, the Analytics Reports API lets you request report types like APP_STORE_ENGAGEMENT which includes ratings counts. You can also use the legacy Reporter tool (java -jar Reporter.jar) to download Sales and Trends reports that include ratings metrics. It's not as clean as a direct REST endpoint for individual ratings, but it should give you the historical data you're looking for.
3w
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:
3w
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.
3w
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:
3w
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:
3w
Reply to How to identify free trial subscription transaction
In the JWS transaction payload (the one you get from Transaction.currentEntitlements client-side, or from Get Transaction Info server-side), there are two fields that together tell you unambiguously: offerType: an integer. 1 = introductory offer, 2 = promotional offer, 3 = offer code. Free trials are a form of introductory offer. offerDiscountType: a string enum. Values are FREE_TRIAL, PAY_AS_YOU_GO, or PAY_UP_FRONT. This is the one you probably actually want. If it equals FREE_TRIAL you're definitively in a trial. Important caveat: these fields are only populated while the transaction is in the promotional or intro period. Once the trial converts to paid, the subsequent renewal transaction won't have offerType set at all. So you can only detect "currently in free trial" from the currently-active transaction, not by looking at historical renewal transactions. If you need this server-side (not on device): Call the App Store Server API Get Transaction Info endpoint for the transactionId in question. Or parse the signedTransactionInfo JWS from your App Store Server Notifications webhook. The SUBSCRIBED notification with offerDiscountType = FREE_TRIAL on initial subscribe is your signal. Strong recommendation: use the App Store Server Library (available for Swift, Java, Python, Node, Go). It handles JWS verification and decoding for you, rather than rolling your own JWT parse which is easy to get subtly wrong around certificate chain validation. WWDC22 "Explore App Store server APIs" and WWDC23 "Meet StoreKit 2" both cover this.
Replies
Boosts
Views
Activity
2w
Reply to Apple Server Notifications Webhooks stopped retrying on HTTP 400
The retry policy is actually documented behavior, though enforcement seems to have gotten stricter around that date. Apple's webhook retry rules: 2xx response: success, no retry (as expected). 4xx response: treated as a permanent failure. Your server is effectively saying "this notification is malformed or not for me", so no retry because retrying won't help. 5xx response: treated as a temporary failure. Retries follow the documented schedule (5 attempts over roughly 3 days). No response or timeout: also treated as temporary failure, retried. If you want retries, return 5xx (or just let your server error naturally). Returning 400 tells Apple "I got your notification but I permanently cannot process it, don't bother sending again." Before that change, 4xx may have been getting retried in some cases, which wasn't the documented behavior. The March 2026 change likely aligned actual behavior with what the docs have always said. Two things I'd check: Why is your server returning 400 in the first place? If it's a decode failure on a malformed payload (JWS signature check failing, etc.), that might warrant returning 500 so you get retries and can investigate. If it's intentional validation rejection, 400 is fine but log it so you know what's being discarded. Use the App Store Server API requestTestNotification plus getTestNotificationStatus endpoints to verify your webhook end-to-end without waiting on real transactions.
Topic: App & System Services SubTopic: StoreKit Tags:
Replies
Boosts
Views
Activity
2w
Reply to Why Non-Consumable product has originalTransactionId?
This trips up a lot of people coming from the verifyReceipt world. Short version: transactionId is not stable for a non-consumable. It changes every time the purchase is "issued" to a device, which includes restore, re-download on a new device, Family Sharing additions, etc. originalTransactionId is the stable identifier. For one non-consumable purchase, reinstalled across multiple devices, you'll see: originalTransactionId: same value across all entries (the first purchase). transactionId: a new value for each issuance event. That's why querying Get Transaction Info with different transactionId values over time can return what looks like the same product ownership. Each one represents a separate re-issuance of the same underlying entitlement. Rules of thumb for backend storage: Use originalTransactionId as the stable "user owns this product" key in your database. Use transactionId only when you need a unique identifier for a specific issuance event, e.g. deduplication on your webhook. For Family Sharing, check inAppOwnershipType on each transaction: PURCHASED means the user bought it, FAMILY_SHARED means they received it via Family Sharing. They can share the same originalTransactionId but have different transactionIds. WWDC23 "Meet StoreKit 2" walks through this relationship visually if you want more context.
Topic: App & System Services SubTopic: StoreKit Tags:
Replies
Boosts
Views
Activity
2w
Reply to StoreKit Configuration Not Syncing to Xcode
The "Synced @ [time]" timestamp updating while content stays empty is one of those bugs where everything looks correct and nothing works. A few things that usually fix it: Most common cause: the subscriptions in App Store Connect aren't fully configured. The sync only pulls subscriptions that have localization, pricing, and review info all filled in for at least one language. If any single one of those is missing, that subscription gets silently skipped. Open each subscription in App Store Connect and look for red "Missing Metadata" warnings. The subscription group itself matters. Xcode pulls the group along with the subscriptions. If the group has no localization (display name, level), nothing under it comes across. Sign out and back into your Apple ID in Xcode > Settings > Accounts. The auth token for the App Store Connect API can go stale and the sync silently fails for one team while appearing to succeed. If none of that helps, just build the .storekit file manually. It's usually faster than fighting the sync. In the editor, click + and add each subscription with the same product ID as in App Store Connect. The IDs are all that need to match; the pricing in the file is only used by the local StoreKit simulator, not production. Did you try fetching products with Product.products(for:) at runtime (without a .storekit file) pointed at sandbox? If those also come back empty, the problem is on the App Store Connect side, not Xcode's sync.
Topic: App & System Services SubTopic: StoreKit Tags:
Replies
Boosts
Views
Activity
2w
Reply to Subscription Unavailable - Strange Behavior with StoreKit
Seen this one a lot. "Subscription is unavailable in the current storefront" almost always comes down to one of these, in order of likelihood: Paid Apps Agreement isn't in Active state for the team. Open App Store Connect > Agreements, Tax, and Banking. If the Paid Apps agreement shows anything other than Active (Action Required, missing bank info, missing tax forms, or a contact who's no longer on the team), every subscription rejects with this exact error until it's resolved. The subscription's price schedule doesn't include the user's storefront. Each subscription has pricing set per country. If you only configured prices for some countries, users outside that list get this error. Check the Price tab on the subscription and confirm the user's country is covered. The app and the subscription are in different availability regions. Even with pricing set, the app itself must also be available in that country. Check App Availability on the main app page. The subscription isn't actually in "Ready for Sale" state. After app approval, a subscription can still sit at "Ready to Submit" if it wasn't attached to the submission that got reviewed. It needs to have cleared review and be Ready for Sale. Easiest diagnostic: have a friend in a different country try it. Works there but not for you = storefront/availability issue. Fails universally = agreements issue. Three days of waiting is actually normal for storefront propagation the first time a subscription goes live, but only the first time. After that it should be immediate.
Topic: App & System Services SubTopic: StoreKit Tags:
Replies
Boosts
Views
Activity
2w
Reply to AppStore.sync() not restoring purchases
Classic StoreKit 1 to 2 migration pitfall. A few things worth checking: The sandbox account matters more than you'd expect. When you reinstall, make sure you're signed into the same sandbox Apple ID that actually made the SK1 purchase. If it's a fresh sandbox user or a different one, there's literally no transaction to restore. Settings > Developer > Sandbox Apple Account shows who's currently active. For a non-consumable originally purchased via SK1, after AppStore.sync() completes, the transaction shows up in Transaction.currentEntitlements with its original productID, but the id or originalID might be a legacy numeric identifier rather than a UUID. If you're filtering entitlements by anything other than productID, that could be why you don't see it. AppStore.sync() triggers an Apple ID password prompt. If the user cancels that prompt, it returns without throwing but also without actually syncing. Wrap it in try/catch and log so you can distinguish canceled vs successful vs failed. If this is a TestFlight build rather than a sandbox-signed build, TestFlight uses the production App Store Commerce backend. You won't be able to restore SK1 sandbox purchases across, only production purchases the TF user actually made. One more thing: check Transaction.all (not just currentEntitlements) after sync. If the old SK1 transactions show up there but not in currentEntitlements, it's a filtering issue on your side. If they don't appear in Transaction.all at all, the sync isn't reaching them, which usually points back to point 1.
Topic: App & System Services SubTopic: StoreKit Tags:
Replies
Boosts
Views
Activity
2w
Reply to StoreKit 2: Transaction.all and Transaction.currentEntitlements return empty for valid non-consumable purchases in production
Seen this pattern a few times. Transaction.all and Transaction.currentEntitlements both read from a local transaction cache that StoreKit 2 builds by syncing with Apple's servers. If that sync has never completed for the current user on the current device, both streams come back empty even when the purchase still exists server-side. Users who tend to land in this state: Restored the device from a backup and haven't re-signed into the Apple ID that owns the purchase. Family Sharing participants (not the original buyer). There's been a recurring regression on 26.x where family-shared non-consumables disappear from currentEntitlements after a restore. Changed their Apple ID on the device at some point. The unblock for all of these is AppStore.sync(). Gate it behind a "Restore Purchases" button (it prompts for Apple ID password, so never call it on launch), and re-read currentEntitlements after it completes. That's the officially documented recovery path for this exact scenario. If sync() doesn't recover them, the App Store Server API (GET /inApps/v1/history/{transactionId}) is still available server-side and will tell you whether Apple still recognises the purchase at all. That at least narrows it to a device-state issue vs. a server-side one worth escalating to DTS. Any pattern in the affected users? Recent device restores, family sharing, Apple ID changes?
Topic: App & System Services SubTopic: StoreKit Tags:
Replies
Boosts
Views
Activity
2w
Reply to Live Activity updates not received on iPhone 16 Pro Max when started via ActivityKit push
When "start arrives but updates don't" on one specific device, it's almost always one of three things. Walking through them: Wrong push token for updates. The start push uses apns-push-type: liveactivity plus your app's device token. But once the activity is running, each activity has its own token delivered via Activity.pushToken (or pushTokenUpdates as an async sequence). Every update has to go to that per-activity token, not the device token, and not a stale token from a previous activity. Worth logging and diffing the token you're actually sending between 16 Pro and 16 Pro Max. stale-date already in the past. iOS silently drops updates whose stale-date is before "now" on the device. Small clock drift or a timezone mismatch is enough. Try pushing with stale-date explicitly far in the future and see if that changes anything. content-state schema mismatch. If your ContentState decoder throws on the update payload (new field, wrong type, enum case removed), the update is dropped with no user-visible signal. Start payloads tend to be more forgiving than updates. Quickest way to know which of the three it is: install the ActivityKit logging profile from Apple's developer downloads and filter Console.app on liveactivities while pushing to the 16 Pro Max. The logs will tell you whether APNs delivered the payload and it got rejected, or it never arrived at all.
Replies
Boosts
Views
Activity
2w
Reply to Xcode 26 Causing StoreKit Fiasco for macOS?
Sounds like a frustrating regression. Before chalking it up to a bug, a few things worth trying: The transaction cache in Xcode's StoreKit environment gets into weird states after major version upgrades. From Xcode, open Debug > StoreKit > Manage Transactions, delete everything in there, then clean build folder (Shift-Cmd-K), nuke DerivedData, and restart Xcode. On the running target, delete the app entirely before re-running. Second, check your scheme's StoreKit configuration setting. The Xcode 16 to 26 migration has been resetting "StoreKit Configuration" to None on some projects. Edit Scheme > Run > Options, confirm your .storekit file is still selected. Third, when purchases silently fail without even showing the confirmation sheet, it's usually the store failing to resolve the product ID. Open the .storekit file, hit the refresh/sync icon, and confirm every product identifier matches what your code requests exactly (it's case-sensitive). Did macOS also update around the same time? When it's not Xcode, it's usually commercekit or storekitd on the host Mac. Console.app filtered by those processes while you try a purchase will tell you if the daemon is the actual culprit.
Topic: App & System Services SubTopic: StoreKit Tags:
Replies
Boosts
Views
Activity
2w
Reply to Is there a reliable way to check pending agreement status for multiple App Store Connect accounts via API?
Your analysis is correct. The /v1/agreements endpoint was deprecated and removed in newer API versions, which is why you get a 404 on some accounts (likely those using newer API keys or auth scopes). There is no dedicated "agreement status" endpoint, so the 403 gate is genuinely the only signal available via the API. The enforcement is progressive as you guessed: the UI shows the warning immediately, but the API only blocks once the grace period expires. One additional probe that tends to fail earlier than bundleIds/certificates is attempting to create or update an app store version via POST /v1/appStoreVersions or listing your apps with GET /v1/apps since those operations are more sensitive to agreement state. Not a perfect solution, but it might shrink the detection gap for your dashboard.
Replies
Boosts
Views
Activity
3w
Reply to Is there a way to pull Ratings data via API or other method?
The App Store Connect API doesn't expose standalone ratings (without reviews), but you can get aggregate ratings data through the App Analytics reports. Specifically, the Analytics Reports API lets you request report types like APP_STORE_ENGAGEMENT which includes ratings counts. You can also use the legacy Reporter tool (java -jar Reporter.jar) to download Sales and Trends reports that include ratings metrics. It's not as clean as a direct REST endpoint for individual ratings, but it should give you the historical data you're looking for.
Replies
Boosts
Views
Activity
3w
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
3w
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
3w
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
3w
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
3w