Attempts to purchase an SKProduct or restore all completed transactions via the usual method calls in StoreKit leads to failure in the beta environment with the following error:
Error Domain=SKErrorDomain Code=0 "An unknown error occurred" UserInfo={NSLocalizedDescription=An unknown error occurred, NSUnderlyingError=0x300b10210 {Error Domain=ASDErrorDomain Code=500 "(null)" UserInfo={NSUnderlyingError=0x300b10090 {Error Domain=AMSErrorDomain Code=301 "Invalid Status Code" UserInfo={NSLocalizedDescription=Invalid Status Code, AMSURL=https://sandbox.itunes.apple.com/WebObjects/MZBuy.woa/wa/inAppBuy?REDACTED, AMSStatusCode=500, NSLocalizedFailureReason=The response has an invalid status code}}}}}
We've tried with existing sandbox user accounts, and created fresh ones which also fail in a similar way. Our beta testers report the same thing. Nothing has changed in our IAP code, and this started happening about 24-48 hours ago.
It seems to be a server-side error - please can someone verify on Apple's side?
StoreKit
RSS for tagSupport in-app purchases and interactions with the App Store using StoreKit.
Post
Replies
Boosts
Views
Activity
I've added .storeButton(.visible, for:.policies) to my SubscriptionStoreView, and the buttons do appear, but when I tap on them I get a sheet that just says "Terms of Service Unavailable / Somethng went wrong. Try Again.". (similar for Privacy Policy).
Is this expected in development? Will these start working correctly in production? (and, more importantly, in App Review?)
The docs say that these use the values (i.e. URLs) set in App Store Connect, but that I can override those. This is a new app. Is that wrong, do I need to set the URLs explicitly?
Edited to add:
the console reports: Failed to fetch terms of service and privacy policy: Error Domain=NSURLErrorDomain Code=-1011 "(null)"
We recently reduced the subscription price for new customers in the USA from $9.99 to $4.99. However, existing customers are also seeing the new price of $4.99, but when they attempt to purchase the subscription, they are charged the original price of $9.99.
Actual Behavior:
Existing Customers: See the price as $9.99 and are charged $9.99.
New Customers: See the price as $4.99 and are charged $4.99.
Can anyone assist with resolving this issue?
Thank you!
Hi all.
Our application uses server-side validation of user subscriptions. After purchasing a subscription, the server keeps track of the subscription renewal statuses. But for the second week already, when requesting information on subscriptions, the server receives 403 Forbidden error.
At first we decided that our ip was blocked somewhere and tried to change the ip to a new one. But changing the ip address did not give any results. We keep getting 403 Forbidden error on all requests to check subscriptions from our server.
The request goes to the following address /verifyReceipt This method is deprecated and it is necessary to change the method of verification to a new one, but it can't be done quickly. At the moment, there is no information when verifyReceipt will be disabled. And we need to verify subscriptions.
Maybe someone has encountered a similar problem?
Thanks for the help!
Hello!
If one of our users has previously installed a version of the app that doesn't have the External Purchase entitlement, they'll be presented with this automated disclosure sheet on app launch. This automated sheet cannot be dismissed, if you press "LearnMore", the app closes, if you try to swipe it away, the app closes.
This completely blocks the user from using the app since they can't get past this disclosure sheet.
I'm not allowed to link video recordings here, let me know if there's any way for me to share a recording with steps to reproduce.
Thank you!
I recently had a request from a Product Owner to implement capability like Netflix has to enable users to switch their payment method from App Store Subscription to Credit Card on our website, as per capability that Netflix has in their account management portal.
We tested it today with a colleague who was paying for Netflix through iOS in-app subscription:
In the Netflix account management pages it showed that he was currently paying via In App Subscription
He updated his payment method to Credit Card in their website's account management portal.
Almost immediately after adding his Credit Card in his iOS Subscription Management settings (we could see the the subscription had been set to no longer renew, with an expiry date)
How is this done - I can't see any API in App Store Server API documentation that gives us a way of cancelling / preventing renewal of subscriptions on behalf of a user... But Netflix can clearly do it somehow...
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 {
...
Trying to manage my Sandbox Account. Using the web AppStoreConnect interface, I keep getting and error message "Something went wrong try again later". I have tried during multiple days without success.
Any solution to this as it is impossible to do some app testing?
I have an APP. After User A (Apple ID) subscribes, the user switches to User B (Apple ID) in the App Store. I want to cancel the subscription. If the user switches back to User A (Apple ID) in the App Store, I want to restore the subscription. How can I achieve this? According to the official documentation, it is not recommended to call the restore function frequently.
I'm opening presentCodeRedemptionSheet in my app to redeem offer codes. It is used to open the sheet in the app. For some reason, it opened and started loading in the past few days, then redirected to the Appstore and left the app.
Error Domain=NSURLErrorDomain Code=-1005 "The network connection was lost
Getting this error with: SKPaymentQueue.default().restoreCompletedTransactions()
Implemented: func paymentQueue(_ queue: SKPaymentQueue, restoreCompletedTransactionsFailedWithError error: any Error) {
<#code#>
}
Error returned is the 1005 error I listed above.
The laptop works fine, it is connected to the internet just fine. The problem is connecting to the AppStore Simulator when the project target is intended for the Mac.
I have an iOS project for this product and I do NOT get this problem with the transaction observer when the project target is iOS (iPhone, iPad).
This problem only occurs on the M1 Laptop and the target is MacOS.
Hello,
I am currently implementing server-side handling for in-app subscription payments and using App Store Server Notifications V2 to receive notifications with a TestFlight account.
However, I am not receiving EXPIRED notifications, although I am successfully receiving other notifications such as SUBSCRIBED, DID_RENEW, and DID_CHANGE_RENEWAL_PREF.
Here are some details of my observations:
Until a certain point, I was receiving EXPIRED notifications without any issues, but they stopped coming in after that point.
Each subscription renews every 3 minutes in TestFlight account, and I receive DID_RENEW notifications 7 to 12 times. According to the official documentation, the subscriptions should renew up to 12 times, but I am not receiving exactly 12 DID_RENEW notifications. This inconsistency might be related to the issue.
Other notifications (SUBSCRIBED, DID_RENEW, DID_CHANGE_RENEWAL_PREF) are received without any issues.
Could anyone provide insight into why this might be happening and suggest any alternative methods to handle subscription expirations in case the EXPIRED notifications are not reliable?
Thank you for your assistance.
Relevant Official Documentation
App Store Server Notifications V2
App Store Server Notifications V2_notificationType
Testing in-app purchases with sandbox
Current Server Implementation
Below is the Kotlin Spring Boot server code currently implemented for handling App Store Server Notifications V2:
@RestController
class ProductIosController(
private val productIosService: ProductIosService,
private val appStoreNotificationService: AppStoreNotificationService,
) : BaseController {
@PostMapping("/api/v1/ios-products/app-store-notifications-v2")
fun handleNotification(@RequestBody @Valid notification: AppStoreNotificationRequest): CustomResponse {
appStoreNotificationService.processNotification(notification)
return CustomResponse.ok()
}
}
@Service
class AppStoreNotificationService(
@Qualifier("appStoreClient") private val appStoreServerAPIClient: AppStoreServerAPIClient,
@Qualifier("signedVerifier") private val signedDataVerifier: SignedDataVerifier,
) {
@Transactional
fun processNotification(notification: AppStoreNotificationRequest) {
logger.info("signedPayload: ${notification.signedPayload}")
val decodedPayload = verifyAndDecodeSignedPayload(notification.signedPayload)
val notificationType = decodedPayload.notificationType
val signedTransactionInfo = decodedPayload.data.signedTransactionInfo
val transaction = signedDataVerifier.verifyAndDecodeTransaction(signedTransactionInfo)
val (user, product) = fetchUserAndProduct(transaction)
when (notificationType) {
SUBSCRIBED -> processSubscriptionPurchase(user, product, decodedPayload, transaction)
DID_CHANGE_RENEWAL_PREF -> processSubscriptionGradeChange(user, product, decodedPayload, transaction)
DID_CHANGE_RENEWAL_STATUS -> processRenewalStatusChange(transaction)
OFFER_REDEEMED -> processOfferRedeemed(transaction)
DID_RENEW -> processSubscriptionRenewal(user, product, decodedPayload, transaction)
EXPIRED -> processSubscriptionExpiration(user, product)
DID_FAIL_TO_RENEW -> processFailedRenewal(transaction)
GRACE_PERIOD_EXPIRED -> processSubscriptionGracePeriodExpiration(transaction)
PRICE_INCREASE -> processPriceIncrease(transaction)
REFUND -> processSubscriptionRefund(transaction)
REFUND_DECLINED -> processRefundDeclined(transaction)
CONSUMPTION_REQUEST -> processConsumptionRequest(transaction)
RENEWAL_EXTENDED -> processRenewalExtension(transaction)
REVOKE -> processSubscriptionRevocation(transaction)
TEST -> processTestNotification(transaction)
RENEWAL_EXTENSION -> processRenewalExtension(transaction)
REFUND_REVERSED -> processRefundReversed(transaction)
EXTERNAL_PURCHASE_TOKEN -> processExternalPurchaseToken(transaction)
else -> logger.warn("Unsupported notification type: ${notificationType.value}")
}
}
I just released an app to the App Store, and one of the in-app purchase options is missing. If I reinstall the TestFlight version, the option is available. If I then reinstall the App Store version, it's missing. All the other options are available and working just fine.
This is how I surface them, and I've checked that all the product ids match (if they didn't they wouldn't show up in the TestFlight build).
StoreView(ids: myProductIds)
.productViewStyle(.compact)
.storeButton(.visible, for: .restorePurchases)
Any idea why one of the options wouldn't show up?
I'm developing an application where user can access contents based on In-app purchase subscription.As per the app requirement I want to restrict user from accessing the content when they try to access from a different country.
Example:
Being a user I brought subscription while I was in India by paying lets say 10$ instead of actual 20$ (50% discount for India users).
Lets say I am travelling to other country and in order to use the content user now has to pay the remaining 10$.
As per apple's policy is this allowed? , if yes, then how to achieve this.
Hi,
We previously scheduled a price change (which did NOT affect existing subscribers) however months later, we have now made a decision to apply the increase to all subscribers.
As the price has not increased, I only see the option to preserve and isn't obvious if this has any effect on those grandfathered in the lower price.
Can anyone confirm or must I increase the price again?
Hi, Our app that implemented in-app payment has been reviewed and passed and is currently in operation.
However, there is a problem with the App Store server notification V2.
According to the url https://developer.apple.com/documentation/appstoreservernotifications/responding_to_app_store_server_notifications,
it is written as follows.
"When you set up the endpoints on your server to receive notifications, configure your server to send a response. Use HTTP status codes to indicate whether the App Store server notification post succeeded:
Send HTTP 200, or any HTTP code between 200 and 206, if the post was successful.
Send HTTP 50x or 40x to have the App Store retry the notification, if the post didn't succeed.
The system considers all other HTTP codes an unsuccessful post. Your server isn’t required to return a data value.
If the App Store server doesn’t receive a success response from your server after the initial notification attempt, it retries as follows:
For version 2 notifications, it retries five times, at 1, 12, 24, 48, and 72 hours after the previous attempt."
We are sending an HTTP status code to the Apple server by 200 or 40x or 50x when we receive an Apple notification from the server as per the document.
Nevertheless, Apple Server continues to send us 5 times App Store server notifications for each transaction.
I would appreciate it if you could share how we can do it.
Also, we can provide the implementation code of our server through code-level support.
Thank you for your support.
Hi,
I'm using the App Store Server API for in-app purchase receipt validation. However I received 401 error status code.
My app is ready for submit in App Store Connect, but not yet published the first version.
The receipt is generated using StoreKit test configuration and follow the Sandbox testing instruction. It is generated on a real device using Sandbox Apple account registered in the App Sandbox tester section.
If I go back to use the deprecated verifyReceipt API sandbox endpoint, I get {'status': 21002} error instead.
Is it expected for an App that has not yet published in App Store?
If not, is there any way to test the in-app purchase server-side validation before the App is release?
"Jaxl Phone" a calling application. Users buy recharges to make cellular calls from the application. In this particular case, user has already utilised their recharge by making cellular calls from within the application. They have made about 4-hours of cellular calls from the app.
Now, suddenly, customer started asking for REFUND from Apple. They never reached out to us. In fact, they also asked for REFUNDs for older IAP's and to our surprise, Apple has refunded all 6-IAP that the user has asked refund for.
We have written twice to Apple Developer Support about it
We have also hit consumption request API and used DECLINE as refund preference. But still Apple has gone ahead and issued a refund.
How can we stop this scam and bleeding?
I implemented a store kit in my application, which was working fine until the last three months. Recently, we have encountered an issue where the store kit screen automatically dismisses when attempting to purchase an in-app product using the UPI payment method. This issue specifically occurs with consumable products. Our non-renewable products are working fine with the same code base.
In Apple official example code "Backyard Birds", is this code wrong?
For I've tested this code many times but this part has never been executed!
.onInAppPurchaseCompletion { _, purchaseResult in
guard case .success(let verificationResult) = purchaseResult,
case .success(_) = verificationResult else {
return
}
showingSubscriptionStore = false
}
This modifier decorate code as below
.sheet(isPresented: $showingSubscriptionStore) {
SubscriptionStoreView(groupID: groupID)
}
Is it because the modifier onInAppPurchaseCompletion only works with ProductView ?