App Store Server API

RSS for tag

Call this REST API from your server to request and provide information about your customers' in-app purchases.

Posts under App Store Server API tag

38 Posts

Post

Replies

Boosts

Views

Activity

App Store Server Notification v2: how to distinguish a resubscription that happened in-app from one that happened in Settings → Subscriptions?
Context We're handling App Store subscriptions on the server side using App Store Server Notification v2. Our pipeline currently identifies each event by transactionId and originalTransactionId. A few notes about our client: Our app is built with Flutter and uses the standard in_app_purchase plugin layer to drive App Store purchases (StoreKit 1 under the hood). We have not migrated to StoreKit 2 on the client yet. We have not been setting SKPayment.applicationUsername on outgoing purchases, so every transaction we've ever produced has appAccountToken: null in its v2 notification. This question is purely about what the server-side notification can tell us, given the current client state above. What we're trying to figure out A user can resubscribe to an expired subscription in two different places: In-app — the user opens our app and re-purchases through our normal in-app purchase flow. App Store — the user goes to Settings → Apple ID → Subscriptions and resubscribes from the system UI, without ever returning to the app. Both paths trigger a SUBSCRIBED notification (subtype RESUBSCRIBE) with structurally identical payloads as far as we can tell — same shape for data.transactionInfo, data.renewalInfo, etc. From the notification alone we can't decide which path produced it. The reason this matters: in our system, the two paths require different business handling: In-app path: the user may have signed in to a different business account in our app. The new subscription should be attributed to whoever paid in the app just now, not to the previous owner of originalTransactionId. App Store path: there is no in-app signal, so the business owner can only be inferred from the previous originalTransactionId mapping. If we get it wrong, the subscription's entitlement ends up on the wrong business account. What we do today Because we can't tell the paths apart from the notification, we defer processing for a few minutes and check whether an in-app order for the same transaction has arrived in the meantime: If an in-app order shows up → it's the in-app path; attribute to the in-app account. If nothing shows up after the delay → assume App Store path; fall back to the previous owner mapping. This works but adds latency to entitlement activation and forces us to build a deferred-retry queue with idempotency against the in-app callback path. Possible direction: appAccountToken / applicationUsername We noticed that v2 notifications carry transactionInfo.appAccountToken, and the docs suggest that StoreKit 1's SKPayment.applicationUsername (when it's a valid UUID) is mirrored into this field. In theory, if we start setting it on every in-app purchase from the Flutter client, the field could double as a path discriminator on the server: appAccountToken != null → in-app path (only the app can set it), and we even get the business user id for free appAccountToken == null → App Store path (no UI to populate it) But we have some open questions before committing to this direction: Questions Is there an existing signal in ResponseBodyV2 / JWSTransactionDecodedPayload / JWSRenewalInfoDecodedPayload that distinguishes these two paths, that I might be missing? Can the same distinction be obtained via getAllSubscriptionStatuses / getTransactionHistory / any other Server API endpoint? Is applicationUsername (StoreKit 1) still a reliable way to populate appAccountToken on v2 notifications today? Specifically: Are there format constraints beyond "valid UUID" that cause Apple to drop the value? Any known differences between sandbox and production in how it's mirrored? Does the App Store path ever strip or overwrite a previously-set value when the same originalTransactionId is reused? For existing subscriptions where applicationUsername was never set (which is all of ours today, since we've never polient), is there any way to retroactively distinguish the in-app vs App Store path? Or is timing-based deferred matching theonly option for that cohort, even after we start setting the value on new purchases? If neither (1) nor (2) is currently possible, is the timing-based heuristic we use today the pattern Apple expects developers to follow, or is there a recommended approach we're missing? A small suggestion, if it turns out there's no existing way If the information genuinely isn't exposed today, it might be worth surfacing a salesChannel-style field on the transaction, similar to what Google Play Developer API exposes on Order.salesChannel (IN_APP, PLAY_STORE, etc.). That would let server-side handlers route each event to the correct business owner immediately, regardless of whether appAccountToken was set, and would also cover legacynt never had a chance to populate it. Thanks — happy to share sample payloads or more detail if helpful.
1
0
53
1d
How to validate App Store receipts and check subscription status from my server?
Hello, I have an app on the App Store that offers in-app purchases (consumable, non-consumable) and auto-renewable subscriptions. My goal is to verify the validity of purchase receipts on my own backend server, to prevent fraudulent transactions. My questions: Does Apple provide an API that allows my server to validate a receipt (the one generated after a purchase) and confirm whether it is genuine? For auto-renewable subscriptions, can I retrieve renewal dates, expiration dates, and current renewal status using that same API? From reading the documentation, I understand that Apple provides the App Store Server API and the App Store Server Notifications. Is this the correct approach for receipt validation and subscription status checking? Any clarification or code example would be greatly appreciated. Thank you.
1
0
94
1w
Significant delay in Transaction ID availability via App Store Server API (Error 4040010)
Hi everyone, I’ve been encountering a recurring issue with the App Store Server API over the past 48 hours, specifically regarding the Get Transaction Info endpoint. Endpoint: GET /inApps/v1/transactions/{transactionId} Environment: Production Error Code: 4040010 (TransactionIdNotFound) The Issue When a user completes a purchase in our app, the client-side sends the transactionId to our backend for validation. However, when our server immediately calls the Get Transaction Info API using that ID, it frequently returns a 4040010 error, stating that the transaction ID cannot be found. Key Observations Eventual Consistency Delay: If we implement a retry logic and wait for 2 to 5 minutes, the exact same transactionId eventually becomes queryable and returns a valid signedTransactionInfo. Notifications vs. API: Interestingly, our server receives the App Store Server Notifications V2 (webhook) for these transactions almost instantly. The notifications contain the correct data, but the "Pull" API seems to lag behind the "Push" notification system. Recent Spikes: This behavior started occurring frequently within the last 2 days. Prior to this, the API was almost always near-instant. Questions Has anyone else noticed a spike in 4040010 errors or increased indexing latency in the Production environment recently? Is there a recommended "grace period" or backoff strategy when querying for a new transactionId? Apple's documentation doesn't explicitly mention an expected delay between a successful purchase and its availability via the Server API. Any insights or confirmation of similar issues would be greatly appreciated!
1
0
101
2w
Apple Server Notifications Webhooks stopped retrying on HTTP 400
Hey We have noticed a change in the retry behavior of Apple Server Notifications webhooks V2 starting around March 12–13, 2026. Previously, when our webhook endpoint returned an HTTP 400 response, Apple would retry the notification delivery multiple times according to the documented retry policy. However, beginning around March 12–13, it appears that Apple no longer retries the webhook when a 400 response is returned. The notification is sent only once and no further retry attempts are made. From our understanding of the documentation, retries should occur when delivery fails, and historically we observed retries even for some 4xx responses. We would like to confirm: Has Apple recently changed the retry behavior for Server Notifications? Are HTTP 4xx responses (specifically 400) now considered terminal failures that will not trigger retries? Is this change intentional or related to a rollout in the webhook delivery system? We have called the "Notification History" endpoint for some users who purchased a sub and we are only getting one attempt with the following data in it: { attemptDate: 1773469202552, (2026-03-14T06:20:02.552Z) sendAttemptResult: 'UNSUCCESSFUL_HTTP_RESPONSE_CODE', } This was 2 days ago, based on the docs, the user should have a few attempts at least. This behavior change affects systems that rely on retries to handle temporary validation issues or transient failures. Thanks!
4
2
242
3w
Why Non-Consumable product has originalTransactionId?
I try to call Get Transaction Info from App Store Server API, and the transactionId is for a Non-consumable type product, but it is odd that there are so many different transactionId and they have a same originalTransactionId { "bundleId": "${bundleId}", "environment": "Production", "inAppOwnershipType": "PURCHASED", "originalPurchaseDate": 1691220528000, "originalTransactionId": "${originalTransactionId}", "productId": "${productId}", "purchaseDate": 1691220528000, "quantity": 1, "signedDate": 1692590989925, "storefront": "USA", "storefrontId": "143441", "transactionId": "${originalTransactionId}", "transactionReason": "PURCHASE", "type": "Non-Consumable" } the defination of Non-Consumable is can only purchase once for same apple account. But why there would have originalTransactionId?
4
0
1.2k
3w
Authentication Error with App Store Server API (NOT_AUTHORIZED) while Using JWT for Subscription Validation
Hello Apple Developer Community, We are currently facing an authentication issue when calling the App Store Server API for subscription validation. Despite following Apple’s documentation and verifying all credentials, we consistently receive a NOT_AUTHORIZED error response. GET https://api.storekit-sandbox.itunes.apple.com/inApps/v1/transactions/appTransactions/{transactionId} Environment: Sandbox and Production (both tested, same result) Our Setup: Key ID: {Your Key ID} Issuer ID: {Your Issuer ID} Bundle ID: {Your Bundle ID} JWT Header: { "alg": "ES256", "kid": "" } JWT Payload: { "iss": "", "iat": , "exp": <timestamp + 5 minutes>, "aud": "appstoreconnect-v1", "bid": "" } Authorization Header: Authorization: Bearer Troubleshooting Steps Already Taken: Verified that .p8 key, Key ID, Issuer ID, and Bundle ID are all correctly configured and match the App Store Connect details. Confirmed that the system clock is accurate (UTC). Used appropriate endpoint (sandbox or production) based on environment. Ensured that the JWT is short-lived (under 5 minutes). Added the “Bearer” prefix correctly in the header. Tested JWT generations using Python. Issue: All requests return: { "errorCode": "NOT_AUTHORIZED" } Questions: Are there any additional claims or headers required for the subscriptions endpoint? Are there specific permissions or roles needed for the API key in App Store Connect? Is there a way to get more detailed logs or diagnostics for this NOT_AUTHORIZED response? Does the App Store Server API require a different aud or bid structure for certain endpoints? We already contacted Apple Developer Support, but they suggested posting here for engineering-level guidance. Any insight or examples of a working JWT + request for this endpoint would be greatly appreciated.
1
0
402
Apr ’26
Unexpected 401 Unauthorized response from production endpoint when using sandbox transactionId with Get Transaction Info API
We have encountered an issue when verifying transactions using the Get Transaction Info API. We tested the behavior in both the sandbox and production environments and observed the following results. When calling the production endpoint: https://api.storekit.itunes.apple.com/inApps/v1/transactions/{transactionId} with a transactionId generated in the sandbox environment, the API returns HTTP 401 Unauthorized. However, based on the documentation and common understanding, we expected HTTP 404 Not Found in this case. Using the same JWT token, if we call the sandbox endpoint: https://api.storekit-sandbox.itunes.apple.com/inApps/v1/transactions/{transactionId}, we receive HTTP 200 OK with the expected response body. We have also confirmed that the same behavior occurs when using the Get Transaction History API — it works correctly in the sandbox environment but returns 401 in production. Could you please confirm whether this behavior (receiving 401 instead of 404) is expected by design, or if it indicates a potential issue? If this is not the intended behavior, we would appreciate any guidance or instructions to resolve it. Thank you very much for your technical support. 「Get Transaction Info」APIを用いてトランザクションの検証を行ったところ、以下の問題が発生しました。 サンドボックス環境および本番環境の両方で検証を行い、次の結果を確認しています。 本番環境エンドポイント https://api.storekit.itunes.apple.com/inApps/v1/transactions/{transactionId} に対して サンドボックス環境で生成された transactionId を使用すると、HTTP 401 Unauthorized が返却されます。 (一般的には、この場合 404 Not Found が返る想定であると理解しています。) 同一のJWTトークン を用いて サンドボックス環境のエンドポイント https://api.storekit-sandbox.itunes.apple.com/inApps/v1/transactions/{transactionId} を呼び出した場合は、HTTP 200 OK が返り、期待通りのレスポンスボディを受け取ることができています。 また、同様の挙動が Get Transaction History を使用した場合にも発生することを確認しています。 サンドボックス環境では正常に動作しますが、本番環境では401が返却されます。 この挙動(401が返却されること)は仕様上想定されたものか、または何らかの問題によるものかご確認をお願いいたします。 もし想定外の挙動である場合は、解決に向けたご案内をいただけますと幸いです。 本件について、技術的なサポートをお願いいたします。 よろしくお願いいたします。
3
0
359
Apr ’26
Migration Subscription API returns 500 error
We got Advanced Commerce API and the generic product identifiers approved. When I was try to migrate a sandbox subscription to ACA enabled subscription I hit an error Request payload (Hid some info but the requestReferenceId is the real) { "descriptors": { "description": "Migrated", "displayName": "Migration" }, "items": [ { "sku": "product_1mo_999", "description": "description", "displayName": "Product" } ], "requestInfo": { "requestReferenceId": "3b0b8e67-d8a0-45f4-8f6d-06bffa9a2c08" }, "storefront": "USA", "targetProductId": "com.company.generic.subscription", "taxCode": "C003-00-1" } Response { "errorCode": 5000000, "errorMessage": "An unknown error occurred." }
3
0
379
Apr ’26
prorated refund and upgrade of tier
Hi all, I'm encountering an issue with auto-renewable subscription upgrades in the App Store. Here's my setup: Context: Plan A: Base Plan (yearly auto-renewable subscription) Plan B: Pro Plan (monthly auto-renewable subscription) B is configured as an upgrade from A. Issue: When a user with an active Plan A subscription upgrades to Plan B, I correctly receive an App Store Server Notification v2 with DID_CHANGE_RENEWAL_PREF and UPGRADE subtype. According to Apple's documentation, a prorated refund is issued automatically in this scenario, and no separate REFUND event is sent, the refund information should be retrievable through the upgrade event itself. Testing in Sandbox: In my sandbox tests, Plan A has a 1-hour duration and Plan B has a 5-minute duration. After the user upgrades to Plan B, I immediately cancel the subscription to prevent auto-renewal. Expected vs. Actual Behavior: After the 5 minutes expire, Plan A still appears as the active current entitlement. I initially thought this might be because the prorated refund hadn't been processed yet. However, even after waiting the full hour (the original duration of Plan A), it continues to show as an active entitlement—which shouldn't be the case. As a result, when I attempt to restore purchases, Plan A is still identified as valid and the subscription gets reactivated. Question: Is this behavior expected in the sandbox environment, or am I missing something in how the prorated refund and entitlement expiration should be handled?
1
0
424
Apr ’26
How to choose between v1 & v2 for App Store Server Notifications
Based on https://developer.apple.com/help/app-store-connect/configure-in-app-purchase-settings/enter-server-urls-for-app-store-server-notifications It seems like we can choose between version 1 or version 2 notification Choose either Version 1 (deprecated) or Version 2 notifications. Learn about versions of App Store Server Notifications. However, I do not find a way to make such a choice. Does anyone know, how I can choose between v1 or v2 notification? We currently provide a self-hosted server endpoint built on the v1 specification. While the existing server is perfectly stable, we are evaluating a migration to v2. Thanks.
1
0
85
Apr ’26
In-App Purchase dialog not appearing during App Review but works on physical device
Hi everyone, My app has been rejected twice under Guideline 2.1(b) - App Completeness because the reviewer says the In-App Purchase does not trigger a purchase flow when tapping the purchase button. However, I have tested it on a physical iPhone (iOS 18.6.2) and the StoreKit purchase dialog appears and completes successfully. I have confirmed: Paid Apps Agreement is active In-App Purchase product (non-consumable) is configured correctly Sandbox test account works fine Purchase flow works on physical device with screen recording as proof The reviewer tested on iPad Air 11-inch (M3) with iPadOS 26.4. My app uses Flutter with the in_app_purchase package (v3.2.0). The purchase implementation: Calls InAppPurchase.instance.isAvailable() Queries product details with queryProductDetails() Calls buyNonConsumable() when user taps purchase button I found and fixed a potential null reference issue in the purchase completer that could cause the purchase to fail silently, but I'm not sure if this was the exact cause since I cannot reproduce the issue. Has anyone experienced a similar situation where IAP works on device but fails during App Review? Any suggestions on what might be different in the review environment? Thank you.
2
0
115
Apr ’26
Significant delay in Transaction ID availability via App Store Server API (Error 4040010)
Hi everyone, I’ve been encountering a recurring issue with the App Store Server API over the past 48 hours, specifically regarding the Get Transaction Info endpoint. Endpoint: GET /inApps/v1/transactions/{transactionId} Environment: Production Error Code: 4040010 (TransactionIdNotFound) The Issue When a user completes a purchase in our app, the client-side sends the transactionId to our backend for validation. However, when our server immediately calls the Get Transaction Info API using that ID, it frequently returns a 4040010 error, stating that the transaction ID cannot be found. Key Observations Eventual Consistency Delay: If we implement a retry logic and wait for 2 to 5 minutes, the exact same transactionId eventually becomes queryable and returns a valid signedTransactionInfo. Notifications vs. API: Interestingly, our server receives the App Store Server Notifications V2 (webhook) for these transactions almost instantly. The notifications contain the correct data, but the "Pull" API seems to lag behind the "Push" notification system. Recent Spikes: This behavior started occurring frequently within the last 2 days. Prior to this, the API was almost always near-instant. Questions Has anyone else noticed a spike in 4040010 errors or increased indexing latency in the Production environment recently? Is there a recommended "grace period" or backoff strategy when querying for a new transactionId? Apple's documentation doesn't explicitly mention an expected delay between a successful purchase and its availability via the Server API. Any insights or confirmation of similar issues would be greatly appreciated!
1
0
110
Mar ’26
Apple Pay v2 (signedTransactionInfo) : how to verify new token format and migrate from legacy EC_v1?
I’m updating a legacy application that used Apple Pay v1 token format, and in my new revamped version I’m now receiving the newer Apple Pay v2 format. The old (v1) payload looked like this: php { "version": "EC_v1", "data": "...", "signature": "...", "header": { "ephemeralPublicKey": "...", "publicKeyHash": "...", "transactionId": "..." } } In the new revamp (v2), Apple Pay returns this instead: php { "signedTransactionInfo": "eyJhbGciOiJFUzI1NiIsIng1YyI6WyJNSUlF..." } From what I understand: v1 tokens were elliptic-curve encrypted JSON objects containing a header and signature. v2 tokens seem to be JWS (JSON Web Signature) strings using the ES256 algorithm, possibly containing transaction and subscription details inside. Questions Is there any official Apple documentation or migration note explaining the move from EC_v1 → signedTransactionInfo? How should I verify or decode the new signedTransactionInfo payload? Should the verification now use Apple’s public keys instead of the legacy Merchant ID certificate? Are there any example implementations or SDKs that can handle both v1 and v2 formats during migration? Is there a recommended way to maintain backward compatibility while transitioning existing users? Goal Ensure that my revamped app can handle Apple Pay v2 tokens securely while keeping the legacy v1 integration functional until all users are migrated.
1
0
520
Feb ’26
Not receiving any App Store Server Notifications when upgrading Monthly -> Yearly subscription
Scenario: User is actively subscribed to Monthly Package From the Device App (Manage Subscriptions), user upgrades to Yearly Package Purchase completes successfully on device Issue: Do not receive any server notification for this action Month Package Purchase Date: 2025-11-11 19:06:45.537 +0600 Month to Yearly Upgradation Date: 2025-12-11 paymentReferenceId: 510002270528780
1
0
160
Jan ’26
Not receiving any App Store Server Notifications when upgrading Monthly -> Yearly subscription
Scenario User is actively subscribed to Monthly Package From the Device App (Manage Subscriptions), user upgrades to Yearly Package Purchase completes successfully on device Issue Do not receive any server notification for this action Month Package Purchase Date: 2025-11-11 19:06:45.537 +0600 Month to Yearly Upgradation Date: 2025-12-11 paymentReferenceId: 510002270528780
1
0
126
Jan ’26
App Store Server Notification v2: how to distinguish a resubscription that happened in-app from one that happened in Settings → Subscriptions?
Context We're handling App Store subscriptions on the server side using App Store Server Notification v2. Our pipeline currently identifies each event by transactionId and originalTransactionId. A few notes about our client: Our app is built with Flutter and uses the standard in_app_purchase plugin layer to drive App Store purchases (StoreKit 1 under the hood). We have not migrated to StoreKit 2 on the client yet. We have not been setting SKPayment.applicationUsername on outgoing purchases, so every transaction we've ever produced has appAccountToken: null in its v2 notification. This question is purely about what the server-side notification can tell us, given the current client state above. What we're trying to figure out A user can resubscribe to an expired subscription in two different places: In-app — the user opens our app and re-purchases through our normal in-app purchase flow. App Store — the user goes to Settings → Apple ID → Subscriptions and resubscribes from the system UI, without ever returning to the app. Both paths trigger a SUBSCRIBED notification (subtype RESUBSCRIBE) with structurally identical payloads as far as we can tell — same shape for data.transactionInfo, data.renewalInfo, etc. From the notification alone we can't decide which path produced it. The reason this matters: in our system, the two paths require different business handling: In-app path: the user may have signed in to a different business account in our app. The new subscription should be attributed to whoever paid in the app just now, not to the previous owner of originalTransactionId. App Store path: there is no in-app signal, so the business owner can only be inferred from the previous originalTransactionId mapping. If we get it wrong, the subscription's entitlement ends up on the wrong business account. What we do today Because we can't tell the paths apart from the notification, we defer processing for a few minutes and check whether an in-app order for the same transaction has arrived in the meantime: If an in-app order shows up → it's the in-app path; attribute to the in-app account. If nothing shows up after the delay → assume App Store path; fall back to the previous owner mapping. This works but adds latency to entitlement activation and forces us to build a deferred-retry queue with idempotency against the in-app callback path. Possible direction: appAccountToken / applicationUsername We noticed that v2 notifications carry transactionInfo.appAccountToken, and the docs suggest that StoreKit 1's SKPayment.applicationUsername (when it's a valid UUID) is mirrored into this field. In theory, if we start setting it on every in-app purchase from the Flutter client, the field could double as a path discriminator on the server: appAccountToken != null → in-app path (only the app can set it), and we even get the business user id for free appAccountToken == null → App Store path (no UI to populate it) But we have some open questions before committing to this direction: Questions Is there an existing signal in ResponseBodyV2 / JWSTransactionDecodedPayload / JWSRenewalInfoDecodedPayload that distinguishes these two paths, that I might be missing? Can the same distinction be obtained via getAllSubscriptionStatuses / getTransactionHistory / any other Server API endpoint? Is applicationUsername (StoreKit 1) still a reliable way to populate appAccountToken on v2 notifications today? Specifically: Are there format constraints beyond "valid UUID" that cause Apple to drop the value? Any known differences between sandbox and production in how it's mirrored? Does the App Store path ever strip or overwrite a previously-set value when the same originalTransactionId is reused? For existing subscriptions where applicationUsername was never set (which is all of ours today, since we've never polient), is there any way to retroactively distinguish the in-app vs App Store path? Or is timing-based deferred matching theonly option for that cohort, even after we start setting the value on new purchases? If neither (1) nor (2) is currently possible, is the timing-based heuristic we use today the pattern Apple expects developers to follow, or is there a recommended approach we're missing? A small suggestion, if it turns out there's no existing way If the information genuinely isn't exposed today, it might be worth surfacing a salesChannel-style field on the transaction, similar to what Google Play Developer API exposes on Order.salesChannel (IN_APP, PLAY_STORE, etc.). That would let server-side handlers route each event to the correct business owner immediately, regardless of whether appAccountToken was set, and would also cover legacynt never had a chance to populate it. Thanks — happy to share sample payloads or more detail if helpful.
Replies
1
Boosts
0
Views
53
Activity
1d
How to validate App Store receipts and check subscription status from my server?
Hello, I have an app on the App Store that offers in-app purchases (consumable, non-consumable) and auto-renewable subscriptions. My goal is to verify the validity of purchase receipts on my own backend server, to prevent fraudulent transactions. My questions: Does Apple provide an API that allows my server to validate a receipt (the one generated after a purchase) and confirm whether it is genuine? For auto-renewable subscriptions, can I retrieve renewal dates, expiration dates, and current renewal status using that same API? From reading the documentation, I understand that Apple provides the App Store Server API and the App Store Server Notifications. Is this the correct approach for receipt validation and subscription status checking? Any clarification or code example would be greatly appreciated. Thank you.
Replies
1
Boosts
0
Views
94
Activity
1w
Significant delay in Transaction ID availability via App Store Server API (Error 4040010)
Hi everyone, I’ve been encountering a recurring issue with the App Store Server API over the past 48 hours, specifically regarding the Get Transaction Info endpoint. Endpoint: GET /inApps/v1/transactions/{transactionId} Environment: Production Error Code: 4040010 (TransactionIdNotFound) The Issue When a user completes a purchase in our app, the client-side sends the transactionId to our backend for validation. However, when our server immediately calls the Get Transaction Info API using that ID, it frequently returns a 4040010 error, stating that the transaction ID cannot be found. Key Observations Eventual Consistency Delay: If we implement a retry logic and wait for 2 to 5 minutes, the exact same transactionId eventually becomes queryable and returns a valid signedTransactionInfo. Notifications vs. API: Interestingly, our server receives the App Store Server Notifications V2 (webhook) for these transactions almost instantly. The notifications contain the correct data, but the "Pull" API seems to lag behind the "Push" notification system. Recent Spikes: This behavior started occurring frequently within the last 2 days. Prior to this, the API was almost always near-instant. Questions Has anyone else noticed a spike in 4040010 errors or increased indexing latency in the Production environment recently? Is there a recommended "grace period" or backoff strategy when querying for a new transactionId? Apple's documentation doesn't explicitly mention an expected delay between a successful purchase and its availability via the Server API. Any insights or confirmation of similar issues would be greatly appreciated!
Replies
1
Boosts
0
Views
101
Activity
2w
How to identify free trial subscription transaction
In the verifyReceipt API response, there is a "is_trial_period" field. As detailed in WWDC 2023 the verifyReceipt is deprecated, how to fetch the fact that the subscription is during the free trial period via recommended App Store server APIs?
Replies
6
Boosts
0
Views
2.9k
Activity
3w
Apple Server Notifications Webhooks stopped retrying on HTTP 400
Hey We have noticed a change in the retry behavior of Apple Server Notifications webhooks V2 starting around March 12–13, 2026. Previously, when our webhook endpoint returned an HTTP 400 response, Apple would retry the notification delivery multiple times according to the documented retry policy. However, beginning around March 12–13, it appears that Apple no longer retries the webhook when a 400 response is returned. The notification is sent only once and no further retry attempts are made. From our understanding of the documentation, retries should occur when delivery fails, and historically we observed retries even for some 4xx responses. We would like to confirm: Has Apple recently changed the retry behavior for Server Notifications? Are HTTP 4xx responses (specifically 400) now considered terminal failures that will not trigger retries? Is this change intentional or related to a rollout in the webhook delivery system? We have called the "Notification History" endpoint for some users who purchased a sub and we are only getting one attempt with the following data in it: { attemptDate: 1773469202552, (2026-03-14T06:20:02.552Z) sendAttemptResult: 'UNSUCCESSFUL_HTTP_RESPONSE_CODE', } This was 2 days ago, based on the docs, the user should have a few attempts at least. This behavior change affects systems that rely on retries to handle temporary validation issues or transient failures. Thanks!
Replies
4
Boosts
2
Views
242
Activity
3w
Why Non-Consumable product has originalTransactionId?
I try to call Get Transaction Info from App Store Server API, and the transactionId is for a Non-consumable type product, but it is odd that there are so many different transactionId and they have a same originalTransactionId { "bundleId": "${bundleId}", "environment": "Production", "inAppOwnershipType": "PURCHASED", "originalPurchaseDate": 1691220528000, "originalTransactionId": "${originalTransactionId}", "productId": "${productId}", "purchaseDate": 1691220528000, "quantity": 1, "signedDate": 1692590989925, "storefront": "USA", "storefrontId": "143441", "transactionId": "${originalTransactionId}", "transactionReason": "PURCHASE", "type": "Non-Consumable" } the defination of Non-Consumable is can only purchase once for same apple account. But why there would have originalTransactionId?
Replies
4
Boosts
0
Views
1.2k
Activity
3w
85% of Subscriptions are in Billing Retry State
One of our apps has 85% stuck in Billing Retry -- We are so confused. All the users are from the US, and have a one-week free trial. We had 1,000 subscriptions expire from this issue. So any help would be so appreciated.
Replies
3
Boosts
2
Views
295
Activity
Apr ’26
Authentication Error with App Store Server API (NOT_AUTHORIZED) while Using JWT for Subscription Validation
Hello Apple Developer Community, We are currently facing an authentication issue when calling the App Store Server API for subscription validation. Despite following Apple’s documentation and verifying all credentials, we consistently receive a NOT_AUTHORIZED error response. GET https://api.storekit-sandbox.itunes.apple.com/inApps/v1/transactions/appTransactions/{transactionId} Environment: Sandbox and Production (both tested, same result) Our Setup: Key ID: {Your Key ID} Issuer ID: {Your Issuer ID} Bundle ID: {Your Bundle ID} JWT Header: { "alg": "ES256", "kid": "" } JWT Payload: { "iss": "", "iat": , "exp": <timestamp + 5 minutes>, "aud": "appstoreconnect-v1", "bid": "" } Authorization Header: Authorization: Bearer Troubleshooting Steps Already Taken: Verified that .p8 key, Key ID, Issuer ID, and Bundle ID are all correctly configured and match the App Store Connect details. Confirmed that the system clock is accurate (UTC). Used appropriate endpoint (sandbox or production) based on environment. Ensured that the JWT is short-lived (under 5 minutes). Added the “Bearer” prefix correctly in the header. Tested JWT generations using Python. Issue: All requests return: { "errorCode": "NOT_AUTHORIZED" } Questions: Are there any additional claims or headers required for the subscriptions endpoint? Are there specific permissions or roles needed for the API key in App Store Connect? Is there a way to get more detailed logs or diagnostics for this NOT_AUTHORIZED response? Does the App Store Server API require a different aud or bid structure for certain endpoints? We already contacted Apple Developer Support, but they suggested posting here for engineering-level guidance. Any insight or examples of a working JWT + request for this endpoint would be greatly appreciated.
Replies
1
Boosts
0
Views
402
Activity
Apr ’26
Unexpected 401 Unauthorized response from production endpoint when using sandbox transactionId with Get Transaction Info API
We have encountered an issue when verifying transactions using the Get Transaction Info API. We tested the behavior in both the sandbox and production environments and observed the following results. When calling the production endpoint: https://api.storekit.itunes.apple.com/inApps/v1/transactions/{transactionId} with a transactionId generated in the sandbox environment, the API returns HTTP 401 Unauthorized. However, based on the documentation and common understanding, we expected HTTP 404 Not Found in this case. Using the same JWT token, if we call the sandbox endpoint: https://api.storekit-sandbox.itunes.apple.com/inApps/v1/transactions/{transactionId}, we receive HTTP 200 OK with the expected response body. We have also confirmed that the same behavior occurs when using the Get Transaction History API — it works correctly in the sandbox environment but returns 401 in production. Could you please confirm whether this behavior (receiving 401 instead of 404) is expected by design, or if it indicates a potential issue? If this is not the intended behavior, we would appreciate any guidance or instructions to resolve it. Thank you very much for your technical support. 「Get Transaction Info」APIを用いてトランザクションの検証を行ったところ、以下の問題が発生しました。 サンドボックス環境および本番環境の両方で検証を行い、次の結果を確認しています。 本番環境エンドポイント https://api.storekit.itunes.apple.com/inApps/v1/transactions/{transactionId} に対して サンドボックス環境で生成された transactionId を使用すると、HTTP 401 Unauthorized が返却されます。 (一般的には、この場合 404 Not Found が返る想定であると理解しています。) 同一のJWTトークン を用いて サンドボックス環境のエンドポイント https://api.storekit-sandbox.itunes.apple.com/inApps/v1/transactions/{transactionId} を呼び出した場合は、HTTP 200 OK が返り、期待通りのレスポンスボディを受け取ることができています。 また、同様の挙動が Get Transaction History を使用した場合にも発生することを確認しています。 サンドボックス環境では正常に動作しますが、本番環境では401が返却されます。 この挙動(401が返却されること)は仕様上想定されたものか、または何らかの問題によるものかご確認をお願いいたします。 もし想定外の挙動である場合は、解決に向けたご案内をいただけますと幸いです。 本件について、技術的なサポートをお願いいたします。 よろしくお願いいたします。
Replies
3
Boosts
0
Views
359
Activity
Apr ’26
Migration Subscription API returns 500 error
We got Advanced Commerce API and the generic product identifiers approved. When I was try to migrate a sandbox subscription to ACA enabled subscription I hit an error Request payload (Hid some info but the requestReferenceId is the real) { "descriptors": { "description": "Migrated", "displayName": "Migration" }, "items": [ { "sku": "product_1mo_999", "description": "description", "displayName": "Product" } ], "requestInfo": { "requestReferenceId": "3b0b8e67-d8a0-45f4-8f6d-06bffa9a2c08" }, "storefront": "USA", "targetProductId": "com.company.generic.subscription", "taxCode": "C003-00-1" } Response { "errorCode": 5000000, "errorMessage": "An unknown error occurred." }
Replies
3
Boosts
0
Views
379
Activity
Apr ’26
prorated refund and upgrade of tier
Hi all, I'm encountering an issue with auto-renewable subscription upgrades in the App Store. Here's my setup: Context: Plan A: Base Plan (yearly auto-renewable subscription) Plan B: Pro Plan (monthly auto-renewable subscription) B is configured as an upgrade from A. Issue: When a user with an active Plan A subscription upgrades to Plan B, I correctly receive an App Store Server Notification v2 with DID_CHANGE_RENEWAL_PREF and UPGRADE subtype. According to Apple's documentation, a prorated refund is issued automatically in this scenario, and no separate REFUND event is sent, the refund information should be retrievable through the upgrade event itself. Testing in Sandbox: In my sandbox tests, Plan A has a 1-hour duration and Plan B has a 5-minute duration. After the user upgrades to Plan B, I immediately cancel the subscription to prevent auto-renewal. Expected vs. Actual Behavior: After the 5 minutes expire, Plan A still appears as the active current entitlement. I initially thought this might be because the prorated refund hadn't been processed yet. However, even after waiting the full hour (the original duration of Plan A), it continues to show as an active entitlement—which shouldn't be the case. As a result, when I attempt to restore purchases, Plan A is still identified as valid and the subscription gets reactivated. Question: Is this behavior expected in the sandbox environment, or am I missing something in how the prorated refund and entitlement expiration should be handled?
Replies
1
Boosts
0
Views
424
Activity
Apr ’26
How to choose between v1 & v2 for App Store Server Notifications
Based on https://developer.apple.com/help/app-store-connect/configure-in-app-purchase-settings/enter-server-urls-for-app-store-server-notifications It seems like we can choose between version 1 or version 2 notification Choose either Version 1 (deprecated) or Version 2 notifications. Learn about versions of App Store Server Notifications. However, I do not find a way to make such a choice. Does anyone know, how I can choose between v1 or v2 notification? We currently provide a self-hosted server endpoint built on the v1 specification. While the existing server is perfectly stable, we are evaluating a migration to v2. Thanks.
Replies
1
Boosts
0
Views
85
Activity
Apr ’26
In-App Purchase dialog not appearing during App Review but works on physical device
Hi everyone, My app has been rejected twice under Guideline 2.1(b) - App Completeness because the reviewer says the In-App Purchase does not trigger a purchase flow when tapping the purchase button. However, I have tested it on a physical iPhone (iOS 18.6.2) and the StoreKit purchase dialog appears and completes successfully. I have confirmed: Paid Apps Agreement is active In-App Purchase product (non-consumable) is configured correctly Sandbox test account works fine Purchase flow works on physical device with screen recording as proof The reviewer tested on iPad Air 11-inch (M3) with iPadOS 26.4. My app uses Flutter with the in_app_purchase package (v3.2.0). The purchase implementation: Calls InAppPurchase.instance.isAvailable() Queries product details with queryProductDetails() Calls buyNonConsumable() when user taps purchase button I found and fixed a potential null reference issue in the purchase completer that could cause the purchase to fail silently, but I'm not sure if this was the exact cause since I cannot reproduce the issue. Has anyone experienced a similar situation where IAP works on device but fails during App Review? Any suggestions on what might be different in the review environment? Thank you.
Replies
2
Boosts
0
Views
115
Activity
Apr ’26
Significant delay in Transaction ID availability via App Store Server API (Error 4040010)
Hi everyone, I’ve been encountering a recurring issue with the App Store Server API over the past 48 hours, specifically regarding the Get Transaction Info endpoint. Endpoint: GET /inApps/v1/transactions/{transactionId} Environment: Production Error Code: 4040010 (TransactionIdNotFound) The Issue When a user completes a purchase in our app, the client-side sends the transactionId to our backend for validation. However, when our server immediately calls the Get Transaction Info API using that ID, it frequently returns a 4040010 error, stating that the transaction ID cannot be found. Key Observations Eventual Consistency Delay: If we implement a retry logic and wait for 2 to 5 minutes, the exact same transactionId eventually becomes queryable and returns a valid signedTransactionInfo. Notifications vs. API: Interestingly, our server receives the App Store Server Notifications V2 (webhook) for these transactions almost instantly. The notifications contain the correct data, but the "Pull" API seems to lag behind the "Push" notification system. Recent Spikes: This behavior started occurring frequently within the last 2 days. Prior to this, the API was almost always near-instant. Questions Has anyone else noticed a spike in 4040010 errors or increased indexing latency in the Production environment recently? Is there a recommended "grace period" or backoff strategy when querying for a new transactionId? Apple's documentation doesn't explicitly mention an expected delay between a successful purchase and its availability via the Server API. Any insights or confirmation of similar issues would be greatly appreciated!
Replies
1
Boosts
0
Views
110
Activity
Mar ’26
Apple Server Notifications V2
I am in a process to change ASSN-V2 url, However i am still receiving Subscription notifications on old URL. Changed to new URL from Appstore connect --> --> App Information. Old URL is pointing to aws lambda. New URL is pointing to a third party provider (confirmed not received notification.) Any pointers ?
Replies
1
Boosts
0
Views
399
Activity
Mar ’26
Purchase your membership.
Hello. Despite making my membership payment (and accidentally twice!), my membership is still not activated even after 62 hours. I contacted their support system but received no response. Does anyone have any suggestions?
Replies
0
Boosts
0
Views
170
Activity
Mar ’26
Apple Pay v2 (signedTransactionInfo) : how to verify new token format and migrate from legacy EC_v1?
I’m updating a legacy application that used Apple Pay v1 token format, and in my new revamped version I’m now receiving the newer Apple Pay v2 format. The old (v1) payload looked like this: php { "version": "EC_v1", "data": "...", "signature": "...", "header": { "ephemeralPublicKey": "...", "publicKeyHash": "...", "transactionId": "..." } } In the new revamp (v2), Apple Pay returns this instead: php { "signedTransactionInfo": "eyJhbGciOiJFUzI1NiIsIng1YyI6WyJNSUlF..." } From what I understand: v1 tokens were elliptic-curve encrypted JSON objects containing a header and signature. v2 tokens seem to be JWS (JSON Web Signature) strings using the ES256 algorithm, possibly containing transaction and subscription details inside. Questions Is there any official Apple documentation or migration note explaining the move from EC_v1 → signedTransactionInfo? How should I verify or decode the new signedTransactionInfo payload? Should the verification now use Apple’s public keys instead of the legacy Merchant ID certificate? Are there any example implementations or SDKs that can handle both v1 and v2 formats during migration? Is there a recommended way to maintain backward compatibility while transitioning existing users? Goal Ensure that my revamped app can handle Apple Pay v2 tokens securely while keeping the legacy v1 integration functional until all users are migrated.
Replies
1
Boosts
0
Views
520
Activity
Feb ’26
Not receiving any App Store Server Notifications when upgrading Monthly -> Yearly subscription
Scenario: User is actively subscribed to Monthly Package From the Device App (Manage Subscriptions), user upgrades to Yearly Package Purchase completes successfully on device Issue: Do not receive any server notification for this action Month Package Purchase Date: 2025-11-11 19:06:45.537 +0600 Month to Yearly Upgradation Date: 2025-12-11 paymentReferenceId: 510002270528780
Replies
1
Boosts
0
Views
160
Activity
Jan ’26
Not receiving any App Store Server Notifications when upgrading Monthly -> Yearly subscription
Scenario User is actively subscribed to Monthly Package From the Device App (Manage Subscriptions), user upgrades to Yearly Package Purchase completes successfully on device Issue Do not receive any server notification for this action Month Package Purchase Date: 2025-11-11 19:06:45.537 +0600 Month to Yearly Upgradation Date: 2025-12-11 paymentReferenceId: 510002270528780
Replies
1
Boosts
0
Views
126
Activity
Jan ’26
IAP应用内购买怎么配置升级的?
会员等级进行升级?需要按天计算费用,像爱奇艺这样是怎么做的?
Replies
0
Boosts
0
Views
238
Activity
Jan ’26