In Getting started with In-App Purchase using StoreKit views and the corresponding sample project, Store simultaneously enumerates Transaction.unfinished and Transaction.updates.
Since, "if your app has unfinished transactions, the updates listener receives them once, immediately after the app launches," it appears that Transaction.unfinished would also receive the same unfinished transactions causing handle(updatedTransaction:) to be called for twice for each transaction, causing consumables to be double-counted.
Is this a bug in the sample? Is there more information on concurrent execution of unfinished and updates?
StoreKit
RSS for tagSupport in-app purchases and interactions with the App Store using StoreKit.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
I get crash reports which I can't reproduce when trying to present an SKStoreProductViewController :
Fatal Exception: UIApplicationInvalidInterfaceOrientation
Supported orientations has no common orientation with the application, and [SKStoreProductViewController shouldAutorotate] is returning YES
No matter what app Deployment info orientation I try I can't get my SKStoreProductViewController shouldAutorotate property to return YES. It is always false.
Does anyone knows why or how to get an SKStoreProductViewController to return shouldAutorotate YES?
Topic:
App & System Services
SubTopic:
StoreKit
We feel like we're at the end of the long and treacherous process of migrating to StoreKit2. But we've hit a small snag. When testing in the sandbox environment, we've found that if we don't finish a transactions, no subsequent purchase (invoked via call to purchase or the other purchase) will produce the confirmation sheet. Is this the expected behavior? The behavior is observed on iOS26 and 18.
Our app will only attempt to finish the transaction if it successfully uploads the receipt to our API. If it fails to do so for whatever reason, the transaction is left unfinished. Whilst the user is informed about this, users will commonly try again. Our concern is that since the confirmation sheet will not be shown again, users will not know they are actually paying again - most certainly not the UX we want to have. We'd much rather have our users be fully aware when they're paying us money.
The reason we're choosing not to finish the transaction until our backend has received it and confirmed the receipt to be valid is that the only way the user can get their product is if the server side is aware of this and add more time to the users account. When finishing the transaction via finish immediately after the purchase() call, the confirmation sheet is shown every time after subsequent calls to purchase().
Again, is this the expected behavior both in the sandbox and the production environments? Are we doing something wrong or misusing the product API? We are somewhat stumped because technically, we could get the first confirmation for a product purchase, and then finish it only after an arbitrary amount of calls to purchase() have been made - the user will believe they will have paid only once, but we will receive however much money we can drain from their account - most certainly not the kind of app we want to develop.
Please advise and best regards,
Emīls
I have setup offer codes and subscriptions for users to purchase, when a user signs up using an offer code outside of the app the offer code does not save into my database where the subscriptions are saved
the transaction is successful and validated by store kit but I cant see that that user used an offer code - an example
https://apps.apple.com/redeem/?ctx=offercodes&id=6744338284&code=ASKDOM
I then setup an edge function in supabase to retrieve the data that store kit sends back and im not sure where to find the offer code as it still doesnt save
is there an internal apple reference that they use as apposed to the users offer code i.e offer code askdomSA = P3050 for example
how can Identify if an offer code was used
thank you
最近我们有个应用要对接App 内购买项目,有什么好的资料或者demo提供一下吗?
I am using Store Kit 2 to implement In App Purchases for my app. I need to maintain a pending state in the UI for all my pending purchases. Is there a way to get a list of all pending purchases? If not, is there a way to know if my pending purchase was cancelled?
We’re testing SKAN postbacks via AdAttributionKit but aren’t receiving any requests on our server even after generating development impressions and triggering a postback.
Setup:
Domain: https://linkrunner-skan.com
Configured in Info.plist as:
<key>NSAdvertisingAttributionReportEndpoint</key>
<string>https://linkrunner-skan.com</string>
<key>AttributionCopyEndpoint</key>
<string>https://linkrunner-skan.com</string>
Apple automatically appends the .well-known paths:
/.well-known/private-click-measurement/report-attribution/
/.well-known/skadnetwork/report-attribution/
ATS diagnostics for the domain: PASS for all tests (TLS 1.0–1.3, PFS disabled, arbitrary loads allowed, etc.)
Both .well-known paths are publicly accessible and return 200 OK
Testing Flow:
Enabled Developer → AdAttributionKit Developer Mode on iOS (15+)
Followed Apple’s official guide: Testing AdAttributionKit with Developer Mode
Generated test impression using:
createAdAttributionKitDevelopmentImpression implemented in SKANManager.swift
Called Postback.updateConversionValue with lockPostback: true
Created Development Postback from Developer Settings
Waited 30+ minutes while intercepting server requests (proxy + backend logs)
What We’ve Tried So Far:
Confirmed ATS compliance with nscurl --ats-diagnostics (all PASS)
Verified .well-known paths are accessible publicly without redirects
Tested endpoints manually with a POST request – server responds 200 OK
Confirmed Info.plist entries exactly match Apple’s required keys
Double-checked iOS device is running iOS 15+ with Developer Mode enabled
Repeated test flow multiple times with fresh impressions and postbacks
Waited up to 1 hour for postback (in case of delays)
Issue:
No POST requests are being received from Apple to either .well-known endpoint, even though the setup appears correct and ATS tests pass.
References Used:
Configuring an Advertised App
Generating JWS Impressions
Question:
Has anyone faced a similar issue where AdAttributionKit Development Postbacks are not firing despite correct Info.plist setup, ATS compliance, and reachable .well-known endpoints?
Any insight into possible missing configuration steps or testing nuances would be greatly appreciated.
We have received reports from users that their in-app purchases suddenly appear as unpurchased.
We would like to know the cause of this issue.
Our implementation does not use a server; purchases are determined solely on the client side.
These reports often occur after updating the app version,
but we have been unable to reproduce the issue in our development environment.
Topic:
App & System Services
SubTopic:
StoreKit
I have an iOS and iPadOS app that also runs on macOS Catalyst. The user is able to view their subscription using the SubscriptionStoreView with two SubscriptionOptionGroups.
The documentation does not mention these are supported on macOS Catalyst and the app crashes when attempting to show the SubscriptionStoreView on macOS Catalyst.
If not supported, how can the user manage their subscription on macOS?
Hi,
Using StoreKit 2 with App Store Server notifications like so:
User selects a purchase
App calls Product.purchase()
If successful, App Store notifies our backend with the transaction details, importantly with a UUID for the transaction ID.
This works fine, but when I try to test contingent pricing via the handy StoreKit config Transaction Manager in Xcode by creating a PurchaseIntent if I then complete the purchase in the app the Transaction ID is sequential, (0 for the first, 1 for the second etc), which doesn't work for us as the backend might already have that ID stored so the purchase never completes.
If I disable the config file it works fine, but then I can't use the Transaction Manager debug tool. Is there a way to override the ID of a custom transaction that's created via the StoreKit configuration?
Thanks
Is the following subscription cancellation flow possible for an iOS in-app subscription?
(Note: This is during the feature planning stage, not actual app deployment.)
Planned user flow:
User taps the “Cancel Subscription” button
Display a “Wait a moment!” screen showing how much the user has enjoyed BFLIX content (to encourage retention)
User taps “Proceed to Cancel”
Collect cancellation reason from the user
Redirect the user to the Apple subscription management page to complete cancellation
Can this flow be implemented under Apple’s current in-app purchase and App Store Review guidelines?
Topic:
App & System Services
SubTopic:
StoreKit
Hi
To test SkAdNetwork, I installed the profile from the documentation (https://developer.apple.com/documentation/storekit/testing-ad-attributions-with-a-downloaded-profile) on my ios device.
and turned off and on Allow Apps to Request to Track to change the idfa value.
In this state, I installed the app (bundle id: id436731843) using SKAdNetwork with the following values at April 8th AM 01 (UTC)
SkAdnetwork version: 3.0
fidelity
fidelity=0, nonce=b3346a51-f7b5-42a2-a508-775a62317c83, timestamp=1744076349671, signature=...
fidelity=1, nonce=b3346a51-f7b5-42a2-a508-775a62317c83, timestamp=1744076349672, signature=...
itunesitem=436731843
network=87u5trcl3r.skadnetwork
sourceapp=1220307907
I was hoping to get a postback after , but after a day, the postback is still not delivered.
Any idea why the postback is not delivered?
Thank you
Topic:
App & System Services
SubTopic:
StoreKit
Hi,
I have a setup using App Store Server notifications, which has worked fine for a while now. However, I've never been able to successfully verify a purchase via Xcode, only via TestFlight.
The reason for this is that the StoreKit transactions have numerical IDs (e.g. starting from 0, incrementing one-by-one), instead of UUIDs like in TestFlight/production.
This means that often the backend will detect an existing transaction with the same ID and not complete the purchase.
What are we meant to do here? If I send a custom ID to make it unique the backend won't accept this - I can ask them to change this for our dev environment but it's not ideal.
What I'm after is a way to use UUIDs for transaction IDs when running via Xcode.
Thanks
Topic:
App & System Services
SubTopic:
StoreKit
I’m reaching out regarding our existing in-app subscription implementation that currently uses App Store Server Notifications version 1 (v1). Our live application has a significant number of active recurring subscriptions that are being managed through the v1 webhook integration.
We have now developed a revamped version of our application, which uses the same Apple Developer Account and App Store Connect setup, but in this new app version, we’ve implemented App Store Server Notifications version 2 (v2).
Before moving forward with the migration, I would like to clarify the following points to ensure a smooth transition and avoid any disruptions to ongoing subscriptions:
Backward Compatibility:
Will existing active subscriptions (originally created and managed via v1 notifications) continue to work seamlessly once we switch to v2, or do we need to maintain both v1 and v2 endpoints during the transition?
Notification Delivery:
If both webhook versions are configured simultaneously, will Apple send notifications to both endpoints, or only the one currently configured in App Store Connect?
Migration Strategy:
What is Apple’s recommended best practice for migrating from v1 to v2 in a scenario where the live app still has active subscriptions tied to the v1 webhook?
Potential Risks or Considerations:
Are there any known limitations, delays, or issues that we should prepare for during this migration (for example, differences in payload structure or event types between v1 and v2 that could affect subscription lifecycle management)?
I would greatly appreciate your guidance or documentation links that outline the correct migration steps and recommended approach for ensuring continuity of service for all existing subscribers.
Topic:
App & System Services
SubTopic:
StoreKit
Tags:
Subscriptions
App Store
App Store Server Notifications
Currently, we are using the Apple V2 interface to develop the payment function. We generate a transaction ID on the mobile client and obtain the receipt. Now, when we call the Apple sandbox environment interface to verify the receipt, we always get a 404 error. The above is the request and response. The token used in it is also the original data after decoding, and there is no problem. Could you help me figure out what other possible reasons there might be?
Topic:
App & System Services
SubTopic:
StoreKit
My server's access to Apple's payment interface (buy. itunes. apple. com/verifiyReceipt) has been unresponsive since the end of March, and I have been searching for a long time without finding any issues. Normally, even if the data is incorrect, there is still a {"status": 21000} response. We are using Alibaba Cloud's virtual servers here. I don't know if Apple has made any adjustments to the interface. If anyone has encountered this problem, please kindly help to answer it. Thank you all.
Topic:
App & System Services
SubTopic:
StoreKit
I am finding that the verifyReceipt endpoint used to verify a receipt is failing on occassion starting around October 27, 2015. I realize this API is deprecated. I am using cURL to call verifyReceipt. The specific errors are 52 - Empty reply from server and 56 - Connection closed abruptly. This indicates an issue with Apple's server as I understand it.
Is anyone else experiencing this as well?
我正在通过集成app-store-server-library-java来实现 iap服务端校验。我参照了官网提供的Verification Usage 的代码,运行的时候异常信息如下:
at com.apple.itunes.storekit.verification.ChainVerifier.verifyChainWithoutCaching(ChainVerifier.java:98)
at com.apple.itunes.storekit.verification.ChainVerifier.verifyChain(ChainVerifier.java:71)
at com.apple.itunes.storekit.verification.SignedDataVerifier.decodeSignedObject(SignedDataVerifier.java:186)
at com.apple.itunes.storekit.verification.SignedDataVerifier.verifyAndDecodeTransaction(SignedDataVerifier.java:72)
我的代码如下:
import com.apple.itunes.storekit.model.ResponseBodyV2DecodedPayload;
import com.apple.itunes.storekit.verification.SignedDataVerifier;
import com.apple.itunes.storekit.verification.VerificationException;
import com.auth0.jwt.JWT;
import com.auth0.jwt.interfaces.DecodedJWT;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.Base64;
import java.util.Set;
public class ExampleVerification {
public static void main(String[] args) throws FileNotFoundException {
String bundleId = "com.example";
Environment environment = Environment.SANDBOX;
Set<InputStream> rootCAs = Set.of(
new FileInputStream("AppleRootCA-G3.cer"),
new FileInputStream("AppleRootCA-G2.cer")
);
Long appAppleId = null; // appAppleId must be provided for the Production environment
SignedDataVerifier signedPayloadVerifier = new SignedDataVerifier(rootCAs, bundleId, appAppleId, environment, true);
String appTransactionJWS = "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6IkFwcGxlX1hjb2RlX0tleSIsIng1YyI6WyJNSUlCeXpDQ0FYR2dBd0lCQWdJQkFUQUtCZ2dxaGtqT1BRUURBakJJTVNJd0lBWURWUVFERXhsVGRHOXlaVXRwZENCVVpYTjBhVzVuSUdsdUlGaGpiMlJsTVNJd0lBWURWUVFLRXhsVGRHOXlaVXRwZENCVVpYTjBhVzVuSUdsdUlGaGpiMlJsTUI0WERUSTFNRFl3TXpFeE1UQXdNRm9YRFRJMk1EWXdNekV4TVRBd01Gb3dTREVpTUNBR0ExVUVBeE1aVTNSdmNtVkxhWFFnVkdWemRHbHVaeUJwYmlCWVkyOWtaVEVpTUNBR0ExVUVDaE1aVTNSdmNtVkxhWFFnVkdWemRHbHVaeUJwYmlCWVkyOWtaVEJaTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEEwSUFCTnZZZ3o1MW1CbEMweE5McW9rMUJCcithRWJEb1ZEeVkyaVRsejZsK1JjYVR4QStVY2ptMjBESTNncFFlM280a2doRGxSbGowdEo1enBGUHgyQWR2VCtqVERCS01CSUdBMVVkRXdFQlwvd1FJTUFZQkFmOENBUUF3SkFZRFZSMFJCQjB3RzRFWlUzUnZjbVZMYVhRZ1ZHVnpkR2x1WnlCcGJpQllZMjlrWlRBT0JnTlZIUThCQWY4RUJBTUNCNEF3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQU40bUJWTHBoZkpjYjdweHF2b09XcjkyK1czYU5LRG9pazV5Vk9BT0NEVmxBaUFYWVF0czJubWZGMStGYzlSODJHXC96QWhaVU00aDNTXC9VdFE4Q1lPS2p3ZlE9PSJdfQ.eyJhcHBsaWNhdGlvblZlcnNpb24iOiIxIiwib3JpZ2luYWxQdXJjaGFzZURhdGUiOjAsImJ1bmRsZUlkIjoiYnJpZ2h0LnVuaWhhbmQuY24iLCJhcHBUcmFuc2FjdGlvbklkIjoiMCIsImRldmljZVZlcmlmaWNhdGlvbiI6IlRYdGRvMWZtNDhQVDdXUUh5cHU4K2l3TW55YmNoTTNNeG5XUnhOR1JqSFhQQnVqMXdUaldcL05zN3JtUmJlQTd3IiwicmVjZWlwdFR5cGUiOiJYY29kZSIsIm9yaWdpbmFsQXBwbGljYXRpb25WZXJzaW9uIjoiMSIsInJlcXVlc3REYXRlIjoxNzYxMDM1OTMzNTE3LCJvcmlnaW5hbFBsYXRmb3JtIjoiaU9TIiwicmVjZWlwdENyZWF0aW9uRGF0ZSI6MTc2MTAzNTkzMzUxNywiZGV2aWNlVmVyaWZpY2F0aW9uTm9uY2UiOiI1ZDhmNzM5Mi01N2YwLTQyM2YtOTMzNy1hZDQ0YTk5MDM4Y2EifQ.2ZO5xsx-yywP4IyaDz4KQ3mq181ZGwlX2uANSm-kHq50KIdMMUDveMsCrcZmHdzLH2rpfPsXKaIMdM25Hdcuuw";
DecodedJWT unverifiedJWT = JWT.decode(appTransactionJWS);
String header = unverifiedJWT.getHeader();
System.out.println(new String(Base64.getDecoder().decode(header)));
try {
signedPayloadVerifier.verifyAndDecodeTransaction(appTransactionJWS);
} catch (VerificationException e) {
e.printStackTrace();
}
}
}
查看了ChainVerifier.java 源代码,发现
private static final int EXPECTED_CHAIN_LENGTH = 3; // <--- 关键常量
// ...
PublicKey verifyChainWithoutCaching(String[] certificates, boolean performRevocationChecking, Date effectiveDate) throws VerificationException {
// ... 解析证书代码 ...
if (parsedCertificates.size() != EXPECTED_CHAIN_LENGTH) {
throw new VerificationException(VerificationStatus.INVALID_CHAIN_LENGTH); // <--- 抛出异常点
}
// ... 后续验证代码 ...
}
appTransactionJWS是来自客户端的沙盒环境。
我发现沙盒环境的jws总是包含一个证书,而后端验证又必须要求三个证书,请问这个问题如何解决。
Topic:
App & System Services
SubTopic:
StoreKit
Apple review says , my app displayed an error when we attempted to purchase subscriptions. Please review the details and resources below and complete the next steps.
Device type: iPad Air (5th generation)
OS version: iPadOS 26.0.1
Next Steps
When validating receipts on your server, your server needs to be able to handle a production-signed app getting its receipts from Apple’s test environment. The recommended approach is for your production server to always validate receipts against the production App Store first. If validation fails with the error code "Sandbox receipt used in production," you should validate against the test environment instead.
Question: Is it due to Device being used by reviewer or is it really from my code. As my code relies on Apple infrastructure for purchases and all things.
Initially i did had subscription reporting api for receipt handling and all.When i went through with ChatGPT it did say that issue is due to half baked subscription module on my server. So i decided not to send any Subscription related things to backend, now it's Apple only and on App side.
Is it correct fix ? Or do i need to fix backend even though i have no use for it ?
My team did test in sandbox env via internal testing that time we had no issues. And all was tested using Mobile devices, that's why i still have question just to be sure these errors are due to devices or not?
Screenshot shared by Apple team did show they got a error popup saying Something went wrong : Unable to complete request. I am trying to reproduce in development but can't.
Anyone had got same issue before and has information on how to resolve and test for it will be helpful.
Thanks
Shikhar Sahu
Hi does anyone have trouble using expo store review package for ios apps. for some reason on our app., the review may show for certain people, but when they submit a review, it doesn't update our review count
Topic:
App & System Services
SubTopic:
StoreKit