I am developing and testing Apple Promotional Offers and encountered issues during implementation.
Purchase Failure
When using the following API, the promotional purchase sheet is displayed, but after attempting payment, the transaction fails.
API:
public static func promotionalOffer(
offerID: String,
keyID: String,
nonce: UUID,
signature: Data,
timestamp: Int
) -> Product.PurchaseOption
Observed behavior:
Alert shows:
Unable to Purchase [Environment: Xcode]
Not Eligible for Offer
Console logs:
AMSErrorDomain Code=305
ASDErrorDomain Code=3903
Discount Not Applied
When calling this API, there are no errors, but the promotional price is not applied, and the user still sees the original price.
API:
public static func promotionalOffer(
_ offerID: String,
compactJWS: String
) -> [Product.PurchaseOption]
Questions
Does Promotional Offers support testing with .storekit files in Xcode?
Can Promotional Offers be tested with sandbox accounts using real offers configured in App Store Connect?
How should I troubleshoot and resolve the above issues?
• Could it be related to the subscription history of the sandbox account?
• Do I need to use TestFlight instead of Xcode to test certain scenarios?
• Could this be caused by signature parameters or StoreKit configuration?
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
The development subscription management screen for managing your sandbox account subscriptions is today showing products that belong to other apps.
Is there a known issue right now?
Created a FB with screenshots
FB FB20199893
Topic:
App & System Services
SubTopic:
StoreKit
hello,
I have an app with In-App purchase set up, it works fine in TestFlight on an iOS device but the download from the App Store gives me a transaction failed message.
I tried to replicate in the simulator but from what I've read is that you can't do in-app purchase testing in the simulator. Perhaps I'm wrong here but I've tried multiple sandbox accounts, etc.. and still get an unusual "...password can't be reused..." error (pasted below) in the debug description.
I'm curious if anyone else has dealt with this scenario and if so how did you go about researching/identifying the issue and/or resolving it.
Partial error message:
<SKPaymentQueue: 0x60000000e370>: Payment completed with error: Error Domain=ASDErrorDomain Code=530 "(null)" UserInfo={NSUnderlyingError=0x600000c74750 {Error Domain=AMSErrorDomain Code=100 "Authentication Failed The authentication failed." UserInfo={NSMultipleUnderlyingErrorsKey=(
"Error Domain=AMSErrorDomain Code=2 "Password reuse not available for account The account state does not support password reuse." UserInfo={NSDebugDescription=Password reuse not available for account The account state does not support password reuse., AMSDescription=Password reuse not available for account, AMSFailureReason=The account state does not support password reuse.}"
works perfectly on android but doesn't work at all on IOS and i have used the same bundle id and product ids on both stores.
The error that i get on IOS is : "IAP initialization failed: NoProductsAvailable - No Product returned from store"
Here are the things that i've done:
Created an App ID on the apple developer portal with the correct capabilities
I have enabled the correct capabilities on the xcode project Unity Framework is embed and signed, Storekit (do not embed)
In singin and capabilities in-app purchases is there
I am using testflight to submit the app with a distribution certificate that appears to be valid
I've checked the the bundle identifier and it's the same everywhere (unity project, xcode project, App ID)
All of the products are cleared for sale and are in the status "ready to submit"
I always uninstall the old app version before testing the new one
My banking updates are still processing does this effect TestFlight IAP
Paid Apps Agreement is in Pending User Info state does this effect also
I still haven't filled out the tax forms, so I'm wondering if I need to complete them before my app's in-app purchases (IAPs) work in TestFlight.
Topic:
App & System Services
SubTopic:
StoreKit
Tags:
Subscriptions
In-App Purchase
Apple Unity Plug-Ins
Hi!
I'm trying to implement a two week free trial for my existing paid ipad app. Following the guidance from the wwdc2022/10007, I'm using AppTransaction.shared and checking the result. I'm getting a verified result, but the appTransaction.originalPurchaseDate is always the same date - 2013-08-01 07:00:00 +0000 / 397033200, even the particular sandbox account user never had a purchase.
This makes testing the logical branch of "has this user never purchased this app before" if the app store is always telling us that it's been purchased. (I've been using new sandbox account, so there should be no history)
Here's some code that includes hacking around always getting that original purchase date. We're in the final stretches, and wanting to test things that will be closer to actual store behavior (and I'm thinking that always returning a purchased date for an unpurchased app wouldn't be happening)
Am I just holding things wrong? Sandbox bug/limitatiin I just have to live with?
thanks!
++md
class MJAppStore: NSObject {
@objc static let shared = MJAppStore()
@objc func verifyAppStoreStatus(_ completion: @escaping (MJAppStoreStatus, Error?) -> Void) {
Task {
do {
let status = try await doVerificationThing()
completion(status, nil)
} catch {
completion(.error, error)
}
}
}
func doVerificationThing() async throws -> MJAppStoreStatus {
do {
let result = try await AppTransaction.shared
print("TRIAL: survived AppTransaction.shared")
switch result {
case .unverified(_, _):
print("TRIAL: app transaction UNVERIFIED")
return .free
case .verified(_):
let appTransaction = try result.payloadValue
// hack around the app store sandbox accounts saying we're purchased even though
// we're not really. 2013-08-01 07:00:00 +0000
print("TRIAL: app transaction VERIFIED \(appTransaction.originalPurchaseDate.timeIntervalSinceReferenceDate) -> \(appTransaction.originalPurchaseDate)")
if appTransaction.originalPurchaseDate.timeIntervalSinceReferenceDate == 397033200 {
return .free
} else {
return .purchased
}
}
} catch {
...
I've just released my first on app store. I have monthly renewing subscription on my app, there is no pay wall for few days.
When I look at my app store page after release it shows me app price upfront instead of users download the app. I know I have subscription, but I don't want it to be upfront before install
I know other store that have the same model and users get to download their app. What am I missing?
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.
Topic:
App & System Services
SubTopic:
StoreKit
Tags:
App Store Server Notifications
App Store Server API
App Store Server Library
I have an iOS app with a main target and an app extension. I want the app extension to write data to the SwiftData in App Groups, while the main target reads the data. However, currently, the app extension only has permission to read data, not to write it.Is the issue due to my incorrect configuration or an Apple-imposed restriction?
Hi,
I've been unable to successfully test in the sandbox environment for a StoreKit 2 subscription group and can't seem to find the missing piece.
I am calling the following line of code:
let products = try await Product.products(for: [subscriptionID])
Expected behavior: The product is returned in the products array.
Actual result: The array is empty
I have done the following:
Successfully tested our logic using a storekit configuration file locally in Xcode.
Created the Subscription group in App Store Connect. The subscription product is currently "Waiting for Review", but it is our first so will not be approved without being attached to a distribution build review.
Created a Sandbox user account in App Store Connect -> Users -> Sandbox
Signed into the sandbox user account in Settings -> Developer -> Sandbox Apple Account
Signed the Paid Apps Agreement for our organization
A few debugging notes:
I deleted all apps before installing from Xcode
I've tried both locally and in TestFlight builds
Restarted my device
Verified productID matches the productID in App Store Connect
I'm not sure if I'm missing something, but any help would be appreciated.
Thanks
Topic:
App & System Services
SubTopic:
StoreKit
Tags:
Subscriptions
StoreKit
App Store Connect
In-App Purchase
We have implementend Storekit 2 in our app, for one time purchases and subscriptions, so it is iOS15 and higher only.
Everything works fine, but now we want to add App Store promotions for our IAP's. That doesn't work because the App requires the app to implement SKPaymentTransactionObserver
How to Promote Your In-App Purchases
Make sure your app supports a delegate method in SKPaymentTransactionObserver. You can choose to customize which promoted in-app purchases a user sees on a specific device by implementing SKProductStorePromotionController.
The problem is that this observer is part of the original Storekit API and not of the new one.
What can we do to make this work with the new Storekit 2 API?
Hello,
I am encountering an issue where I receive an App Store Server Notification V2 upon the purchase of a consumable item.
I have configured the App Store Server Notification V2 endpoint to handle notifications related to subscription products.
However, I did not expect to receive notifications for consumable purchases.
The notification includes the following signedPayload decoded into the ResponseBodyV2DecodedPayload object with the following values:
notificationUUID: 3cd6410b-0c89-4247-aba5-20710e79895e
notificationType: null
subtype: null
The transaction information decoded from the ResponseBodyV2DecodedPayload object is as follows:
transactionId: 2000000633622618
webOrderLineItemId: null
productId: heart_2
To debug, I called the Get Notification History API of the App Store Server API, and the mentioned notification for the consumable product purchase is not included in the history. Only notifications related to subscription product purchases are retrieved.
According to the notification type documentation, there is no explanation for cases where both notificationType and subtype are null, nor is there any mention of receiving notifications for consumable purchases. Therefore, I am uncertain how to interpret and handle this notification.
Could you please provide an explanation or guidance on this issue?
Thank you.
References:
https://developer.apple.com/forums/thread/737592
https://developer.apple.com/documentation/appstoreservernotifications/notificationtype
Topic:
App & System Services
SubTopic:
StoreKit
Tags:
In-App Purchase
App Store Server Notifications
App Store Server API
My app has a couple of consumable IAP items. I have tested this extensively and it works in all test scenarios including loads of beta testers using testflight. However, Apple's production reviewer reports that loading of the products hangs in their setup.
This is very frustrating as I have no means of recreating the problem.
My first product was tested ok an all my IAP items are approved for release. However, I did not explicitly assign them to my build. I read somewhere that you need to do that but could not find in App Store Connect after my first product was approved.
Below is the relevant code section. What am I missing?
class DonationManager: NSObject, ObservableObject, SKProductsRequestDelegate, SKPaymentTransactionObserver {
@Published var products: [SKProduct] = [] // This is observed by a view. But apparently that view never gets populated in Apple's production review setup
@Published var isPurchasing: Bool = false
@Published var purchaseMessage: String? = nil
let productIDs: Set<String> = ["Donation_5", "Donation_10", "Donation_25", "Donation_50"]
override init() {
super.init()
SKPaymentQueue.default().add(self)
fetchProducts()
}
deinit {
SKPaymentQueue.default().remove(self)
}
func fetchProducts() {
print("Attempting to fetch products with IDs: \(productIDs)")
let request = SKProductsRequest(productIdentifiers: productIDs)
request.delegate = self
request.start()
}
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
DispatchQueue.main.async {
self.products = response.products.sorted { $0.price.compare($1.price) == .orderedAscending }
print("Successfully fetched \(self.products.count) products.")
if !response.invalidProductIdentifiers.isEmpty {
print("Invalid Product Identifiers: \(response.invalidProductIdentifiers)")
self.purchaseMessage = NSLocalizedString("Some products could not be loaded. Please check App Store Connect.", comment: "")
} else if self.products.isEmpty {
print("No products were fetched. This could indicate a problem with App Store Connect configuration or network.")
self.purchaseMessage = NSLocalizedString("No products available. Please try again later.", comment: "")
}
}
}
...and the view showing the items:
@StateObject private var donationManager = DonationManager()
var body: some View {
VStack(spacing: 24) {
Spacer()
// Donation options -------------------
if donationManager.products.isEmpty {
ProgressView(NSLocalizedString("Loading donation options...", comment: ""))
.foregroundColor(DARK_BROWN)
.italic()
.font(.title3)
.padding(.top, 16)
} else {
ForEach(donationManager.products, id: \.self) { product in
Button(action: {
donationManager.buy(product: product)
}) {
HStack {
Image(systemName: "cup.and.saucer.fill")
.foregroundColor(.pink)
Text("\(product.localizedTitle) \(product.priceLocale.currencySymbol ?? "$")\(product.price)")
}
.buttonStyle()
}
.disabled(donationManager.isPurchasing)
}
}
I'm encountering a crash on app launch. The crash is observed in iOS version 17.6 but not in iOS version 18.5. The only new notable thing I added to this app version was migrate to store kit 2.
Below is the error message from Xcode:
Referenced from: <DCC68597-D1F6-32AA-8635-FB975BD853FE> /private/var/containers/Bundle/Application/6FB3DDE4-6AD5-4778-AD8A-896F99E744E8/callbreak.app/callbreak
Expected in: <A0C8B407-0ABF-3C28-A54C-FE8B1D3FA7AC> /usr/lib/swift/libswift_Concurrency.dylib
Symbol not found: _$sScIsE4next9isolation7ElementQzSgScA_pSgYi_tYa7FailureQzYKFTu
Referenced from: <DCC68597-D1F6-32AA-8635-FB975BD853FE> /private/var/containers/Bundle/Application/6FB3DDE4-6AD5-4778-AD8A-896F99E744E8/callbreak.app/callbreak
Expected in: <A0C8B407-0ABF-3C28-A54C-FE8B1D3FA7AC> /usr/lib/swift/libswift_Concurrency.dylib
dyld config: DYLD_LIBRARY_PATH=/usr/lib/system/introspection DYLD_INSERT_LIBRARIES=/usr/lib/libLogRedirect.dylib:/usr/lib/libBacktraceRecording.dylib:/usr/lib/libMainThreadChecker.dylib:/usr/lib/libRPAC.dylib:/System/Library/PrivateFrameworks/GPUToolsCapture.framework/GPUToolsCapture:/usr/lib/libViewDebuggerSupport.dylib```
and Stack Trace:
```* thread #1, stop reason = signal SIGABRT
* frame #0: 0x00000001c73716f8 dyld`__abort_with_payload + 8
frame #1: 0x00000001c737ce34 dyld`abort_with_payload_wrapper_internal + 104
frame #2: 0x00000001c737ce68 dyld`abort_with_payload + 16
frame #3: 0x00000001c7309dd4 dyld`dyld4::halt(char const*, dyld4::StructuredError const*) + 304
frame #4: 0x00000001c73176a8 dyld`dyld4::prepare(...) + 4088
frame #5: 0x00000001c733bef4 dyld`start + 1748```
Note: My app is a Godot App and uses objc static libraries. I am using swift with bridging headers for interoperability. This issue wasn't observed until my last version in which the migration to storekit2 was the only notable change.
Hey folks!
In one of our apps we're using the FamilyControls framework to manage the screentime for the child. The app requires the Guardian to activate a subscription on his/her device to enable the functionality for the Child on the child device.
We're currently using StoreKit 2 to get notified when there is an active subscription. The issue we're seeing (and our users) is that an activated subscription isn't instantly propagated to the Family members, in this case the device belonging to the child.
Is this a known bug, and are the possible any workarounds? Currently we have to ask our users to "Restore Purchase" or wait minutes/hours for the app to active, which isn't a viable solution. We want it to "just work" :)
Sincerely,
César Pinto Castillo
Ambi Studio
I implemented consumable in-app purchases in an iPhone app using StoreKit's ProductView().
When I tap the payment button in ProductView(), I am taken to the payment screen and once the payment is completed, the desired code appears to be executed, so there doesn't seem to be a problem, but when I tap the payment button in ProductView() again, the desired code is executed without being taken to the payment screen.
So one payment can be used any number of times.
I thought I wrote it exactly according to the reference, but
will it be okay in a production environment?
Is there any code that is necessary?
We are running into exceptions when trying to parse Purchase Date and Original Purchase Date from the base64 encoded receipt.
Expected RFC 3339 format of ASN.1 Field Value is: yyyy-MM-ddTHH:mm:ssZ but we end up getting back 2025-04-22T19.49.03Z.
Started to happen on 3rd Dec 2024.
I have auto-renewable subscriptions, and in Xcode everything works fine. It shows a list of subscriptions where I can make a test purchase.
But when I send it for review, the review team, as well as TestFlight, simply do not have subscriptions. If the problem was in the code, it would not work in the sandbox as I think.
But I think that I configured everything correctly in the subscription settings. The only thing: it shows there for the subscription in appstoreconnect that it is preparing for review, but nothing can be done about it, because it will be solved with the first release of the application.
But I do not know where else to look and what to do. The problem is probably not in the code, but I also redirected the subscription config in appstoreconnect a bunch of times.
I asked help on review team, no way. Tried to google and chat GPT, no ideas where to find a solution.
Hello. I launched my new mobile app Drop Pin Location to promote your business or brand on the go, on January 12, 2023. How can i market and campaign to get more daily users?
Topic:
App & System Services
SubTopic:
StoreKit
Tags:
Subscriptions
App Store Server Notifications
Marketing
I have a macOS app where I am testing the in app subscription purchase using Xcode.
When I trigger the purchase using this code, a dialog is shown in the upper right of my screen, which cannot be moved and just has a "cancel" button. How can I accept the test purchase?
let result = try await product.purchase()
I ran into a problem. When using Storekit1 to purchase an SKU, the user payment was successful, but StoreKit1 did return paymentCancelled to my App. I would like to know under what circumstances this problem may occur? How do I fix it? Thank you