https://developer.apple.com/documentation/appstoreserverapi/send_consumption_information
If the customer provided consent, respond by calling this API and sending the consumption data in the ConsumptionRequest to the App Store. If not, respond by calling this API and setting the customerConsented value to false in the ConsumptionRequest; don't send any other information.
Since our server would be receiving CONSUMPTION_REQUEST server notifications and will be the one calling the Consumption API, how do we know if the user has provided consent? That info doesn't seem to be in the server notification or anywhere else.
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
Created
When testing In-App Purchases in Xcode with a .storekit file, I can delete past purchase transactions, so I can re-test the purchase experience.
I've switched to using a Sandbox tester and made purchases. However, I cannot find how to delete previous purchase transactions made in the sandbox so I can re-run the tests.
Is this possible?
I'm using TestFlight to test an app with payment/subscription functionality. I created sandbox accounts in AppStore Connect accordingly to be able to test the subscriptions. I'm logged in with the sandbox account.
When I try to subscribe in the App the wrong account (this is my actual real AppleID) is used for the subscription although it is recognized that this is just a sandbox subscription.
I tried:
logging off/on into the sandbox account
creating a totally new sandbox account
trying to trigger the payment with no logged in sandbox account
The result is always: in the payment popup it is stated that the purchase account will be my original AppleID and not a sandbox account.
How can I switch the accounts? Is this a bug at Apple's side somehow?
Topic:
App & System Services
SubTopic:
StoreKit
Tags:
Subscriptions
TestFlight
In-App Purchase
StoreKit
On an app that was using the old API for In-App Purchases (StoreKit 1). The app is already published on the App Store. The purchase is non-consumable.
While trying to migrate to StoreKit 2, I'm unable to restore purchases.
Specifically displaying and purchasing products works as expected, but when deleting and reinstalling the app, and then trying to restore purchases I can't do it.
I'm trying to restore them using the new APIs but it doesn't seem to be working.
What I have tried so far:
I'm listening for transaction updates during the whole lifetime of the app, with:
Task.detached {
for await result in Transaction.updates {
if case let .verified(safe) = result {
}
}
}
I have a button that calls this method, but other than prompting to log in again with the Apple ID it doesn't seem to have any effect at all:
try? await AppStore.sync()
This doesn't return any item
for await result in Transaction.currentEntitlements {
if case let .verified(transaction) = result {
}
}
This doesn't return any item
for await result in Transaction.all {
if case let .verified(transaction) = result {
}
}
As mentioned before I'm trying this after purchasing the item and deleting the app. So I'm sure it should be able to restore the purchase.
Am trying this both with a Configuration.storekit file on the simulator, and without it on a real device, in the Sandbox Environment.
Has anyone being able to restore purchases using StoreKit 2?
PD: I already filed a feedback report on Feedback Assistant, but so far the only thing that they have replied is:
Because StoreKit Testing in Xcode is a local environment, and the data is tied to the app, when you delete the app you're also deleting all the transaction data for that app in the Xcode environment. The code snippets provided are correct usage of the API.
So yes, using a Configuration.storekit file won't work on restoring purchases, but if I can't restore them on the Sandbox Environment I'm afraid that this won't work once released, leaving my users totally unable to restore what they have already purchased.
Hello!
I make use of the new iOS 15.4 SKAdNetwork.updatePostbackConversionValue feature:
SKAdNetwork.updatePostbackConversionValue(0) { error in
if let error = error {
print(error.localizedDescription)
}
}
I am not sure why, but I always see this error message in the console:
SKAdNetwork: Error while updating conversion value: Error Domain=SKANErrorDomain Code=10 "(null)"
The operation couldn’t be completed. (SKANErrorDomain error 10.)
Any idea what’s going on there? What does Error Code 10 mean? Couldn't find anything in the documentation about that so far.
I have the NSAdvertisingAttributionReportEndpoint key with domain (https://api2.branch.io/v1/skadnetwork/advertiser_app) in my .plist.
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?
My apps stuck on review stage. Reason of it is
Guideline 2.3.2 - Performance - Accurate Metadata
We noticed that your promotional image to be displayed on the App Store does not sufficiently represent the associated promoted in-app purchase. Specifically, we found the following issue with your promotional image: – Your promotional image is the same as your app’s icon.
The problem is i can't change this image. My subscription is still in 'in review' stage and I don't have option like delete image or change image. I replied to the review explaining that I cannot change it as long as the subscription is under review, but I haven’t received any meaningful reply, except that I need to change promotion image to be eligible for further review(which i cant do because i haven't option to change this image). Has anyone had such a problem before?
We uploaded to App Store Connect a new app version with new subscription groups & items. Everything was approved, and we received the emails from App Store connect, but if we visit our App Store Connect account App, some of these subscription items are still "Waiting for review" for more than 4 days. It has no sense as the email informed us that the new app version and all the items had been approved. The app is online, but some subscription items are not available.
We even uploaded a new app version, it was updated, but the subscription items are still "Waiting for review".
Has anyone faced this problem? How do you solved it? We have contacted App Store Connect but it is pretty difficult to get real assistance, most of the time they reply with template email answers.
Hi, I can't get into "manage" sandbox account. I either get to a screen to put my password in. Here there is no way to click "next" or "login". (I have tried pressing "enter" on my keyboard to no effect). Or I get directly into "Cannot Connect" page. I have tried this two days in a row. I have tried turning it off and on again. I have tried logging out and in.
Device: iPhone 13 pro max, iOS: 16.0.3 (also tried the version before this)
Hello, thank you for your time. I'm using several physical devices to test IAPs in builds from xCode. Some of my test devices are logged into child accounts from my family account.
Child accounts "Ask Permission" from devices logged into adult accounts in the family. when you attempt to make a purchase. I'm hoping to be able to use these devices to test my IAPs but I get the following error after supplying the password for the sandbox account:
Unable to Ask Permission
You can't ask permission because you have signed in with iCloud and iTunes accounts that are not associated with each other.
[Environment: Sandbox]
Is there any way to make this work?
Hi there! Whenever I try to add a new Offer Code for my app's subscription, I get an unknown error. When I get to the last step of the "Create Offer for Codes" flow, I get an error that error reads "An error has occurred. Try again later." I have been getting this same error for over a week now, so any help figuring out how to add new offer codes would be greatly appreciated!
I'm using the iOS simulator with a StoreKit configuration file. I can see that there have been transactions while the app has been closed, but my StoreKit 2 listener is never called with those updates to be able to finish them When I open my app from a cold start.
I've added a listener on application(_:didFinishLaunching:launchOptions:) like this:
func startObservingTransactions() {
task = Task(priority: .background) {
for await result in Transaction.updates {
if case .verified(let transaction) = result {
await transaction.finish()
}
}
}
}
But the Transaction.updates loop never gets called (have added breakpoints to check). It's only ever called when a purchase is made, or subsequent transaction renewals when the app is open. Only then it will get the previously unfinished transactions.
Steps to reproduce:
Create an app with a StoreKit config file (with sped up transactions) to purchase an item
Make a purchase then quit the app
Wait for a bit for more transactions to be made while the app is closed.
Open the app from a cold start and none of the transactions will be finished by the listener in your app. Cancel the subscription via the transaction manager.
Close and open the app from a cold start. The first transaction will be finished by the listener but none of the others will be.
In Apple's docs it says
If your app has unfinished transactions, the listener receives them immediately after the app launches
Why is this not the case?
Hi, thanks for reading my question. I need help with some odd behaviour with product.purchase() not triggering a confirmation dialog after a subscription has expired and trying to purchase it again. Seeing this in iOS 16.2 and 15.7.2 (haven't tried any other versions) on actual devices, not in simulator.
I'm using a sandbox user on the sandbox environment (not using the local store kit config file testing option).
Using a newly created sandbox user, first subscription purchase goes through just fine, dialog box pops up, login with sandbox user, get confirmation of purchase and then Transaction.currentEntitlements has one item as expected. It auto renews for 12 times (each time Transaction.currentEntitlements contains the correct results) and then expires, as expected for sandbox. Transaction.currentEntitlements is then also empty, as expected. All good so far.
Now I want to test purchasing it again...Call product.purchase() again to renew/start a new subscription and nothing happens, no confirm purchase dialog box pops up at all. The purchase function simply exits BUT returns success (as in the following gets called) but in self.updatePurchasedProducts(), Transaction.currentEntitlements is empty.
case let .success(.verified(transaction)):
// Successful purchase
await transaction.finish()
await self.updatePurchasedProducts()
if I instead go to Settings->App Store->Sandbox User-> Manage Subscriptions and renew the subscription there, instead of in my app, then Transaction.currentEntitlements has a new entry and all is good again.
Alternatively, if I create yet another new sandbox user and logout of the old one I was using, I am once again able to purchase from within the app, so .purchase() once again works as normal.
Is there something I am missing about expired subscriptions and trying to purchase them again in the app? Is this a sandbox issue and in production I'll have no problem?
The sandbox user has purchasing enabled in Settings->App Store.
I've also tried calling AppStore.sync() (which is in my "Restore Purchase" button) before calling product.purchase() after the subscription stops renewing, expires and this issue comes up, doesn't resolve it.
Also have a less important question, the initial call to product.purchase(), the one that works as expected, has a bit of a delay before the confirmation dialog pops up, a few seconds, which will probably result in the user clicking the buy button again thinking it didn't work. Is a bit of a delay normal for sandbox? Will it be ok in production? When it fails, and I have to renew in Settings->AppStore->Sandbox user, there's also a bit of a delay after I return to my app, 5-15 or so seconds, before the transaction observer fires and currentEntitlements is checked again, is there a way to reduce this delay?
Thank you!
Colin
@MainActor
class IAPManager: NSObject, ObservableObject {
// removed other functions.....
func purchase(_ product: Product) async throws {
let result = try await product.purchase()
switch result {
case let .success(.verified(transaction)):
// Successful purchase
await transaction.finish()
await self.updatePurchasedProducts()
case let .success(.unverified(_, error)):
break
case .pending:
break
case .userCancelled:
break
@unknown default:
break
}
}
func updatePurchasedProducts() async {
for await result in Transaction.currentEntitlements {
guard case .verified(let transaction) = result else {
continue
}
if transaction.revocationDate == nil {
self.purchasedProductIDs.insert(transaction.productID)
} else {
self.purchasedProductIDs.remove(transaction.productID)
}
}
}
}
Topic:
App & System Services
SubTopic:
StoreKit
Tags:
In-App Purchase
StoreKit
StoreKit Test
Subscriptions
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
The sample code provided in https://developer.apple.com/wwdc21/10114 doesn't appear to call finish() on unverified transactions, and I haven't been able to find any documentation regarding what to do with unfinished transactions. However, Apple has always emphasized the importance of finishing transactions, and since a transaction object is provided even with the unverified state, I'd love some guidance!
Hello, I have 2 subscription group. Each group have different plans and promotional offer. I was set 1 month free promotional offer in all plans. While I subscribe any plan IAP sheet is not showing 1 month free promotional offer. I already used with new sandbox account. How can I get promotional offer in IAP sheet?
Hi,
title says it all: I have Transaction.currentEntitlements returning expired subscriptions (testing both transaction expirationDate & RenewalState).
Environment: local via .storekit file. Subscription duration is shortened for testing. Could it be the issue? The sub duration is normally 1 year.
The documentation says it should only returns active subscription (RenewalState.subscribed) or in grace period (RenewalState.inGracePeriod).
Hello,
For In App Purchases with a renewable subscription, does the originalTransactionId change in the following scenarios?
Case 1:
A user subscribes to a subscription A within a Subscription Group SG1.
The user then cancels it at the end of the month.
Comes back later to subscribe to the same subscription A within the same Subscription Group SG1.
Case 2:
A user subscribes to a subscription A within a Subscription Group SG1.
The user then cancels it at the end of the month.
Comes back later to subscribe to subscription B within the same Subscription Group SG1.
I am looking to move from paid app to fremium without upsetting my existing users. I see WWDC2022 session where new fields introduced in iOS 16 are used to extract original application version user used to purchase the app. While my app supports iOS 14 and above, I am willing to sacrifice iOS 14 and go iOS 15 and above as StoreKit2 requires iOS 15 at the minimum. The code below is however only valid for iOS 16. I need to know what is the best way out for iOS 15 devices if I am using StoreKit2? If it is not possible in StoreKit2, then how much is the work involved in original StoreKit API(because in that case I can handle for iOS 14 as well)?
I've recently published an app, and while developing it, I could always get consistent entitlements from Transaction.currentEntitlements. But now I see some inconsistent behaviour for a subscribed device in the AppStore version. It looks like sometimes the entitlements do not emit value for the subscriptions.
It usually happens on the first couple tries when the device goes offline, or on the first couple tries when the device goes online. But it also happens randomly at other times as well.
Can there be a problem with Transaction.currentEntitlements when the connectivity was just changed?
Of course my implementation may also be broken. I will give you the details of my implementation below.
I have a SubscriptionManager that is observable (irrelevant parts of the entity is omitted):
final class SubscriptionManager: NSObject, ObservableObject {
private let productIds = ["yearly", "monthly"]
private(set) var purchasedProductIDs = Set<String>()
var hasUnlockedPro: Bool {
return !self.purchasedProductIDs.isEmpty
}
@MainActor
func updatePurchasedProducts() async {
var purchasedProductIDs = Set<String>()
for await result in Transaction.currentEntitlements {
guard case .verified(let transaction) = result else {
continue
}
if transaction.revocationDate == nil {
purchasedProductIDs.insert(transaction.productID)
} else {
purchasedProductIDs.remove(transaction.productID)
}
}
// only update if changed to avoid unnecessary published triggers
if purchasedProductIDs != self.purchasedProductIDs {
self.purchasedProductIDs = purchasedProductIDs
}
}
}
And I call the updatePurchasedProducts() when the app first launches in AppDelegate, before returning true on didFinishLaunchingWithOptions as:
Task(priority: .high) {
await DependencyContainer.shared.subscriptionManager.updatePurchasedProducts()
}
You may be wondering maybe the request is not finished yet and I fail to refresh my UI, but it is not the case. Because later on, every time I do something related to a subscribed content, I check the hasUnlockedPro computed property of the subscription manager, which still returns false, meaning the purchasedProductIDs is empty.
You may also be curious about the dependency container approach, but I ensured by testing multiple times that there is only one instance of the SubscriptionManager at all times in the app.
Which makes me think maybe there is something wrong with Transaction.currentEntitlements
I would appreciate any help regarding this problem, or would like to know if anyone else experienced similar problems.