StoreKit

RSS for tag

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

StoreKit Documentation

Posts under StoreKit subtopic

Post

Replies

Boosts

Views

Activity

Same same originalTransactionId, productId, but the transactionIds are different.
We are seeing an issue with a potential duplicate charge issue regarding our app. We have received two transactions with the same originalTransactionId but different transactionIds: Order A: TransactionId: [Redacted_TID_1] OriginalTransactionId: [Redacted_OID_A] ProductId: weekly_subscription PurchaseDate: [Redacted_Timestamp_1] SignedDate: [Redacted_Timestamp_2] Price: [Redacted_Price] CAD Order B: TransactionId: [Redacted_TID_2] OriginalTransactionId: [Redacted_OID_A] ProductId: weekly_subscription PurchaseDate: [Redacted_Timestamp_1] SignedDate: [Redacted_Timestamp_3] Price: [Redacted_Price] CAD Both transactions share the same originalTransactionId, productId, and expiresDate, but the transactionIds are different. We wanna confirm: Were customers charged once or twice for this subscription renewal? If only one charge was made, how should we programmatically determine the “valid” transaction among multiple records with the same originalTransactionId to avoid confusion in our server-side receipt validation? We appreciate any clarification so we can handle this correctly in our backend.
1
0
270
Sep ’25
Issues with Integration of Promotional Offers in React Native app
Hi All, We are trying to integrate Promotional Offer in our app, We have a React Native app and are using react-native-iap for handling our in app purchases, as per the documentation we are generating signature in our BE and passing the proper details to the function as well, but for subscription request which have offer applied we are getting the apple pop up properly as well with offer details but when trying to subscribe it gives us SKErrroDomain: 12, for subscription without applying offer the subscription goes through but when we apply the offer we get the above error. Our app is currently in Development Stages and has not been sent for review sam for our subscription plans as well. Please let me know what could be the probable cause for this and help us resolve the issue. This is the code snippet of ours for the front end : export const buySubscription = async (subscriptionData: any) => { try { if (subscriptionData.offer_id) { const response = await getSubscriptionSignature( subscriptionData.productId, subscriptionData.offer_id, ); const offerData = response?.data; const offer = { identifier: offerData?.offer_id, keyIdentifier: offerData?.key_id, nonce: offerData?.nonce, signature: offerData?.signature, timestamp: Number(offerData?.timestamp), }; await requestSubscription({ sku: subscriptionData.productId, withOffer: offer, }); } else { await requestSubscription({ sku: subscriptionData.productId }); } } catch (err) { logger.error('Subscription error: ' + JSON.stringify(err)); throw err; } }; and 
from my python Backend which generates the signature:

def generate_signature(self, product_id: str, offer_id: str) -> dict: """ Generate signature for Apple StoreKit promotional offers. Args: product_id: The product identifier from App Store Connect offer_id: The promotional offer identifier Returns: dict: Contains signature and required metadata Reference: https://developer.apple.com/documentation/storekit/in-app_purchase/original_api_for_in-app_purchase/subscriptions_and_offers/implementing_promotional_offers_in_your_app """ try: # Generate UUID without dashes and use as nonce nonce = str(uuid.uuid4()) timestamp = get_current_time_ms() # milliseconds # Create the payload string in exact order required by Apple payload_components = [ self.bundle_id, # App Bundle ID self.key_id, # Key ID from App Store Connect product_id, # Product identifier offer_id, # Promotional offer identifier nonce, # UUID without dashes str(timestamp) # Current timestamp in milliseconds ] payload_str = "\u2063".join(payload_components) # Use Unicode separator logger.debug(f"Signing payload: {payload_str}") # Create SHA256 hash of the payload digest = hashes.Hash(hashes.SHA256()) digest.update(payload_str.encode('utf-8')) payload_hash = digest.finalize() # Sign the hash using ES256 (ECDSA with SHA-256) signature = self.private_key.sign( data=payload_hash, signature_algorithm=ec.ECDSA(hashes.SHA256()) ) # Encode signature in base64 signature_b64 = base64.b64encode(signature).decode('utf-8') logger.info(f"Generated signature for product {product_id} and offer {offer_id}") return { "key_id": self.key_id, # Changed to match Apple's naming "nonce": nonce, # UUID without dashes "timestamp": timestamp, # As integer "signature": signature_b64, # Base64 encoded signature "product_id": product_id, # Changed to match Apple's naming "offer_id": offer_id # Changed to match Apple's naming } except Exception as e: logger.error(f"Failed to generate signature: {str(e)}") raise HTTPException( status_code=500, detail=f"Failed to generate signature: {str(e)}" )
0
0
84
Apr ’25
Not receiving App Store Server Notifications for failed transactions
We are currently integrating In-App Purchases for our app and have configured App Store Server Notifications (v2) in the Sandbox environment. During testing, we observed the following issue: When a transaction is cancelled, declined, or pending (e.g., Ask to Buy flows or authorization pending), No App Store Server Notification is sent to our webhook endpoint. We only receive webhook events where the status is "purchased". This becomes a critical problem for us because our backend must accurately track transaction states including failed and pending purchases, especially for wallet top-up use cases. Additionally, we tried mocking failed transactions (via Xcode local environment and turning off In-App Purchases from Developer Settings) to simulate a technical failure scenario. Even in these cases, no webhook notification was received when the purchase failed server-side. Is it expected behavior in Sandbox that only successful transactions ("purchased") trigger webhooks? Are failed or pending transactions suppressed in Sandbox intentionally? Will webhook behavior be different in Production (i.e., will we receive webhook notifications for failures there)? Is there any extra configuration or entitlement needed to fully test failure scenarios via webhooks in Sandbox?
0
0
87
Apr ’25
unable to cancel test subscriptions
I tested a subscription with my developer account, it never charges but at the same time I can't cancel it anymore. It does not appear in the list of my official purchsed subscriptions. I tried to login to the sandbox with my developer account, but then when I click on "Manage" I just keep getting the error "Can't connect - retry". I have already tried to logout from all the services, App store, etc. and re-login, nothing worked. Is there anything I can do? Thanks in advance to anyone who can give any tips.
0
0
91
Sep ’25
Show Price Increase Consent
I'm currently still on StoreKit 1, and am testing the paymentQueueShouldShowPriceConsent delegate function. In my local .storekit file, I have a renewable subscription set up with a promotional offer. My test flow is as follows: User subscribes to renewable subscription Let subscription auto-renew once or twice User subscribes to renewable subscription with promotional offer with significant price reduction Promotional offer lapses and price increases to normal Expect paymentQueueShouldShowPriceConsent delegate function to trigger However, #5 never does get invoked, despite re-trying the subscription and promotional offers in various configurations. Manually triggering the Request Price Increase Consent option in the Xcode StoreKit transactions list does invoke the delegate function, but letting the promotional offer lapse does not. My storefront is set to Korea, and my simulator region is set to Korea as well. According to the documentation here and here, consent is required for all price increases in Korea. Is there some way I could check if things are working as intended?
0
0
90
Apr ’25
Sandbox Testing Issue: 'Submit for Review' Button Missing for Subscription IAPSubmit
Hello Developers! I am trying to run a test In-App Purchase (IAP) for a renewable subscription product in the sandbox environment. I have set up everything required for sandbox testing, but it’s unclear whether the subscription product needs to be pre-approved by Apple for testing. If approval is required, I have already added the necessary metadata, but the status still shows "Ready for Submit." Additionally, when I save the page, a "Submit for Review" button briefly appears for a fraction of a second on the subscription page before disappearing. Is this button missing, or is there a known issue with this process? This is my first time running this test, and I would appreciate any pointers or suggestions. Thanks!
1
0
112
Mar ’25
Help testing sandbox purchases in Xcode
I am attempting to test non-consumable sandbox purchases, however I am unable to select the "Approve Transaction" option after initiating a purchase. Leaving the transaction in a permanent pending state. I can view the transaction in the transaction manager by navigating to Debug -> Storekit -> Manage Transactions.. but the only available options to select are "Refund Transaction" or "Delete Transaction". What am I missing about Xcode or my environment that is preventing me from testing this purchase flow? Some more information about my set up. I have a .storekit file synced to AppStore Connect with my product Id. There's a StoreKitTestCertificate.cert saved in the project. I've tried running the build on my phone as Debug, Release and ReleaseForRunning all with the same behavior after making a purchase. My phone is logged into a sandbox test user apple account in the developer iOS settings
1
0
211
Sep ’25
Cannot use proper sandbox account for internal tester on TestFlight
I cannot test IAP using sandbox account that I logged on from settings, it keeps show my regular Apple ID when I try to test IAP from TestFlight This issue frustrate me and bunch of my colleagues, we cannot manage our subscription when sandbox account is default choosing Apple ID I've seen people complaining about this issue a lot Any help on resolving this issue would be really appreaciated
0
0
71
Mar ’25
App Store Server API JWT Authentication Issue
Issue Description I am experiencing persistent 401 Unauthorized errors when attempting to access the App Store Server API using JWT authentication. Despite following Apple's documentation and regenerating keys, I am unable to successfully authenticate. Implementation Details I'm implementing JWT authentication for the App Store Server API to retrieve transaction information from the following endpoint: https://api.storekit.itunes.apple.com/inApps/v1/transactions/{transactionID} My JWT generation code (in PHP/Laravel) follows Apple's documentation: php$kid = '6W6H649LJ4'; $header = [ "alg" => "ES256", "kid" => $kid, "typ" => "JWT" ]; $iss = 'b8d99de7-b43b-4cbb-aada-546ec784e249'; // App Store Connect API Key Issuer ID $bid = 'com.gitiho.learnCourse'; // Bundle ID $payload = [ "iss" => $iss, "iat" => time(), "exp" => time() + 3600, "aud" => "appstoreconnect-v1", "bid" => $bid ]; $pathFileAuthKeyP8 = "AuthKey_6W6H649LJ4.p8"; $contentFileAuthKey = \File::get(base_path($pathFileAuthKeyP8)); $alg = "ES256"; $jwt = \Firebase\JWT\JWT::encode($payload, $contentFileAuthKey, $alg, null, $header); Steps Taken to Troubleshoot Verified that the Issuer ID is correct and in UUID format Confirmed that the Key ID matches the private key filename Regenerated the key with proper App Store Server API permissions Ensured the private key file is properly formatted with correct headers and footers Verified that the JWT is being properly encoded using the ES256 algorithm Confirmed the bundle ID is correct for our application Checked that the API endpoint URL is correct Additional Information This implementation previously worked correctly We started experiencing 401 errors recently without changing our implementation We are using the Firebase JWT library for PHP to encode the JWT Request Could you please help identify what might be causing these authentication failures? Is there any recent change in the authentication requirements or endpoint URLs that might be affecting our integration? Thanks for support me.
0
0
107
Apr ’25
original_transaction_id associated to web_order_line_item_id of auto-renewable subscription changed
Our app offers auto-renewable subscriptions using StoreKit Original API for In-App Purchase and App Store Server Notifications V1. Starting around 2025-03-15, we found some cases where original_transaction_id which was associated to web_order_line_item_id of already purchased subscription had changed in the receipt information of verifyReceipt response or App Store Server Notifications V1. The detailed steps are: Around February 2025, re-purchase from the app the same subscription product which was canceled and expired some time ago, using StoreKit Original API for In-App Purchase Receive the following 2 notifications from App Store Server Notifications V1 almost at the same time INITIAL_BUY DID_CHANGE_RENEWAL_STATUS In both notifications, latest_receipt_info contains the receipt for the re-purchased subscription period with new original_transaction_id and web_order_line_item_id pending_renewal_info contains both new original_transaction_id and original one which was generated at first purchase, and original one has "is_in_billing_retry_period": "1" Starting around 2025-03-15, the following happens When we receive another "DID_CHANGE_RENEWAL_STATUS" notification from App Store Server Notifications V1, original_transaction_id which is associated to web_order_line_item_id of the re-purchased subscription period has changed back to the original one (the one which was generated at first purchase) in latest_receipt_info. When we call verifyReceipt with the receipt obtained from appStoreReceiptURL, the response does not seem to contain new original_transaction_id which was generated at re-purchase We have some questions regarding this original_transaction_id behavior. When a user re-purchase the same subscription product which was canceled and expired some time ago, it seems that new original_transaction_id is generated. Is this an expected behavior? If yes, it seems that, at some point, original_transaction_id which is associated to web_order_line_item_id of the re-purchased subscription changed back to the original original_transaction_id which had been generated at first purchase. Is this an expected behavior? What triggers the original_transaction_id change to the original one? Is it related to some user actions or subscription status change?
3
0
404
Mar ’25
"StoreKit Testing in Xcode" certificate is not trusted on iOS 26
Hello. I have setup a StoreKit testing in the app that was and still is perfectly working on iOS 18. Unfortunately when run on iOS 26 the following error gets printed in the console after calling Transaction.currentEntitlement(for:) method: Failed to verify certificate chain due to client recoverable failure: Error Domain=NSOSStatusErrorDomain Code=-67843 "“StoreKit Testing in Xcode” certificate is not trusted" UserInfo={NSLocalizedDescription=“StoreKit Testing in Xcode” certificate is not trusted, NSUnderlyingError=0x109de7e10 {Error Domain=NSOSStatusErrorDomain Code=-67843 "Certificate 0 “StoreKit Testing in Xcode” has errors: Root is not trusted;" UserInfo={NSLocalizedDescription=Certificate 0 “StoreKit Testing in Xcode” has errors: Root is not trusted;}}} I'm not seeting any StoreKit Testing certificates in phone's certificate trust settings. This test was performed on iOS 26.0 (23A341) with app built in Xcode 16.4. FB20339145
1
0
171
Nov ’25
Server-to-server notification received 2 days after subscription
One of our customers subscribed to a monthly plan on August 16 but the server-to-server notification seems to have been sent on August 18. What could be the reasons for such a delay between the purchase and the server-to-server notification which are usually sent right after the purchase? The receipt sent along with the notification seems to confirm that the receipt has only been created 2 days after the purchase. Here is an extract: { "environment": "Production", "receipt": { "receipt_type": "Production", "bundle_id": "fr.gaumontvideo.gaumontclassique", "application_version": "613", "receipt_creation_date": "2025-08-18 13:00:16 Etc/GMT", "receipt_creation_date_ms": "1755522016000", "receipt_creation_date_pst": "2025-08-18 06:00:16 America/Los_Angeles", "request_date": "2025-08-25 13:08:27 Etc/GMT", "request_date_ms": "1756127307346", "request_date_pst": "2025-08-25 06:08:27 America/Los_Angeles", "original_purchase_date": "2022-05-11 06:14:37 Etc/GMT", "original_purchase_date_ms": "1652249677000", "original_purchase_date_pst": "2022-05-10 23:14:37 America/Los_Angeles", "original_application_version": "265", "in_app": [ { "quantity": "1", "product_id": "fr.gaumontvideo.gaumontclassique.subscription.monthly.apple", "transaction_id": "270002386706194", "original_transaction_id": "270002386706194", "purchase_date": "2025-08-16 08:02:06 Etc/GMT", "purchase_date_ms": "1755331326000", "purchase_date_pst": "2025-08-16 01:02:06 America/Los_Angeles", "original_purchase_date": "2025-08-16 08:02:08 Etc/GMT", "original_purchase_date_ms": "1755331328000", "original_purchase_date_pst": "2025-08-16 01:02:08 America/Los_Angeles", "expires_date": "2025-09-16 08:02:06 Etc/GMT", "expires_date_ms": "1758009726000", "expires_date_pst": "2025-09-16 01:02:06 America/Los_Angeles" } }
1
0
160
Aug ’25
(verifyreceipt) I cannot verify from the server whether the user's iap payment is successful or not
I have three questions about verify receipt I use this api (https://buy.itunes.apple.com/verifyReceipt)to verify receipt is success or not. But since last month, this interface has started to return an error(21002). I see this document (https://developer.apple.com/documentation/appstorereceipts/verifyreceipt) say its Deprecated. My question is, is the error suddenly returned recently because the interface has been deprecated or for some other reason? (I haven't modified my code about this recently) 2. I can not understand this document: (https://developer.apple.com/documentation/appstorereceipts/validating_receipts_on_the_device) Does this mean that in the new version, as long as the app returns a payment success (purchaseDetails.status == PurchaseStatus.purchased), the payment is guaranteed to be successful, and my server does not need to request payment result verification from Apple's server? 3. I try to use this (https://github.com/apple/app-store-server-library-java) to get TransactionInfo, but I dont konw to get Transaction status to know is success or not. my java server code : AppStoreServerAPIClient client = new AppStoreServerAPIClient(encodedKey, keyId, issuerId, bundleId, environment); TransactionInfoResponse response = client.getTransactionInfo(transactionId); (bug i can note get transaction status, how do i konw this Transaction is success or not)
0
0
78
Aug ’25
ExternalPurchase.presentNoticeSheet returns only cancelled in App Store version
Hello, Our app has been released in Korea with an external payment feature. The function that must display the required modal for external payments is as follows: let result = try await ExternalPurchase.presentNoticeSheet() guard result != .cancelled else { return } However, while testing in the development environment, the API returns a result of continuedWithExternalPurchaseToken(token: String), but in the version distributed through the App Store, it returns cancelled. We would like to know how we can receive the continuedWithExternalPurchaseToken result in the App Store version. Thank you for your guidance. If anyone here has experienced a similar issue or found a solution, I would greatly appreciate your insights as well.
1
0
55
Sep ’25
About review app and subscription
When submitting an app for review, will any unreviewed auto-renewing subscriptions within the app be reviewed simultaneously? I own an app that has passed review and offers an auto-renewing subscription A within the app that has also passed review. To test a new service, I plan to create a new auto-renewing subscription B, which I do not intend to submit for review. After creating Subscription B, I plan to submit the app for review as part of an app update. In that case, is there a possibility that Subscription B will also be reviewed?
1
0
130
Aug ’25
Sandbox Url Not Receiving App Store Server Notifications
I have an Expo React Native application and I am using react-native-iap library. I have setup the URL for sandbox and production url to receive notifications when a something happens regarding subscriptions. I am not able to receive those notifications when I simulate the purchase on the Simulator using Xcode. I then have used the node library app-store-server-library to mock a test notification and I am receiving the test notification when I call requestTestNotification method. below is the react-native code I am using: import {useEffect, useState} from "react"; import { initConnection, Sku, Subscription, useIAP, SubscriptionIOS, requestSubscription, PurchaseError, clearTransactionIOS } from "react-native-iap"; import styles from "@/screens/IAP/IAPStyles"; import CustomText from "@/components/CustomText"; import Heading from "@/components/Heading"; import subscriptionsProducts from "@/utilities/products"; function IAPScreen() { const [isPurchasing, setIsPurchasing] = useState<boolean>(false); const [loading, setLoading] = useState<boolean>(false); const { subscriptions, currentPurchase, finishTransaction, getSubscriptions } = useIAP(); function RenderProduct({ item } : { item: Subscription }) { const iosSubscription: SubscriptionIOS = item as SubscriptionIOS; return( <View style={styles.productCard}> <CustomText customStyles={styles.productTitle} text={iosSubscription.title} size={"medium"} /> <CustomText customStyles={styles.productDescription} text={iosSubscription.description} size={"small"} /> <CustomText customStyles={styles.productPrice} text={iosSubscription.localizedPrice} size={"small"} /> <Button title="Purchase" disabled={isPurchasing} onPress={ () => HandlePurchase(iosSubscription.productId) } /> </View> ); } async function HandlePurchase(sku: Sku) { try { setIsPurchasing(true); await requestSubscription({ sku, andDangerouslyFinishTransactionAutomaticallyIOS: false }); } catch (error: any) { Alert.alert("Error", "Failed to purchase: " + error.message); } finally { setIsPurchasing(false); } } useEffect(() => { setLoading(true); console.log(`[${new Date().toISOString()}] Initializing IAP connection...`); const setupIAP = async () => { try { const result = await initConnection(); console.log(`[${new Date().toISOString()}] IAP connection initialized:`, result); await clearTransactionIOS(); await getSubscriptions({ skus: subscriptionsProducts }); } catch (error: any) { Alert.alert("Error", "Failed to load products: " + error.message); } finally { setLoading(false); } }; setupIAP() .finally(() => setLoading(false)); }, []); useEffect(() => { const checkCurrentPurchase = async () => { try { if(currentPurchase?.productId) { console.log("Current purchase: ", currentPurchase); console.log("Transaction Id: ", currentPurchase.transactionId); await finishTransaction({ purchase: currentPurchase, isConsumable: false, }); } } catch (error) { if(error instanceof PurchaseError) { console.log("Purchase error: ", error); } else { Alert.alert("Error", "Failed to finish transaction: " + error); } } } if(currentPurchase) { console.log("Finishing current purchase."); checkCurrentPurchase() .catch(error => Alert.alert("Error", "Failed to finish transaction: " + error.message)); } }, [currentPurchase, finishTransaction]); return( <View style={styles.mainContainer}> <Heading text={"Packages & Subscriptions"} type={"h2"} customStyles={styles.header} /> { loading ? <ActivityIndicator size="large" /> : subscriptions.length > 0 ? ( <> <FlatList data={subscriptions} renderItem={RenderProduct} keyExtractor={(item) => item.productId} /> </> ) : ( <CustomText customStyles={styles.productDescription} text={"No available products."} size={"small"} /> ) } </View> ); } export default IAPScreen; I am using a store kit file where I just edited the scheme of application to use that store kit file. I would be really thankful If you can help me in this matter.
1
0
181
May ’25
Same same originalTransactionId, productId, but the transactionIds are different.
We are seeing an issue with a potential duplicate charge issue regarding our app. We have received two transactions with the same originalTransactionId but different transactionIds: Order A: TransactionId: [Redacted_TID_1] OriginalTransactionId: [Redacted_OID_A] ProductId: weekly_subscription PurchaseDate: [Redacted_Timestamp_1] SignedDate: [Redacted_Timestamp_2] Price: [Redacted_Price] CAD Order B: TransactionId: [Redacted_TID_2] OriginalTransactionId: [Redacted_OID_A] ProductId: weekly_subscription PurchaseDate: [Redacted_Timestamp_1] SignedDate: [Redacted_Timestamp_3] Price: [Redacted_Price] CAD Both transactions share the same originalTransactionId, productId, and expiresDate, but the transactionIds are different. We wanna confirm: Were customers charged once or twice for this subscription renewal? If only one charge was made, how should we programmatically determine the “valid” transaction among multiple records with the same originalTransactionId to avoid confusion in our server-side receipt validation? We appreciate any clarification so we can handle this correctly in our backend.
Replies
1
Boosts
0
Views
270
Activity
Sep ’25
Issues with Integration of Promotional Offers in React Native app
Hi All, We are trying to integrate Promotional Offer in our app, We have a React Native app and are using react-native-iap for handling our in app purchases, as per the documentation we are generating signature in our BE and passing the proper details to the function as well, but for subscription request which have offer applied we are getting the apple pop up properly as well with offer details but when trying to subscribe it gives us SKErrroDomain: 12, for subscription without applying offer the subscription goes through but when we apply the offer we get the above error. Our app is currently in Development Stages and has not been sent for review sam for our subscription plans as well. Please let me know what could be the probable cause for this and help us resolve the issue. This is the code snippet of ours for the front end : export const buySubscription = async (subscriptionData: any) => { try { if (subscriptionData.offer_id) { const response = await getSubscriptionSignature( subscriptionData.productId, subscriptionData.offer_id, ); const offerData = response?.data; const offer = { identifier: offerData?.offer_id, keyIdentifier: offerData?.key_id, nonce: offerData?.nonce, signature: offerData?.signature, timestamp: Number(offerData?.timestamp), }; await requestSubscription({ sku: subscriptionData.productId, withOffer: offer, }); } else { await requestSubscription({ sku: subscriptionData.productId }); } } catch (err) { logger.error('Subscription error: ' + JSON.stringify(err)); throw err; } }; and 
from my python Backend which generates the signature:

def generate_signature(self, product_id: str, offer_id: str) -> dict: """ Generate signature for Apple StoreKit promotional offers. Args: product_id: The product identifier from App Store Connect offer_id: The promotional offer identifier Returns: dict: Contains signature and required metadata Reference: https://developer.apple.com/documentation/storekit/in-app_purchase/original_api_for_in-app_purchase/subscriptions_and_offers/implementing_promotional_offers_in_your_app """ try: # Generate UUID without dashes and use as nonce nonce = str(uuid.uuid4()) timestamp = get_current_time_ms() # milliseconds # Create the payload string in exact order required by Apple payload_components = [ self.bundle_id, # App Bundle ID self.key_id, # Key ID from App Store Connect product_id, # Product identifier offer_id, # Promotional offer identifier nonce, # UUID without dashes str(timestamp) # Current timestamp in milliseconds ] payload_str = "\u2063".join(payload_components) # Use Unicode separator logger.debug(f"Signing payload: {payload_str}") # Create SHA256 hash of the payload digest = hashes.Hash(hashes.SHA256()) digest.update(payload_str.encode('utf-8')) payload_hash = digest.finalize() # Sign the hash using ES256 (ECDSA with SHA-256) signature = self.private_key.sign( data=payload_hash, signature_algorithm=ec.ECDSA(hashes.SHA256()) ) # Encode signature in base64 signature_b64 = base64.b64encode(signature).decode('utf-8') logger.info(f"Generated signature for product {product_id} and offer {offer_id}") return { "key_id": self.key_id, # Changed to match Apple's naming "nonce": nonce, # UUID without dashes "timestamp": timestamp, # As integer "signature": signature_b64, # Base64 encoded signature "product_id": product_id, # Changed to match Apple's naming "offer_id": offer_id # Changed to match Apple's naming } except Exception as e: logger.error(f"Failed to generate signature: {str(e)}") raise HTTPException( status_code=500, detail=f"Failed to generate signature: {str(e)}" )
Replies
0
Boosts
0
Views
84
Activity
Apr ’25
StoreKit2 and Subscription Receipts Questions
Sorry but I'm not good at English. Is the originalTransactionId received for the same subscription by the same user the same in Store Kit v1 and Store Kit 2? Also, will the originalTransactionId be the same even if the subscription price is changed?
Replies
1
Boosts
0
Views
124
Activity
Mar ’25
Not receiving App Store Server Notifications for failed transactions
We are currently integrating In-App Purchases for our app and have configured App Store Server Notifications (v2) in the Sandbox environment. During testing, we observed the following issue: When a transaction is cancelled, declined, or pending (e.g., Ask to Buy flows or authorization pending), No App Store Server Notification is sent to our webhook endpoint. We only receive webhook events where the status is "purchased". This becomes a critical problem for us because our backend must accurately track transaction states including failed and pending purchases, especially for wallet top-up use cases. Additionally, we tried mocking failed transactions (via Xcode local environment and turning off In-App Purchases from Developer Settings) to simulate a technical failure scenario. Even in these cases, no webhook notification was received when the purchase failed server-side. Is it expected behavior in Sandbox that only successful transactions ("purchased") trigger webhooks? Are failed or pending transactions suppressed in Sandbox intentionally? Will webhook behavior be different in Production (i.e., will we receive webhook notifications for failures there)? Is there any extra configuration or entitlement needed to fully test failure scenarios via webhooks in Sandbox?
Replies
0
Boosts
0
Views
87
Activity
Apr ’25
unable to cancel test subscriptions
I tested a subscription with my developer account, it never charges but at the same time I can't cancel it anymore. It does not appear in the list of my official purchsed subscriptions. I tried to login to the sandbox with my developer account, but then when I click on "Manage" I just keep getting the error "Can't connect - retry". I have already tried to logout from all the services, App store, etc. and re-login, nothing worked. Is there anything I can do? Thanks in advance to anyone who can give any tips.
Replies
0
Boosts
0
Views
91
Activity
Sep ’25
Show Price Increase Consent
I'm currently still on StoreKit 1, and am testing the paymentQueueShouldShowPriceConsent delegate function. In my local .storekit file, I have a renewable subscription set up with a promotional offer. My test flow is as follows: User subscribes to renewable subscription Let subscription auto-renew once or twice User subscribes to renewable subscription with promotional offer with significant price reduction Promotional offer lapses and price increases to normal Expect paymentQueueShouldShowPriceConsent delegate function to trigger However, #5 never does get invoked, despite re-trying the subscription and promotional offers in various configurations. Manually triggering the Request Price Increase Consent option in the Xcode StoreKit transactions list does invoke the delegate function, but letting the promotional offer lapse does not. My storefront is set to Korea, and my simulator region is set to Korea as well. According to the documentation here and here, consent is required for all price increases in Korea. Is there some way I could check if things are working as intended?
Replies
0
Boosts
0
Views
90
Activity
Apr ’25
Sandbox Testing Issue: 'Submit for Review' Button Missing for Subscription IAPSubmit
Hello Developers! I am trying to run a test In-App Purchase (IAP) for a renewable subscription product in the sandbox environment. I have set up everything required for sandbox testing, but it’s unclear whether the subscription product needs to be pre-approved by Apple for testing. If approval is required, I have already added the necessary metadata, but the status still shows "Ready for Submit." Additionally, when I save the page, a "Submit for Review" button briefly appears for a fraction of a second on the subscription page before disappearing. Is this button missing, or is there a known issue with this process? This is my first time running this test, and I would appreciate any pointers or suggestions. Thanks!
Replies
1
Boosts
0
Views
112
Activity
Mar ’25
Display frequency of the winback offer sheet
Could you tell me about the specifications of the winback offer? If a user is eligible for the winback offer, will the winback offer sheet be displayed every time the app is launched? Or will the OS adjust the display frequency in some way?
Replies
1
Boosts
0
Views
69
Activity
Aug ’25
Help testing sandbox purchases in Xcode
I am attempting to test non-consumable sandbox purchases, however I am unable to select the "Approve Transaction" option after initiating a purchase. Leaving the transaction in a permanent pending state. I can view the transaction in the transaction manager by navigating to Debug -> Storekit -> Manage Transactions.. but the only available options to select are "Refund Transaction" or "Delete Transaction". What am I missing about Xcode or my environment that is preventing me from testing this purchase flow? Some more information about my set up. I have a .storekit file synced to AppStore Connect with my product Id. There's a StoreKitTestCertificate.cert saved in the project. I've tried running the build on my phone as Debug, Release and ReleaseForRunning all with the same behavior after making a purchase. My phone is logged into a sandbox test user apple account in the developer iOS settings
Replies
1
Boosts
0
Views
211
Activity
Sep ’25
Cannot use proper sandbox account for internal tester on TestFlight
I cannot test IAP using sandbox account that I logged on from settings, it keeps show my regular Apple ID when I try to test IAP from TestFlight This issue frustrate me and bunch of my colleagues, we cannot manage our subscription when sandbox account is default choosing Apple ID I've seen people complaining about this issue a lot Any help on resolving this issue would be really appreaciated
Replies
0
Boosts
0
Views
71
Activity
Mar ’25
App Store Server API JWT Authentication Issue
Issue Description I am experiencing persistent 401 Unauthorized errors when attempting to access the App Store Server API using JWT authentication. Despite following Apple's documentation and regenerating keys, I am unable to successfully authenticate. Implementation Details I'm implementing JWT authentication for the App Store Server API to retrieve transaction information from the following endpoint: https://api.storekit.itunes.apple.com/inApps/v1/transactions/{transactionID} My JWT generation code (in PHP/Laravel) follows Apple's documentation: php$kid = '6W6H649LJ4'; $header = [ "alg" => "ES256", "kid" => $kid, "typ" => "JWT" ]; $iss = 'b8d99de7-b43b-4cbb-aada-546ec784e249'; // App Store Connect API Key Issuer ID $bid = 'com.gitiho.learnCourse'; // Bundle ID $payload = [ "iss" => $iss, "iat" => time(), "exp" => time() + 3600, "aud" => "appstoreconnect-v1", "bid" => $bid ]; $pathFileAuthKeyP8 = "AuthKey_6W6H649LJ4.p8"; $contentFileAuthKey = \File::get(base_path($pathFileAuthKeyP8)); $alg = "ES256"; $jwt = \Firebase\JWT\JWT::encode($payload, $contentFileAuthKey, $alg, null, $header); Steps Taken to Troubleshoot Verified that the Issuer ID is correct and in UUID format Confirmed that the Key ID matches the private key filename Regenerated the key with proper App Store Server API permissions Ensured the private key file is properly formatted with correct headers and footers Verified that the JWT is being properly encoded using the ES256 algorithm Confirmed the bundle ID is correct for our application Checked that the API endpoint URL is correct Additional Information This implementation previously worked correctly We started experiencing 401 errors recently without changing our implementation We are using the Firebase JWT library for PHP to encode the JWT Request Could you please help identify what might be causing these authentication failures? Is there any recent change in the authentication requirements or endpoint URLs that might be affecting our integration? Thanks for support me.
Replies
0
Boosts
0
Views
107
Activity
Apr ’25
original_transaction_id associated to web_order_line_item_id of auto-renewable subscription changed
Our app offers auto-renewable subscriptions using StoreKit Original API for In-App Purchase and App Store Server Notifications V1. Starting around 2025-03-15, we found some cases where original_transaction_id which was associated to web_order_line_item_id of already purchased subscription had changed in the receipt information of verifyReceipt response or App Store Server Notifications V1. The detailed steps are: Around February 2025, re-purchase from the app the same subscription product which was canceled and expired some time ago, using StoreKit Original API for In-App Purchase Receive the following 2 notifications from App Store Server Notifications V1 almost at the same time INITIAL_BUY DID_CHANGE_RENEWAL_STATUS In both notifications, latest_receipt_info contains the receipt for the re-purchased subscription period with new original_transaction_id and web_order_line_item_id pending_renewal_info contains both new original_transaction_id and original one which was generated at first purchase, and original one has "is_in_billing_retry_period": "1" Starting around 2025-03-15, the following happens When we receive another "DID_CHANGE_RENEWAL_STATUS" notification from App Store Server Notifications V1, original_transaction_id which is associated to web_order_line_item_id of the re-purchased subscription period has changed back to the original one (the one which was generated at first purchase) in latest_receipt_info. When we call verifyReceipt with the receipt obtained from appStoreReceiptURL, the response does not seem to contain new original_transaction_id which was generated at re-purchase We have some questions regarding this original_transaction_id behavior. When a user re-purchase the same subscription product which was canceled and expired some time ago, it seems that new original_transaction_id is generated. Is this an expected behavior? If yes, it seems that, at some point, original_transaction_id which is associated to web_order_line_item_id of the re-purchased subscription changed back to the original original_transaction_id which had been generated at first purchase. Is this an expected behavior? What triggers the original_transaction_id change to the original one? Is it related to some user actions or subscription status change?
Replies
3
Boosts
0
Views
404
Activity
Mar ’25
"StoreKit Testing in Xcode" certificate is not trusted on iOS 26
Hello. I have setup a StoreKit testing in the app that was and still is perfectly working on iOS 18. Unfortunately when run on iOS 26 the following error gets printed in the console after calling Transaction.currentEntitlement(for:) method: Failed to verify certificate chain due to client recoverable failure: Error Domain=NSOSStatusErrorDomain Code=-67843 "“StoreKit Testing in Xcode” certificate is not trusted" UserInfo={NSLocalizedDescription=“StoreKit Testing in Xcode” certificate is not trusted, NSUnderlyingError=0x109de7e10 {Error Domain=NSOSStatusErrorDomain Code=-67843 "Certificate 0 “StoreKit Testing in Xcode” has errors: Root is not trusted;" UserInfo={NSLocalizedDescription=Certificate 0 “StoreKit Testing in Xcode” has errors: Root is not trusted;}}} I'm not seeting any StoreKit Testing certificates in phone's certificate trust settings. This test was performed on iOS 26.0 (23A341) with app built in Xcode 16.4. FB20339145
Replies
1
Boosts
0
Views
171
Activity
Nov ’25
In the US, are we required to use IAP in addition to web payments?
In my understanding, with the latest court ruling in the US, iOS apps may decide to support web-based payments for subscriptions and in-app purchases. However, are we allowed to exclusively support web-based payments and not implement StoreKit at all?
Replies
0
Boosts
0
Views
99
Activity
May ’25
Server-to-server notification received 2 days after subscription
One of our customers subscribed to a monthly plan on August 16 but the server-to-server notification seems to have been sent on August 18. What could be the reasons for such a delay between the purchase and the server-to-server notification which are usually sent right after the purchase? The receipt sent along with the notification seems to confirm that the receipt has only been created 2 days after the purchase. Here is an extract: { "environment": "Production", "receipt": { "receipt_type": "Production", "bundle_id": "fr.gaumontvideo.gaumontclassique", "application_version": "613", "receipt_creation_date": "2025-08-18 13:00:16 Etc/GMT", "receipt_creation_date_ms": "1755522016000", "receipt_creation_date_pst": "2025-08-18 06:00:16 America/Los_Angeles", "request_date": "2025-08-25 13:08:27 Etc/GMT", "request_date_ms": "1756127307346", "request_date_pst": "2025-08-25 06:08:27 America/Los_Angeles", "original_purchase_date": "2022-05-11 06:14:37 Etc/GMT", "original_purchase_date_ms": "1652249677000", "original_purchase_date_pst": "2022-05-10 23:14:37 America/Los_Angeles", "original_application_version": "265", "in_app": [ { "quantity": "1", "product_id": "fr.gaumontvideo.gaumontclassique.subscription.monthly.apple", "transaction_id": "270002386706194", "original_transaction_id": "270002386706194", "purchase_date": "2025-08-16 08:02:06 Etc/GMT", "purchase_date_ms": "1755331326000", "purchase_date_pst": "2025-08-16 01:02:06 America/Los_Angeles", "original_purchase_date": "2025-08-16 08:02:08 Etc/GMT", "original_purchase_date_ms": "1755331328000", "original_purchase_date_pst": "2025-08-16 01:02:08 America/Los_Angeles", "expires_date": "2025-09-16 08:02:06 Etc/GMT", "expires_date_ms": "1758009726000", "expires_date_pst": "2025-09-16 01:02:06 America/Los_Angeles" } }
Replies
1
Boosts
0
Views
160
Activity
Aug ’25
(verifyreceipt) I cannot verify from the server whether the user's iap payment is successful or not
I have three questions about verify receipt I use this api (https://buy.itunes.apple.com/verifyReceipt)to verify receipt is success or not. But since last month, this interface has started to return an error(21002). I see this document (https://developer.apple.com/documentation/appstorereceipts/verifyreceipt) say its Deprecated. My question is, is the error suddenly returned recently because the interface has been deprecated or for some other reason? (I haven't modified my code about this recently) 2. I can not understand this document: (https://developer.apple.com/documentation/appstorereceipts/validating_receipts_on_the_device) Does this mean that in the new version, as long as the app returns a payment success (purchaseDetails.status == PurchaseStatus.purchased), the payment is guaranteed to be successful, and my server does not need to request payment result verification from Apple's server? 3. I try to use this (https://github.com/apple/app-store-server-library-java) to get TransactionInfo, but I dont konw to get Transaction status to know is success or not. my java server code : AppStoreServerAPIClient client = new AppStoreServerAPIClient(encodedKey, keyId, issuerId, bundleId, environment); TransactionInfoResponse response = client.getTransactionInfo(transactionId); (bug i can note get transaction status, how do i konw this Transaction is success or not)
Replies
0
Boosts
0
Views
78
Activity
Aug ’25
ExternalPurchase.presentNoticeSheet returns only cancelled in App Store version
Hello, Our app has been released in Korea with an external payment feature. The function that must display the required modal for external payments is as follows: let result = try await ExternalPurchase.presentNoticeSheet() guard result != .cancelled else { return } However, while testing in the development environment, the API returns a result of continuedWithExternalPurchaseToken(token: String), but in the version distributed through the App Store, it returns cancelled. We would like to know how we can receive the continuedWithExternalPurchaseToken result in the App Store version. Thank you for your guidance. If anyone here has experienced a similar issue or found a solution, I would greatly appreciate your insights as well.
Replies
1
Boosts
0
Views
55
Activity
Sep ’25
Integrate the Subscriptions in my app
Hi! I’m new in programming apps for Apple Store and I’m creating my first app. I already send my for review but I get an answer of problems with the subs flow. If there’s anyone who can help me fix this problem and implement my subscriptions in my app and test it out I would be thankful, I want the flow work like in the image!
Replies
0
Boosts
0
Views
88
Activity
May ’25
About review app and subscription
When submitting an app for review, will any unreviewed auto-renewing subscriptions within the app be reviewed simultaneously? I own an app that has passed review and offers an auto-renewing subscription A within the app that has also passed review. To test a new service, I plan to create a new auto-renewing subscription B, which I do not intend to submit for review. After creating Subscription B, I plan to submit the app for review as part of an app update. In that case, is there a possibility that Subscription B will also be reviewed?
Replies
1
Boosts
0
Views
130
Activity
Aug ’25
Sandbox Url Not Receiving App Store Server Notifications
I have an Expo React Native application and I am using react-native-iap library. I have setup the URL for sandbox and production url to receive notifications when a something happens regarding subscriptions. I am not able to receive those notifications when I simulate the purchase on the Simulator using Xcode. I then have used the node library app-store-server-library to mock a test notification and I am receiving the test notification when I call requestTestNotification method. below is the react-native code I am using: import {useEffect, useState} from "react"; import { initConnection, Sku, Subscription, useIAP, SubscriptionIOS, requestSubscription, PurchaseError, clearTransactionIOS } from "react-native-iap"; import styles from "@/screens/IAP/IAPStyles"; import CustomText from "@/components/CustomText"; import Heading from "@/components/Heading"; import subscriptionsProducts from "@/utilities/products"; function IAPScreen() { const [isPurchasing, setIsPurchasing] = useState<boolean>(false); const [loading, setLoading] = useState<boolean>(false); const { subscriptions, currentPurchase, finishTransaction, getSubscriptions } = useIAP(); function RenderProduct({ item } : { item: Subscription }) { const iosSubscription: SubscriptionIOS = item as SubscriptionIOS; return( <View style={styles.productCard}> <CustomText customStyles={styles.productTitle} text={iosSubscription.title} size={"medium"} /> <CustomText customStyles={styles.productDescription} text={iosSubscription.description} size={"small"} /> <CustomText customStyles={styles.productPrice} text={iosSubscription.localizedPrice} size={"small"} /> <Button title="Purchase" disabled={isPurchasing} onPress={ () => HandlePurchase(iosSubscription.productId) } /> </View> ); } async function HandlePurchase(sku: Sku) { try { setIsPurchasing(true); await requestSubscription({ sku, andDangerouslyFinishTransactionAutomaticallyIOS: false }); } catch (error: any) { Alert.alert("Error", "Failed to purchase: " + error.message); } finally { setIsPurchasing(false); } } useEffect(() => { setLoading(true); console.log(`[${new Date().toISOString()}] Initializing IAP connection...`); const setupIAP = async () => { try { const result = await initConnection(); console.log(`[${new Date().toISOString()}] IAP connection initialized:`, result); await clearTransactionIOS(); await getSubscriptions({ skus: subscriptionsProducts }); } catch (error: any) { Alert.alert("Error", "Failed to load products: " + error.message); } finally { setLoading(false); } }; setupIAP() .finally(() => setLoading(false)); }, []); useEffect(() => { const checkCurrentPurchase = async () => { try { if(currentPurchase?.productId) { console.log("Current purchase: ", currentPurchase); console.log("Transaction Id: ", currentPurchase.transactionId); await finishTransaction({ purchase: currentPurchase, isConsumable: false, }); } } catch (error) { if(error instanceof PurchaseError) { console.log("Purchase error: ", error); } else { Alert.alert("Error", "Failed to finish transaction: " + error); } } } if(currentPurchase) { console.log("Finishing current purchase."); checkCurrentPurchase() .catch(error => Alert.alert("Error", "Failed to finish transaction: " + error.message)); } }, [currentPurchase, finishTransaction]); return( <View style={styles.mainContainer}> <Heading text={"Packages & Subscriptions"} type={"h2"} customStyles={styles.header} /> { loading ? <ActivityIndicator size="large" /> : subscriptions.length > 0 ? ( <> <FlatList data={subscriptions} renderItem={RenderProduct} keyExtractor={(item) => item.productId} /> </> ) : ( <CustomText customStyles={styles.productDescription} text={"No available products."} size={"small"} /> ) } </View> ); } export default IAPScreen; I am using a store kit file where I just edited the scheme of application to use that store kit file. I would be really thankful If you can help me in this matter.
Replies
1
Boosts
0
Views
181
Activity
May ’25