StoreKit

RSS for tag

Support in-app purchases and interactions with the App Store using StoreKit.

StoreKit Documentation

Post

Replies

Boosts

Views

Activity

Please fix offer codes and allow testing in test flight
The current state of testing promotional codes in IOS is not developer friendly in the slightest. I have been trying to implement and test promo codes for a couple months now, while having the store kit integration helps slightly to mimic offer code redemption there is no friendly way of testing offer codes in test flight. I have it implemented with presentCodeRedemptionSheet() it seems the easiest way to test the codes is release my app to production create a 3-day promo which is the minimum amount of days that can be set, then wait 3 days before I can test again in different ways. One of my colleagues who is not a developer also wanted to test this feature and it did not work for her. Unfortunately it was a month long promo code she had redeemed so will have to wait till September to see if this is fixed for her now. I have also must note the fact the code redemption sheet and setting up payments in apple all together is a buggy mess. Starting out I added my card via apple pay thinking this would be enough to go through the redeem code process. Then upon entering my code it would show the dialog to verify with touch ID along with my payment details and even a picture of my card. After verifying, it then kept showing a pop up that I must include payment information which I already had added via apple pay. In the end to fix this I had to remove the payment method restart the device, add the payment method again then restart the device again. Another issue I bumped into is when you press redeem the "redeem offer" button is disabled but nothing happens for a while until it appears to timeout and you have to try again until it eventually works. The final annoyance I experienced was creating the offer code for my subscription and immediately trying to redeem it apple said the offer expired even though i set it to the 31st of August and the date was the 2nd. Only way to fix this was once waited and keep trying banging your head against the wall until it eventually works. In summary, I hope apple have a review of their offer code redemption process and make it more developer friendly and implement a way of testing within test flight whether it use live offer through test flight or include a new section to add test offer codes for subscriptions.
2
3
2k
Aug ’22
App store connect API returns 401 with production url but works with sandbox url
Hi, My app is currently in review (wasn't approved yet). I'm using the Get Transaction History API with a sandbox user transaction ID. I successfully get results when using the sandbox url (https://api.storekit-sandbox.itunes.apple.com/inApps/v1/history/{originalTransactionId}) However, when using the production url (https://api.storekit.itunes.apple.com/inApps/v1/history/{originalTransactionId}) - I'm consistently getting 401 - unauthorized, which according to the doc means something is wrong with my JWT. Should I generate my JWT differently for sandbox vs production? If not, what else could cause this issue? Thanks,
7
1
6.6k
Aug ’22
verifyReceipt in storekit v2
Hi, Currently we are using store kit api and we get the receipt which then backend validate from apple using /verifyReceipt. Now we are planning to move to store kit v2 api. But in this case, we are getting signedPayload instead of receipt. Now this signedPayload cannot be used in the /verifyReceipt. So what is the other way to validate the signedToken from apple and get the data that we get from the /verifyReceipt response. Thanks for the help!
2
2
3.8k
Sep ’22
Dynamic Pricing and in-app purchases
My app is essentially a digital marketplace where users can set their prices and sell digital products to other users. I read the App Review policy and found out that I had to implement in-app purchases if I wanted to sell digital products on iOS. In the process of figuring out how this was going to be implemented, I realized that in-app purchase items have to be created ahead of time. This means dynamic pricing is not possible, so what do now? Is there not a way to programmatically create in-app purchases? If there is not a way to do this, and I cant use my own payment processor, what is the way forward?
1
2
984
Sep ’22
Subscription "Waiting for review" status stuck after been approved
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.
33
11
15k
Oct ’22
Can't manage my sandbox account
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)
64
10
21k
Oct ’22
Testing failed IAP purchase
Does anyone know how to test failed IAP flows? There is documentation here: https://developer.apple.com/documentation/storekit/in-app_purchase/testing_in-app_purchases_with_sandbox/testing_failed_in-app_purchases_and_subscription_renewals which starts with the instructions Sign in to the App Store using a Sandbox Apple ID. Go to Settings > App Store > Sandbox Account > Manage > Account Settings. Disable the Allow Purchases & Renewals setting. This setting is enabled by default. But there is no "Allow Purchases & Renewals" option (or any other option) in the Accounts settings
6
1
1.1k
Oct ’22
What is the significance of an App Store Server Notification that has no signedTransactionInfo?
We have an App Store Server Notification endpoint. Our app offers an in app subscription. Most notifications have all of the expected fields, but in a small number of cases the decoded signedTransactionInfo and signedRenewalInfo fields are empty. I can't see anything about these fields being optional in the documentation, and without the transaction information I can't get the transaction id of the user, so I can't tell how this notification relates to others for the same original transaction id. Are these notifications expected? Should I be handling them in a special way? Or should I just ignore them? For example, a normal transaction will have the following fields: responseBodyV2DecodedPayload (     [notificationType] => DID_RENEW     [notificationUUID] => …     [version] => 2.0     [signedDate] => 1660947328849     [data] => (             [bundleId] => com.playpokpok.playroom             [bundleVersion] => 9             [environment] => Sandbox             [signedTransactionInfo] => JWSTransactionInfo             [signedRenewalInfo] => JWSRenewalInfo         ) ) But one of these unexpected requests will have the following form: responseBodyV2DecodedPayload (     [notificationType] => EXPIRED     [subtype] => VOLUNTARY     [notificationUUID] => …     [version] => 2.0     [signedDate] => 1662661854606     [data] => (             [appAppleId] => 1550204730             [bundleId] => com.playpokpok.playroom             [bundleVersion] => 6             [environment] => Production         ) )
6
0
1.6k
Oct ’22
Cannot handle unfinished consumable in Transaction.currentEntitlements when testing Ask to Buy in Xcode
I am trying to test Ask to Buy for consumable product. When the transaction was approved, I can get verified transaction in Transaction.updates, meaning the process stops at a breakpoint in Transaction.updates. However, when I call Transaction.currentEntitlements after that, I cannot handle transaction as consumable. Am I missing anything? Here is my code. func newTransactionListenerTask() -> Task<Void, Never> { Task(priority: .background) { for await verificationResult in Transaction.updates { guard case .verified(let transaction) = verificationResult,             transaction.revocationDate == nil         else { return }         // Breakpoint stops here await refreshPurchasedProducts()         await transaction.finish()         }    } } func refreshPurchasedProducts() async { for await verificationResult in Transaction.currentEntitlements { guard case .verified(let transaction) = verificationResult else { return } switch transaction.productType { case .consumable: // This code is not called             updateConsumablePurchaseCount(productID: transaction.productID)         default:             break }     } }
3
0
1.4k
Oct ’22
Seeing ASDErrorDomain Code=603 "Request throttled" for SKReceiptRefreshRequest on iOS 16.1 only
I am using local receipt validation and the SKReceiptRefreshRequest API to restore purchases. When my iOS 16.1 users tap "restore purchase", the call fails. Notably, it does not ask the users to log into their iTunes account (it normally does) and my app logs the following error: <SKReceiptRefreshRequest: 0x281b0ad20>: Finished refreshing receipt with error: Error Domain=ASDErrorDomain Code=603 "Request throttled" UserInfo={NSLocalizedFailureReason=Unified receipt is valid and current, NSLocalizedDescription=Request throttled, AMSServerErrorCode=0} These errors started showing up after the release of 16.1 and appear to be limited to that specific version of iOS. The relevant code has not changed in years and I have iOS 15 and iOS 16.0 users who are currently able to restore purchases without issue. Also, I am not able to reproduce the issue in the sandbox but I am able to do so in production. I'm a bit at a loss. Why would my request be "throttled" and, further, why only on iOS 16.1 and only in production? Any thoughts on what could be happening here? Any help is much appreciated. Thank you!
2
3
1.7k
Nov ’22
How to test IAP in the Sandbox environment?
I've been reading through the documents and I feel like each particular doc jumps over the piece of info that I need. It explains how to create a Sandbox Test User and I've done that. I did plenty of IAP work many years ago, but things have changed enough that it's not working as I expect. When I read the docs, I feel like I can't find the missing piece. When I test in a simulator with Xcode, it does my IAP transactions in the Xcode environment. That makes sense. https://developer.apple.com/documentation/storekit/in-app_purchase/testing_in-app_purchases_with_sandbox This page says: To run your app using your Sandbox Apple ID, build and run your app from Xcode. But when I test on a physical device installing directly from Xcode, it also does my IAP transactions in the Xcode environment. I thought this would put me in the Sandbox environment, but it didn't. The initial purchase view controller didn't reference the Sandbox at all and the "You're All Set" alert shows Environment: Xcode. When I put a test build into TestFlight and test using that version, my IAP transactions are happening in production using my real Apple Id (but I'm not actually charged for any transactions). I assumed that testing in TestFlight would give me the Sandbox environment, but it happens in the Production environment. (The purchase view controller doesn't show Sandbox and the "You're All Set" alert doesn't show Sandbox.) So, how do I test in the Sandbox? Every way I try to test either puts me in the Xcode environment or the Production Environment. What am I missing? I've logged out of my real Apple id on my phone and then logged in with the Sandbox User credentials I created in AppStore Connect. But when I tried to test the app, by installing from Xcode it still says I'm in the Xcode test environment. When I create transactions, those transactions show up in the Xcode Transaction Manager. How do I test in the Sandbox environment?
6
4
2.4k
Nov ’22
In-app purchases with crypto
The new guidelines say apps may use in-app purchases to sell NFTs and sell services related to them, such as minting, listing, and the transferring of these tokens. Apps can also allow users to browse NFT collections owned by others so long as the apps do “not include buttons, external links, or other calls to action that direct customers to purchasing mechanisms other than in-app purchase" Is it possible to do in-app purchases using crypto currency for minting? Or minting with crypto currency is not allowed and now they only allow to mint with FIAT currencies?
1
2
598
Nov ’22
Unfinished transactions not being emitted on start of app
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?
14
2
3.2k
Dec ’22
Subscription is still waiting-for-review while app update is deplyoed
Hi. A couple of days ago I've released my new iOS app version update including subscription(in-app-purchase). App is successfully updated and deployed on store but App Store Connect says subscription is still waiting-for-review, and users cannot subscribe our paid features. (API says it's an error; invalid product id) On App Store Connect, it says "A subscription has been returned and is highlighted in the table below." in subscription section. But there's no clue what am I supposed to do next to fix this. I even have received the E-Mail says app update and subscription is successfully reviewed. I am so confused can anyone help me with this?
6
0
1.4k
Dec ’22
Can you preserve "early adopter pricing"?
Hi there, This may be a dumb question but I'm trying to confirm this before we go down this road. Essentially, we are looking to have one premium subscription available to users within our app. A yearly subscription and that's it. Since our app is brand new, we are looking to offer some "early adopter pricing" where early users can sign up for premium and lock in their yearly subscription at a fraction of what we will eventually charge. Will we be able to preserve pricing for select users while also making sure that new users aren't able to access that price? I was reading some articles and saw mention of "unpreserving users subscription pricing" so I figured there must be the functionality to preserve then? Thanks for the help!
2
0
853
Dec ’22
StoreKit2: .purchase() not working after expiry of subscription in app, but renewing in AppStore sandbox does...
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)       }     }   } }
11
8
6.7k
Jan ’23
How to know when user upgrades/downgraded/crossgrades their subscription on the client
Hey, in our app we show post-purchase flow when a user purchases a subscription and its appearance should depend on the type of purchase: upgrade, downgrade or crossgrade. I found a way how to get this type on the backend side but can not figure out how to get this within the app. I see that Transaction has isUpgraded property but it is always false even if I move from a lower service plan to a higher one. So, I have two questions: Is this actually possible to know on the client when the user upgrades, downgrades or crossgrades? If yes, then how? Thanks
4
1
1.6k
Jan ’23