App Store Server API

RSS for tag

Call this REST API from your server to request and provide information about your customers' in-app purchases.

Posts under App Store Server API tag

90 Posts
Sort by:

Post

Replies

Boosts

Views

Activity

"purchaseDate" of the Reciepts
I have some questions regarding the specifications of the receipt information that can be obtained from https://developer.apple.com/documentation/appstoreserverapi/get_transaction_info. When a subscription is newly purchased, it is expected that the purchaseDate should reflect the time of purchase and should not be later than this time, such as an hour after the purchase. Is this understanding correct? We observed a phenomenon where, when a user purchased a new subscription between 17:30 and 20:00 JST on November 3, 2024, the purchaseDate in the received receipt was delayed by one hour compared to the actual purchase time. Is this a specification or an issue? When validating the receipt for a newly purchased subscription, if the purchaseDate reflects a time later than when the purchase was made, should I regard the user as having subscription rights at the time of validation?
0
0
78
1d
In-App Purchase Transaction Handling and Refund Implications in App Store API
Hello, I am currently encountering an issue while using the server-side API for in-app purchase integration. Suppose a user has already purchased a product, and the App Store returns a transactionId of 1. After some time, the user repeats the purchase for some reason, and the App Store returns a transactionId of 2. However, when I use the Get Transaction History interface to query the transaction information for transactionId 2, I see that the data returned by the App Store does not include the transaction data for transactionId 2; it only contains the transaction data for transactionId 1. In this situation, my guess is that when the user makes a repeat purchase, the App Store recognizes that the user has already purchased the item and has not executed a refund. Therefore, the App Store generates a new transactionId for this request (the user's purchase) and associates it with the previous purchase's transaction data. This is my inference. If this user has made 5 repeat purchases, when the user successfully requests a refund, if I query the transaction information through the Get Transaction History interface, will the revocationDate for all 5 transactions in the App Store's official database be modified to the same date? Additionally, after the user successfully refunds and makes another purchase, will the new transactionId still be associated with the previous transaction data?
0
0
109
1w
How to Dynamically Obtain Device Models for App Store Users?
I'm currently pulling device-specific data for my app, and I'm manually listing 150 models like this: device_models = [ "iPhone1_1", "iPhone1_2", "iPhone2_1", ... "iPad16_6"] Is there an API endpoint or an automated method to dynamically retrieve a complete list of device models? I'm specifically looking to connect this with the performance metrics API to monitor launch times per device type. Any suggestions on how to streamline or automate this list would be greatly appreciated. Thanks!
2
0
124
1w
In-App Purchase Refund Procedure
Hi everyone, I was just wondering if anyone could point me in the right direction on how to properly handle inquiries about refunding in-app purchases. I've seen multiple posts saying to direct them to Apple's support, but is there no other direct way of handling this? Also, does Apple not provide an API to interface with so you can issue refunds on behalf of the customer? Thanks.
3
0
166
1w
How can the APP server confirm whether the user has made a payment
When the verifiyReceipt API is marked as Depreciated, I tried to verify the user's in app purchase order by calling the Get Transaction Info API to query the order information. However, the response did not show a payment success status. How can the APP server confirm whether the user has made the payment? Also, there is an issue of how to perform parameter transparency (that is, when the user makes the payment, the APP calls the Apple server to bring the developer's custom parameters, and then the APP server calls the Apple server API to obtain this parameter), similar to the Payload parameter of the developer in Google's in app purchase
0
0
139
3w
About the past retrieval range of Look Up Order ID API
I would like to know if there is a limit to past information in the Look Up Order ID API. https://developer.apple.com/documentation/appstoreserverapi/look_up_order_id I understand that you can also get information about users who deleted or reinstalled the app from the content of the document. On the other hand, are there any temporal limits to the past? For example, can the above API make requests for purchases made one year ago, five years ago, or ten years ago?
1
0
207
2w
keep getting 401 Unauthorized error when fetching Apple's public keys.
I keep getting 401 Unauthorized error when fetching Apple's public keys. In [14]: print(f"Error fetching public keys: {response.status_code} {response.text}") Error fetching public keys: 401 Unauthenticated I've verified that the Key ID, Issuer ID, and private key file are all correct, with the private key having admin access. The server time is correctly set to UTC. Given this, I can't identify what might be causing the issue. Any insights? def generate_apple_developer_token(): # Load the private key in PEM format with open(PRIVATE_KEY_FILE, 'rb') as key_file: private_key = serialization.load_pem_private_key( key_file.read(), password=None, backend=default_backend() ) # JWT header headers = { "alg": "ES256", "kid": KEY_ID, "typ": "JWT" } # JWT payload payload = { "iss": ISSUER_ID, "iat": int(datetime.utcnow().timestamp()), "exp": int((datetime.utcnow() + timedelta(minutes=10)).timestamp()), "aud": "appstoreconnect-v1", } # Encode the header and payload as base64 header_base64 = base64.urlsafe_b64encode(json.dumps(headers).encode()).decode().rstrip("=") payload_base64 = base64.urlsafe_b64encode(json.dumps(payload).encode()).decode().rstrip("=") # Concatenate header and payload message = f"{header_base64}.{payload_base64}".encode() # Sign the message using ECDSA with SHA256 signature = private_key.sign( message, ec.ECDSA(hashes.SHA256()) ) # Convert the DER-encoded signature to raw format (r and s concatenated) der_to_raw_ecdsa_format = lambda der: der[4:36] + der[-32:] # Convert the signature to raw format (64 bytes) signature_64 = der_to_raw_ecdsa_format(signature) # Base64 URL-encode the signature signature_base64 = base64.urlsafe_b64encode(signature_64).decode().rstrip("=") # Concatenate header, payload, and signature to form the JWT jwt_token = f"{header_base64}.{payload_base64}.{signature_base64}" return jwt_token def get_apple_public_keys(): try: # Generate a fresh JWT developer_token = generate_apple_developer_token() # Set up headers with the authorization token headers = { "Authorization": f"Bearer {developer_token}" } # Fetch the public keys from Apple response = requests.get('https://api.storekit.itunes.apple.com/in-app-purchase/publicKeys', headers=headers) # Log the response if it's not successful if response.status_code != 200: print(f"Error fetching public keys: {response.status_code} {response.text}") response.raise_for_status() # Raises an exception for 4xx/5xx errors # Parse and return the public keys response_data = response.json() keys = response_data.get('keys') if not keys: print("No 'keys' found in the response from Apple.") return [] return keys except requests.exceptions.RequestException as e: print(f"Error fetching Apple's public keys: {e}") return []
1
0
212
Oct ’24
IPv6 Support for “verifyReceipt API” and “App Store Server API
We are currently upgrading our server to IPv6, and when we tested it, we found that the following API, which verifies receipts when charging, resulted in an error. verifyReceipt API https://buy.itunes.apple.com/verifyReceipt https://sandbox.itunes.apple.com/verifyReceipt This is currently a deprecated API, so when we tried curling the URL to the "App Store Server API" and using nslookup, we also got an error. App Store Server API https://api.storekit.itunes.apple.com https://api.storekit-sandbox.itunes.apple.com The error was that the address could be retrieved from the domain in IPv4, but the address could not be retrieved in IPv6. "https://www.apple.com" and other sites could be retrieved without any problems in IPv6. Is this API not compatible with IPv6? If this is not possible, the only way to verify receipts and the legitimacy of charges seems to be to perform verification on the device, but as this requires a lot of work, I would like to know if there is a better way.
0
0
161
Oct ’24
I need a help with Create a Subscription Price Change
Hello everyone: I have a question regarding subscription price settings that I would like to ask. The specific API is this one: https://developer.apple.com/documentation/appstoreconnectapi/post-v1-subscriptionprices When I set the initial price, for example, setting a price point A for the US, one of the parameters I set for this price point is preserveCurrentPrice as false. Now, when I want to adjust the price from price point A to price point B, there are two scenarios: Adjusting for all users. Adjusting for new users only. In both scenarios, when I set price point B, should I set the preserveCurrentPrice parameter to true? Do I need to reset any attributes for price point A, or will Apple automatically handle whether to retain price point A when I only set price point B? I would appreciate it if someone could help me answer this. Thank you all!
0
0
170
Oct ’24
How to use 'appStoreReceiptURL' to obtain players' paid purchase information and the purchased version
The application has changed from paid purchase to free use. We need to obtain the previous player's purchase records to unlock the paid content. //Here is the code for the client to obtain the player's payment information: NSURL * receiptURL = [[NSBundle mainBundle] appStoreReceiptURL]; if ([[NSFileManager defaultManager] fileExistsAtPath:[receiptURL path]]){ NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL]; NSString *receiptUrlString = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed]; NSLog(@"requestAppStoreReceipt receiptUrlString = %@", receiptUrlString); } else { // 如果凭证为空,则再发一次凭证请求 SKReceiptRefreshRequest *refreshReceiptRequest = [[SKReceiptRefreshRequest alloc] initWithReceiptProperties:@{}]; refreshReceiptRequest.delegate = self; [refreshReceiptRequest start]; NSLog(@"requestAppStoreReceipt 如果凭证为空,则再发一次凭证请求!"); } //The following is the server-side parsing code: Path filePath = Path.of("SubscriptionKey_ABCDEFGHIJ.p8"); String encodedKey = Files.readString(filePath); Environment environment = Environment.SANDBOX; AppStoreServerAPIClient client = new AppStoreServerAPIClient(encodedKey, keyId, issuerId, bundleId, environment); String appReceipt = "MIIcs..."; ReceiptUtility receiptUtil = new ReceiptUtility(); String transactionId = receiptUtil.extractTransactionIdFromTransactionReceipt(transactionReceipt); System.out.println(transactionId); if (transactionId != null) { long now = System.currentTimeMillis(); TransactionHistoryRequest request = new TransactionHistoryRequest() .sort(TransactionHistoryRequest.Order.DESCENDING) .revoked(false) .productTypes(List.of(TransactionHistoryRequest.ProductType.CONSUMABLE)); HistoryResponse response = null; List<String> transactions = new LinkedList<>(); do { String revision = response != null ? response.getRevision() : null; response = client.getTransactionHistory(transactionId, revision, request, GetTransactionHistoryVersion.V2); transactions.addAll(response.getSignedTransactions()); } while (response.getHasMore()); Set<InputStream> rootCAs = Set.of( new FileInputStream("AppleComputerRootCertificate.cer"), new FileInputStream("AppleIncRootCertificate.cer"), new FileInputStream("AppleRootCA-G2.cer"), new FileInputStream("AppleRootCA-G3.cer") ); Long appAppleId = 1234567899L; // appAppleId must be provided for the Production environment System.out.println(transactions.size()); SignedDataVerifier signedPayloadVerifier = new SignedDataVerifier(rootCAs, bundleId, appAppleId, environment, true); for (String notificationPayload : transactions) { try { AppTransaction payload = signedPayloadVerifier.verifyAndDecodeAppTransaction(notificationPayload); System.out.println(payload); } catch (VerificationException e) { e.printStackTrace(); } } } //Return result analysis: JWSTransactionDecodedPayload{originalTransactionId='2000000641683476', transactionId='2000000641683476', webOrderLineItemId='null', bundleId='', productId='', subscriptionGroupIdentifier='null', purchaseDate=1719566962000, originalPurchaseDate=1719566962000, expiresDate=null, quantity=1, type='Consumable', appAccountToken=null, inAppOwnershipType='PURCHASED', signedDate=1728885967093, revocationReason=null, revocationDate=null, isUpgraded=null, offerType=null, offerIdentifier='null', environment='Sandbox', storefront='CHN', storefrontId='143465', transactionReason='PURCHASE', price=6000, currency='CNY', offerDiscountType='null', unknownFields=null} We have develop according to the following document on our end: https://developer.apple.com/documentation/foundation/nsbundle/1407276-appstorereceipturl#4098404 https://developer.apple.com/documentation/appstoreserverapi/get_transaction_info/ https://developer.apple.com/documentation/appstoreserverapi/data_types We would like to know if the solutions in the document can be used to solve the problems we encountered? Is there a problem with our method of parsing bills that prevents us from obtaining the necessary information?
0
0
200
Oct ’24
Apple In App Purchase Validation through Server Notification
We are currently experiencing an issue where our server is not receiving Apple’s server notification (webhook) for in-app purchase confirmations. This notification is critical as it helps us confirm the purchase status and fulfill the corresponding services to the users. Despite the successful completion of purchases within the app, the lack of webhook notifications prevents us from tracking and processing these payments on our backend. In addition to resolving this issue, we are also concerned about the security aspect of receiving server notifications. Specifically, we want to ensure that any requests or notifications we receive are indeed coming from Apple, and not subject to potential man-in-the-middle (MIM) attacks. We are looking for information or best practices on how to validate that the request originates from a legitimate Apple source, ensuring the integrity of the communication and safeguarding our system from spoofed or malicious requests. Key questions: Server Notification Issue: Why might we not be receiving Apple's payment confirmation notifications, and what steps can we take to troubleshoot this issue? Request Validation: What security mechanisms or validation techniques can we implement to confirm that the server notifications are genuinely from Apple, ensuring no interference from MIM attacks? Does Apple provide any headers, tokens, or signatures in the server notification that we can use to verify the origin? Are there any known methods or configurations to ensure secure receipt of in-app purchase confirmations? We are looking for guidance and possible solutions to ensure a secure and reliable payment validation process for our in-app purchases. Any support in this regard would be highly appreciated.
0
0
180
Oct ’24
Delayed App Store Server Notification(V2) for Subscription Purchase
We experienced an issue with delayed App Store Server notifications for an Auto-Renewable Subscription purchase in our app. On September 27, 2024, at 22:28:28 GMT+0900, a user successfully purchased a Premium membership subscription (transaction ID: 190002223966278, webOrderLineItemId: 190001007274949). However, our server did not receive the corresponding App Store notification for this transaction after purchase. The App Store Server Notification was only received 66 minutes later, at 23:35:16 (transaction ID: 190002224000004, webOrderLineItemId: 190001007274949). The delayed notification contained a different transaction ID than the initial purchase. We would like to inquire about the cause of this delay and request assistance in understanding why the notification took 66 minutes to be delivered to our server, instead of arriving immediately after the transaction was completed. Additionally, we would appreciate your guidance on how to prevent or mitigate such delays in the future, ensuring a seamless experience for our users. Are there any best practices or recommended approaches we should implement to handle potential notification delays more effectively? We have provided detailed information about the received notification and the related transactions in the Feedback Assistant (FB15330451). Thank you for your assistance in resolving this matter. Key Details Purchase time: 2024-09-27T22:28:28 GMT+0900 (1727443708000) Notification received: 2024-09-27T23:35:16 GMT+0900 (1727447716463) Delay: 66 minutes and 48 seconds Initial Purchase Transaction ID: 190002223966278 Initial Purchase Web Order Line Item ID: 190001007274949 Transaction ID in Delayed Notification: 190002224000004 Web Order Line Item ID in Delayed Notification: 190001007274949 Additional info Bundle ID: com.reppley.ReppleyApp SKU: com.reppley.ReppleyApp Feedback Assistant Number: FB15330451
1
0
323
Oct ’24
OrderLookupResponse of Look Up Order ID API
In what cases does the transaction in the 'signedTransactions' property array respond with more than one transaction? Is it the case that the in-app purchase product type is 'Auto-Renewable Subscription'? https://developer.apple.com/documentation/appstoreserverapi/look_up_order_id https://developer.apple.com/documentation/appstoreserverapi/orderlookupresponse
1
0
290
Sep ’24
Use of the App Store Server API in a production environment.
When submitting an app, reviewers are aware that they are using the In App Purchase in Sandbox environment. Therefore, we recognize that when processing an app to run the App Store Server API from the app, the production App Store Server API must be run, and if it is a failure, the Snadbox API must be run. As follows. https://developer.apple.com/documentation/appstoreserverapi#3820693 This would result in two http communications, so is there any more efficient way to do this?
1
0
312
Aug ’24
Invalid product ID when attempting mass extend subscription API
Hi there, I'm having trouble using this API: https://developer.apple.com/documentation/appstoreserverapi/extend_subscription_renewal_dates_for_all_active_subscribers It is returning a 400 response for all product IDs for my app's subscriptions: (400, 4000023, 'Invalid request. The product id parameter is invalid.') I have verified these productIds in the App Store Server UI, and using the App Store Connect API to retrieve the product IDs for all subscriptions in the subscription group. Any tips would be greatly appreciated!
6
0
488
Aug ’24