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

201 Posts

Post

Replies

Boosts

Views

Activity

Production subscription remains Active after failed payment and no funds deducted
Hello, We are investigating an auto-renewable monthly subscription in the Production environment. Timeline and observed behavior: On June 29, 2026, the user initiated the first subscription purchase. The Apple Account used WeChat Pay as its payment method. The WeChat charge failed because the balance was insufficient, and no funds were deducted from any available payment source. Nevertheless, StoreKit returned a verified transaction, the subscription purchase succeeded in the app, and App Store Connect Sales Analytics reports proceeds for the purchase. We grant entitlement based only on Apple's signed transaction and subscription status, so the user currently has access. As of July 20, 2026, Get All Subscription Statuses from App Store Server API returns: environment: Production status: 1 (Active) expiresDate: 2026-07-29T03:37:11Z autoRenewStatus: 1 no gracePeriodExpiresDate no revocationDate no expirationIntent no billing retry indication Our App Store Server Notifications endpoint has received only: SUBSCRIBED / INITIAL_BUY We have not received DID_FAIL_TO_RENEW, EXPIRED, REFUND, or REVOKE. Questions: Is it expected for Apple to issue a valid production initial-purchase transaction and report proceeds even when the underlying WeChat Pay charge failed and no money was deducted? Could this be an unpaid Apple Account balance or delayed settlement that is invisible to the developer? While the Server API returns status 1, should the developer continue granting entitlement until expiresDate? Is there another authoritative App Store Server API or signed field that indicates the payment has not actually been collected? If renewal or collection later fails, when should we expect DID_FAIL_TO_RENEW or a change to billing retry or expired status? We have intentionally omitted transaction IDs and account identifiers from this public post. I can provide them privately to Apple Support if needed. Thanks
0
0
26
1d
Apple-signed Production transactions return 404 (4040010) on every App Store Server API endpoint
Environment: Production. Bundle ID: com.filmixpro.filmix. (Team ID / notification URL available privately or via Feedback Assistant.) We received 7 App Store Server Notifications V2 (SUBSCRIBED) whose JWS signatures we successfully verified against Apple root CAs (decoded payloads show environment=Production, bundleId=com.filmixpro.filmix). However, querying the App Store Server API (production) for these originalTransactionIds returns 404 (4040010) "Transaction id not found" on EVERY endpoint: Get All Subscription Statuses, Get Transaction Info, Get Transaction History, Get Refund History, and Get Notification History (filtered by transactionId). The same API key resolves all other transactions correctly (these are 7 out of 3231 chains scanned). The IDs are also absent from the global Get Notification History (last 180 days). Sandbox returns 404 as well. One of them, 520002039865757, previously generated a REFUND_DECLINED notification (a refund was requested and DECLINED — i.e. not refunded), yet it too now returns 404 on every endpoint including Get Refund History, so the disappearance is not explained by a refund. Affected originalTransactionIds: 590002039736765, 590002053449909, 430002231597484, 70003114793852, 100002338147592, 520002039865757, 340001586213801 Questions: Why do Apple-signed, Production transactions return 404 "Transaction id not found" on all App Store Server API endpoints? Have these transactions been removed/invalidated (fraud, chargeback, account deletion, refund reversal)? If so, which category? We recently signed a previously-unsigned Paid Applications Agreement — does this affect API visibility of historical transactions, and what is the propagation time? How should we reconcile entitlement for transactions that were signed/notified but are not found in the Server API?
1
0
342
2w
Cannot load products in Sandbox
Hi, I'm trying to hook up some test in app purchases to test purchase code between our app and our app's backend. When I try to load products (requestProductData) with my Sandbox account, my product identifiers come back in the invalid product identifiers member of the response. My product says it's in "waiting for review" status in app store connect, and I'm logged in to the app store with my sandbox account on my device. We just accepted the paid apps agreement as well--is there some propagation time to that? The product ID I'm using (both in app store connect and in-app) is test_durable. Do I need to append the package name to that or something? I've dug through the docs and through the forums here and come up empty. I tried using the Xcode storekit test harness and the issue there is that because that doesn't actually talk to the store apis, I can't use that to test my backend correctly validating/processing the transactions. Thanks!
0
0
240
2w
Can Product.products / SKProductsRequest be used only for display metadata when EU storefront uses ExternalPurchaseCustomLink only?
This is a StoreKit / ExternalPurchaseCustomLink clarification. Apple DTS asked me to post the follow-up question here. We are designing an SDK for apps that support EU external purchase. In EU storefronts, the app will use ExternalPurchaseCustomLink only: No App Store In-App Purchase will be offered to users. No Product.purchase() will be called. No SKPaymentQueue.add(_:) will be called. The actual purchase will happen only on our external website through the ExternalPurchaseCustomLink flow. Question: In this EU ExternalPurchaseCustomLink-only setup, is it acceptable and supported to call Product.products(for:) / SKProductsRequest only to fetch product display metadata from App Store Connect? The metadata would only be used to display the product list UI, for example: product title / display name localized price currency / priceLocale formatting information The returned Product / SKProduct would not be used to start an App Store purchase. Or should apps avoid Product.products(for:) / SKProductsRequest entirely in EU storefronts where only ExternalPurchaseCustomLink is offered, and use their own product catalog instead?
1
0
330
3w
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
536
May ’26
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
751
May ’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
200
Apr ’26
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
360
Apr ’26
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.4k
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.
1
0
619
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
435
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
443
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
516
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
187
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
189
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
151
Mar ’26
Production subscription remains Active after failed payment and no funds deducted
Hello, We are investigating an auto-renewable monthly subscription in the Production environment. Timeline and observed behavior: On June 29, 2026, the user initiated the first subscription purchase. The Apple Account used WeChat Pay as its payment method. The WeChat charge failed because the balance was insufficient, and no funds were deducted from any available payment source. Nevertheless, StoreKit returned a verified transaction, the subscription purchase succeeded in the app, and App Store Connect Sales Analytics reports proceeds for the purchase. We grant entitlement based only on Apple's signed transaction and subscription status, so the user currently has access. As of July 20, 2026, Get All Subscription Statuses from App Store Server API returns: environment: Production status: 1 (Active) expiresDate: 2026-07-29T03:37:11Z autoRenewStatus: 1 no gracePeriodExpiresDate no revocationDate no expirationIntent no billing retry indication Our App Store Server Notifications endpoint has received only: SUBSCRIBED / INITIAL_BUY We have not received DID_FAIL_TO_RENEW, EXPIRED, REFUND, or REVOKE. Questions: Is it expected for Apple to issue a valid production initial-purchase transaction and report proceeds even when the underlying WeChat Pay charge failed and no money was deducted? Could this be an unpaid Apple Account balance or delayed settlement that is invisible to the developer? While the Server API returns status 1, should the developer continue granting entitlement until expiresDate? Is there another authoritative App Store Server API or signed field that indicates the payment has not actually been collected? If renewal or collection later fails, when should we expect DID_FAIL_TO_RENEW or a change to billing retry or expired status? We have intentionally omitted transaction IDs and account identifiers from this public post. I can provide them privately to Apple Support if needed. Thanks
Replies
0
Boosts
0
Views
26
Activity
1d
Apple-signed Production transactions return 404 (4040010) on every App Store Server API endpoint
Environment: Production. Bundle ID: com.filmixpro.filmix. (Team ID / notification URL available privately or via Feedback Assistant.) We received 7 App Store Server Notifications V2 (SUBSCRIBED) whose JWS signatures we successfully verified against Apple root CAs (decoded payloads show environment=Production, bundleId=com.filmixpro.filmix). However, querying the App Store Server API (production) for these originalTransactionIds returns 404 (4040010) "Transaction id not found" on EVERY endpoint: Get All Subscription Statuses, Get Transaction Info, Get Transaction History, Get Refund History, and Get Notification History (filtered by transactionId). The same API key resolves all other transactions correctly (these are 7 out of 3231 chains scanned). The IDs are also absent from the global Get Notification History (last 180 days). Sandbox returns 404 as well. One of them, 520002039865757, previously generated a REFUND_DECLINED notification (a refund was requested and DECLINED — i.e. not refunded), yet it too now returns 404 on every endpoint including Get Refund History, so the disappearance is not explained by a refund. Affected originalTransactionIds: 590002039736765, 590002053449909, 430002231597484, 70003114793852, 100002338147592, 520002039865757, 340001586213801 Questions: Why do Apple-signed, Production transactions return 404 "Transaction id not found" on all App Store Server API endpoints? Have these transactions been removed/invalidated (fraud, chargeback, account deletion, refund reversal)? If so, which category? We recently signed a previously-unsigned Paid Applications Agreement — does this affect API visibility of historical transactions, and what is the propagation time? How should we reconcile entitlement for transactions that were signed/notified but are not found in the Server API?
Replies
1
Boosts
0
Views
342
Activity
2w
Cannot load products in Sandbox
Hi, I'm trying to hook up some test in app purchases to test purchase code between our app and our app's backend. When I try to load products (requestProductData) with my Sandbox account, my product identifiers come back in the invalid product identifiers member of the response. My product says it's in "waiting for review" status in app store connect, and I'm logged in to the app store with my sandbox account on my device. We just accepted the paid apps agreement as well--is there some propagation time to that? The product ID I'm using (both in app store connect and in-app) is test_durable. Do I need to append the package name to that or something? I've dug through the docs and through the forums here and come up empty. I tried using the Xcode storekit test harness and the issue there is that because that doesn't actually talk to the store apis, I can't use that to test my backend correctly validating/processing the transactions. Thanks!
Replies
0
Boosts
0
Views
240
Activity
2w
Can Product.products / SKProductsRequest be used only for display metadata when EU storefront uses ExternalPurchaseCustomLink only?
This is a StoreKit / ExternalPurchaseCustomLink clarification. Apple DTS asked me to post the follow-up question here. We are designing an SDK for apps that support EU external purchase. In EU storefronts, the app will use ExternalPurchaseCustomLink only: No App Store In-App Purchase will be offered to users. No Product.purchase() will be called. No SKPaymentQueue.add(_:) will be called. The actual purchase will happen only on our external website through the ExternalPurchaseCustomLink flow. Question: In this EU ExternalPurchaseCustomLink-only setup, is it acceptable and supported to call Product.products(for:) / SKProductsRequest only to fetch product display metadata from App Store Connect? The metadata would only be used to display the product list UI, for example: product title / display name localized price currency / priceLocale formatting information The returned Product / SKProduct would not be used to start an App Store purchase. Or should apps avoid Product.products(for:) / SKProductsRequest entirely in EU storefronts where only ExternalPurchaseCustomLink is offered, and use their own product catalog instead?
Replies
1
Boosts
0
Views
330
Activity
3w
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
536
Activity
May ’26
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
751
Activity
May ’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
200
Activity
Apr ’26
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
3k
Activity
Apr ’26
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
360
Activity
Apr ’26
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.4k
Activity
Apr ’26
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
352
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
619
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
435
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
443
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
516
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
187
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
189
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
151
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
582
Activity
Mar ’26