App Store Server Library

RSS for tag

App Store Server Library is the library for the App Store Server API and App Store Server Notifications. It provides an API client, a JWS signed data verifier, a utility to extract a transaction id from a receipt, and a promotional offer signature.

Posts under App Store Server Library tag

30 Posts
Sort by:

Post

Replies

Boosts

Views

Activity

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
108
1w
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
322
Oct ’24
Receipt verification Verification failed with status VERIFICATION_FAILURE
Hello team, There is a Function,App create a order;When the app is all paid out,it sends me a credentials; I accept and verify; verify_and_decode_signed_transaction function have an error; requests.exceptions.ConnectionError: HTTPConnectionPool(host='ocsp.apple.com', port=80): Max retries exceeded with url: /ocsp03-applerootcag3 (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x1123c7d00>: Failed to establish a new connection: [Errno 61] Connection refused')) The above exception was the direct cause of the following exception: appstoreserverlibrary.signed_data_verifier.VerificationException: Verification failed with status VERIFICATION_FAILURE def verify_purchase(self, request, *args, **kwargs): try: receipt_data = request.data.get('receipt_data') transaction_id = receiptUtilInstance.extract_transaction_id_from_app_receipt(receipt_data) sendResponse: TransactionInfoResponse = appleClientInstance.client.get_transaction_info(transaction_id) signedPayLoad: str = sendResponse.signedTransactionInfo time.sleep(3) payload = signedDataInstance.client.verify_and_decode_signed_transaction(signedPayLoad) please help me
1
0
385
Sep ’24
Can't receive CONSUMPTION_REQUEST notification.
My App uses an auto-renewal subscription, and I've been using the CONSUMPTION_REQUEST event to track user refund requests. However, since yesterday morning, I haven't been receiving any CONSUMPTION_REQUEST notifications. All other notifications are functioning normally and I haven't changed anything. What could be the issue?
1
0
277
Sep ’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
487
Aug ’24
Jws tranaction receipt verified pass but storekit API reponse 404
We receive a JWS receipt and successfully verify the x5c pass. However, when we use the transaction_id from the receipt to query the endpoint https://api.storekit.itunes.apple.com/inApps/v1/transactions/, we encounter the following error: {"errorCode":4040010,"errorMessage":"Transaction id not found."}. Why does this happen? Thanks for your answer. The jws receipt is: eyJhbGciOiJFUzI1NiIsIng1YyI6WyJNSUlFTURDQ0E3YWdBd0lCQWdJUWZUbGZkMGZOdkZXdnpDMVlJQU5zWGpBS0JnZ3Foa2pPUFFRREF6QjFNVVF3UWdZRFZRUURERHRCY0hCc1pTQlhiM0pzWkhkcFpHVWdSR1YyWld4dmNHVnlJRkpsYkdGMGFXOXVjeUJEWlhKMGFXWnBZMkYwYVc5dUlFRjFkR2h2Y21sMGVURUxNQWtHQTFVRUN3d0NSell4RXpBUkJnTlZCQW9NQ2tGd2NHeGxJRWx1WXk0eEN6QUpCZ05WQkFZVEFsVlRNQjRYRFRJek1Ea3hNakU1TlRFMU0xb1hEVEkxTVRBeE1URTVOVEUxTWxvd2daSXhRREErQmdOVkJBTU1OMUJ5YjJRZ1JVTkRJRTFoWXlCQmNIQWdVM1J2Y21VZ1lXNWtJR2xVZFc1bGN5QlRkRzl5WlNCU1pXTmxhWEIwSUZOcFoyNXBibWN4TERBcUJnTlZCQXNNSTBGd2NHeGxJRmR2Y214a2QybGtaU0JFWlhabGJHOXdaWElnVW1Wc1lYUnBiMjV6TVJNd0VRWURWUVFLREFwQmNIQnNaU0JKYm1NdU1Rc3dDUVlEVlFRR0V3SlZVekJaTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEEwSUFCRUZFWWUvSnFUcXlRdi9kdFhrYXVESENTY1YxMjlGWVJWLzB4aUIyNG5DUWt6UWYzYXNISk9OUjVyMFJBMGFMdko0MzJoeTFTWk1vdXZ5ZnBtMjZqWFNqZ2dJSU1JSUNCREFNQmdOVkhSTUJBZjhFQWpBQU1COEdBMVVkSXdRWU1CYUFGRDh2bENOUjAxREptaWc5N2JCODVjK2xrR0taTUhBR0NDc0dBUVVGQndFQkJHUXdZakF0QmdnckJnRUZCUWN3QW9ZaGFIUjBjRG92TDJObGNuUnpMbUZ3Y0d4bExtTnZiUzkzZDJSeVp6WXVaR1Z5TURFR0NDc0dBUVVGQnpBQmhpVm9kSFJ3T2k4dmIyTnpjQzVoY0hCc1pTNWpiMjB2YjJOemNEQXpMWGQzWkhKbk5qQXlNSUlCSGdZRFZSMGdCSUlCRlRDQ0FSRXdnZ0VOQmdvcWhraUc5Mk5rQlFZQk1JSCtNSUhEQmdnckJnRUZCUWNDQWpDQnRneUJzMUpsYkdsaGJtTmxJRzl1SUhSb2FYTWdZMlZ5ZEdsbWFXTmhkR1VnWW5rZ1lXNTVJSEJoY25SNUlHRnpjM1Z0WlhNZ1lXTmpaWEIwWVc1alpTQnZaaUIwYUdVZ2RHaGxiaUJoY0hCc2FXTmhZbXhsSUhOMFlXNWtZWEprSUhSbGNtMXpJR0Z1WkNCamIyNWthWFJwYjI1eklHOW1JSFZ6WlN3Z1kyVnlkR2xtYVdOaGRHVWdjRzlzYVdONUlHRnVaQ0JqWlhKMGFXWnBZMkYwYVc5dUlIQnlZV04wYVdObElITjBZWFJsYldWdWRITXVNRFlHQ0NzR0FRVUZCd0lCRmlwb2RIUndPaTh2ZDNkM0xtRndjR3hsTG1OdmJTOWpaWEowYVdacFkyRjBaV0YxZEdodmNtbDBlUzh3SFFZRFZSME9CQllFRkFNczhQanM2VmhXR1FsekUyWk9FK0dYNE9vL01BNEdBMVVkRHdFQi93UUVBd0lIZ0RBUUJnb3Foa2lHOTJOa0Jnc0JCQUlGQURBS0JnZ3Foa2pPUFFRREF3Tm9BREJsQWpFQTh5Uk5kc2twNTA2REZkUExnaExMSndBdjVKOGhCR0xhSThERXhkY1BYK2FCS2pqTzhlVW85S3BmcGNOWVVZNVlBakFQWG1NWEVaTCtRMDJhZHJtbXNoTnh6M05uS20rb3VRd1U3dkJUbjBMdmxNN3ZwczJZc2xWVGFtUllMNGFTczVrPSIsIk1JSURGakNDQXB5Z0F3SUJBZ0lVSXNHaFJ3cDBjMm52VTRZU3ljYWZQVGp6Yk5jd0NnWUlLb1pJemowRUF3TXdaekViTUJrR0ExVUVBd3dTUVhCd2JHVWdVbTl2ZENCRFFTQXRJRWN6TVNZd0pBWURWUVFMREIxQmNIQnNaU0JEWlhKMGFXWnBZMkYwYVc5dUlFRjFkR2h2Y21sMGVURVRNQkVHQTFVRUNnd0tRWEJ3YkdVZ1NXNWpMakVMTUFrR0ExVUVCaE1DVlZNd0hoY05NakV3TXpFM01qQXpOekV3V2hjTk16WXdNekU1TURBd01EQXdXakIxTVVRd1FnWURWUVFERER0QmNIQnNaU0JYYjNKc1pIZHBaR1VnUkdWMlpXeHZjR1Z5SUZKbGJHRjBhVzl1Y3lCRFpYSjBhV1pwWTJGMGFXOXVJRUYxZEdodmNtbDBlVEVMTUFrR0ExVUVDd3dDUnpZeEV6QVJCZ05WQkFvTUNrRndjR3hsSUVsdVl5NHhDekFKQmdOVkJBWVRBbFZUTUhZd0VBWUhLb1pJemowQ0FRWUZLNEVFQUNJRFlnQUVic1FLQzk0UHJsV21aWG5YZ3R4emRWSkw4VDBTR1luZ0RSR3BuZ24zTjZQVDhKTUViN0ZEaTRiQm1QaENuWjMvc3E2UEYvY0djS1hXc0w1dk90ZVJoeUo0NXgzQVNQN2NPQithYW85MGZjcHhTdi9FWkZibmlBYk5nWkdoSWhwSW80SDZNSUgzTUJJR0ExVWRFd0VCL3dRSU1BWUJBZjhDQVFBd0h3WURWUjBqQkJnd0ZvQVV1N0Rlb1ZnemlKcWtpcG5ldnIzcnI5ckxKS3N3UmdZSUt3WUJCUVVIQVFFRU9qQTRNRFlHQ0NzR0FRVUZCekFCaGlwb2RIUndPaTh2YjJOemNDNWhjSEJzWlM1amIyMHZiMk56Y0RBekxXRndjR3hsY205dmRHTmhaek13TndZRFZSMGZCREF3TGpBc29DcWdLSVltYUhSMGNEb3ZMMk55YkM1aGNIQnNaUzVqYjIwdllYQndiR1Z5YjI5MFkyRm5NeTVqY213d0hRWURWUjBPQkJZRUZEOHZsQ05SMDFESm1pZzk3YkI4NWMrbGtHS1pNQTRHQTFVZER3RUIvd1FFQXdJQkJqQVFCZ29xaGtpRzkyTmtCZ0lCQkFJRkFEQUtCZ2dxaGtqT1BRUURBd05vQURCbEFqQkFYaFNxNUl5S29nTUNQdHc0OTBCYUI2NzdDYUVHSlh1ZlFCL0VxWkdkNkNTamlDdE9udU1UYlhWWG14eGN4ZmtDTVFEVFNQeGFyWlh2TnJreFUzVGtVTUkzM3l6dkZWVlJUNHd4V0pDOTk0T3NkY1o0K1JHTnNZRHlSNWdtZHIwbkRHZz0iLCJNSUlDUXpDQ0FjbWdBd0lCQWdJSUxjWDhpTkxGUzVVd0NnWUlLb1pJemowRUF3TXdaekViTUJrR0ExVUVBd3dTUVhCd2JHVWdVbTl2ZENCRFFTQXRJRWN6TVNZd0pBWURWUVFMREIxQmNIQnNaU0JEWlhKMGFXWnBZMkYwYVc5dUlFRjFkR2h2Y21sMGVURVRNQkVHQTFVRUNnd0tRWEJ3YkdVZ1NXNWpMakVMTUFrR0ExVUVCaE1DVlZNd0hoY05NVFF3TkRNd01UZ3hPVEEyV2hjTk16a3dORE13TVRneE9UQTJXakJuTVJzd0dRWURWUVFEREJKQmNIQnNaU0JTYjI5MElFTkJJQzBnUnpNeEpqQWtCZ05WQkFzTUhVRndjR3hsSUVObGNuUnBabWxqWVhScGIyNGdRWFYwYUc5eWFYUjVNUk13RVFZRFZRUUtEQXBCY0hCc1pTQkpibU11TVFzd0NRWURWUVFHRXdKVlV6QjJNQkFHQnlxR1NNNDlBZ0VHQlN1QkJBQWlBMklBQkpqcEx6MUFjcVR0a3lKeWdSTWMzUkNWOGNXalRuSGNGQmJaRHVXbUJTcDNaSHRmVGpqVHV4eEV0WC8xSDdZeVlsM0o2WVJiVHpCUEVWb0EvVmhZREtYMUR5eE5CMGNUZGRxWGw1ZHZNVnp0SzUxN0lEdll1VlRaWHBta09sRUtNYU5DTUVBd0hRWURWUjBPQkJZRUZMdXczcUZZTTRpYXBJcVozcjY5NjYvYXl5U3JNQThHQTFVZEV3RUIvd1FGTUFNQkFmOHdEZ1lEVlIwUEFRSC9CQVFEQWdFR01Bb0dDQ3FHU000OUJBTURBMmdBTUdVQ01RQ0Q2Y0hFRmw0YVhUUVkyZTN2OUd3T0FFWkx1***5UmhIRkQvM21lb3locG12T3dnUFVuUFdUeG5TNGF0K3FJeFVDTUcxbWloREsxQTNVVDgyTlF6NjBpbU9sTTI3amJkb1h0MlFmeUZNbStZaGlkRGtMRjF2TFVhZ002QmdENTZLeUtBPT0iXX0.eyJ0cmFuc2FjdGlvbklkIjoiMzAwMDAxODE3NTk4MjgwIiwib3JpZ2luYWxUcmFuc2FjdGlvbklkIjoiMzAwMDAxODE3NTk4MjgwIiwiYnVuZGxlSWQiOiJjb20ud2Vqb3kud2VwbGF5LmFyIiwicHJvZHVjdElkIjoiY29pbjYwMF9hciIsInB1cmNoYXNlRGF0ZSI6MTcxNDAwMDE4MjAwMCwib3JpZ2luYWxQdXJjaGFzZURhdGUiOjE3MTQwMDAxODIwMDAsInF1YW50aXR5IjoxLCJ0eXBlIjoiQ29uc3VtYWJsZSIsImRldmljZVZlcmlmaWNhdGlvbiI6Im00SFVMaUxKemVyMzZNK3pkZVNnYzY4MXRlQUZQY3FhUVJ3dEFxU25xdFU2emI0U29haUtmYnM5Mm1QU1FhcjUiLCJkZXZpY2VWZXJpZmljYXRpb25Ob25jZSI6IjMzODU5YzIzLTY5NDQtNDQ1Yi1iYmU3LTliNDY5YjhmZjBlZSIsImFwcEFjY291bnRUb2tlbiI6IjZkNjU4MjZmLTdkZDAtNDIwMi1iZmQ2LTEzMjJhOWQyZTY5NCIsImluQXBwT3duZXJzaGlwVHlwZSI6IlBVUkNIQVNFRCIsInNpZ25lZERhdGUiOjE3MTQwMDAxODA2MDcsImVudmlyb25tZW50IjoiUHJvZHVjdGlvbiIsInRyYW5zYWN0aW9uUmVhc29uIjoiUFVSQ0hBU0UiLCJzdG9yZWZyb250IjoiU0FVIiwic3RvcmVmcm9udElkIjoiMTQzNDc5IiwicHJpY2UiOjM5OTAsImN1cnJlbmN5IjoiU0FSIn0.WNfzeCcChz--9tasyrejhgHw4cCrehptucQKVDF_FU46vHqIIlWvQY_jNUDSDhuT2fVYbL10yVx6uA6q5XfCbw
1
0
399
Jul ’24
APP Store Server Notifications Unrelated transactions info for auto-renewable subscription
Greetings for App Store Server Notifications especially sandbox (I have not tried production) it seems that that is no way to associate two transactions to their orignal subscription instance the docs indicate webLineItemOrderId id but they are different from each subscription the originalTransactionId is the same among all subscription instances and customers, theres originalPurchaseDate but that is not reliable becuase 2 transactions can occur on the same date what can be done here. I even tried to use it but its like the sandbox is broken with the originalPurchaseDate of one instance being the same as another. is it a bug or will things get in line once I go to production?
1
0
292
Jul ’24
Handling Subscription Status Updates with Apple Notification V2
We are using Apple Notification V2 and supporting only one subscription service per user (e.g., Netflix with Basic, Premium plans). In Notification V1, we could fetch the latest subscription information using the /verifyReceipt API. However, the documentation for Notification V2 suggests using SignedDataVerifier to decode the data locally. This raises a concern that the data received via notification might not always be up-to-date. For example, if a user cancels a subscription but the server fails to process the notification for some reason, and later the user upgrades and resumes the subscription, the new notification succeeds. In this scenario, the previously failed cancellation notification will be resent after some time. How should the backend server handle this? Should we always use APIs like get all subscription statuses to fetch the latest data instead of solely relying on the decoded data from each notification?
1
0
372
Jul ’24
Checking refund history for multiple transactions
As of the latest available information, Apple does not directly provide an endpoint for checking refund history for multiple transactions in a single request via their App Store Server API. The endpoint https://api.storekit.itunes.apple.com/inApps/v2/refund/lookup/{transactionId} allows you to check the refund status for a single transaction ID at a time. What if you have 8000 subscribers? Are we going to send 8k requests everyday? What's the solution for this scenario? We don't want to implement the notifications by the way. Any solutions?
2
0
523
Jul ’24
App crashes with error "SIGNAL 6:Abort trap:6"
The application crashes and displays the error "SIGNAL 6:Abort trap:6" while it is in movement. We have implemented telematics functionality, which required us to add permissions for location, motion, and bluetooth. We have attached the log file. Help us to resolve this Exception Type: EXC_CRASH (SIGABRT) Exception Codes: 0x0000000000000000, 0x0000000000000000 Exception Reason: -[%s %s]: unrecognized selector sent to instance 0x303475170 Termination Reason: SIGNAL 6 Abort trap: 6 Triggered by Thread: 6 Last Exception Backtrace: 0 CoreFoundation 0x1a6594f20 __exceptionPreprocess + 164 (NSException.m:249) 1 libobjc.A.dylib 0x19e426018 objc_exception_throw + 60 (objc-exception.mm:356) 2 CoreFoundation 0x1a669e480 -[NSObject(NSObject) doesNotRecognizeSelector:] + 344 (NSObject.m:161) 3 CoreFoundation 0x1a6531fb4 forwarding + 1572 (NSForwarding.m:3612) 4 CoreFoundation 0x1a65318d0 CF_forwarding_prep_0 + 96 (:-1) 5 Boubyan Takaful Insurance 0x1045199fc -[MendixEncryptedStorageModule getItem:resolver:rejecter:] + 456 (MendixEncryptedStorageModule.m:93) 6 CoreFoundation 0x1a6531814 invoking + 148 (:-1) 7 CoreFoundation 0x1a6530860 -[NSInvocation invoke] + 428 (NSForwarding.m:3411) 8 CoreFoundation 0x1a65a71dc -[NSInvocation invokeWithTarget:] + 64 (NSForwarding.m:3508) 9 Boubyan Takaful Insurance 0x1041fc6fc -[RCTModuleMethod invokeWithBridge:module:arguments:] + 388 (RCTModuleMethod.mm:584) 10 Boubyan Takaful Insurance 0x1041fe6e0 facebook::react::invokeInner(RCTBridge*, RCTModuleData*, unsigned int, folly::dynamic const&, int, (anonymous namespace)::SchedulingContext) + 452 (RCTNativeModule.mm:183) 11 Boubyan Takaful Insurance 0x1041fe330 facebook::react::RCTNativeModule::invoke(unsigned int, folly::dynamic&&, int)::$_0::operator()() const + 68 (RCTNativeModule.mm:104) 12 Boubyan Takaful Insurance 0x1041fe330 invocation function for block in facebook::react::RCTNativeModule::invoke(unsigned int, folly::dynamic&&, int) + 112 (RCTNativeModule.mm:95) 13 libdispatch.dylib 0x1ae43813c _dispatch_call_block_and_release + 32 (init.c:1530) 14 libdispatch.dylib 0x1ae439dd4 _dispatch_client_callout + 20 (object.m:576) 15 libdispatch.dylib 0x1ae441400 _dispatch_lane_serial_drain + 748 (queue.c:3900) 16 libdispatch.dylib 0x1ae441f30 _dispatch_lane_invoke + 380 (queue.c:3991) 17 libdispatch.dylib 0x1ae44ccb4 _dispatch_root_queue_drain_deferred_wlh + 288 (queue.c:6998) 18 libdispatch.dylib 0x1ae44c528 _dispatch_workloop_worker_thread + 404 (queue.c:6592) 19 libsystem_pthread.dylib 0x2033eb934 _pthread_wqthread + 288 (pthread.c:2696) 20 libsystem_pthread.dylib 0x2033e80cc start_wqthread + 8 (:-1) hread 6 crashed with ARM Thread State (64-bit): x0: 0x0000000000000000 x1: 0x0000000000000000 x2: 0x0000000000000000 x3: 0x0000000000000000 x4: 0x00000002033112c3 x5: 0x000000016c0aa810 x6: 0x000000000000006e x7: 0x0000000000000000 x8: 0xe50a98ccb19cbcdd x9: 0xe50a98cddd960cdd x10: 0x0000000000000200 x11: 0x000000016c0aa340 x12: 0x0000000000000000 x13: 0x00000000001ff800 x14: 0x0000000000000010 x15: 0x0000000000000000 x16: 0x0000000000000148 x17: 0x000000016c0ab000 x18: 0x0000000000000000 x19: 0x0000000000000006 x20: 0x0000000000002403 x21: 0x000000016c0ab0e0 x22: 0x0000000000000114 x23: 0x000000016c0ab0e0 x24: 0x0000000301846ee8 x25: 0x0000000000000000 x26: 0x0000000000000000 x27: 0x0000000302354e00 x28: 0x0000000000000000 fp: 0x000000016c0aa780 lr: 0x00000002033eec0c sp: 0x000000016c0aa760 pc: 0x00000001ef64f42c cpsr: 0x40001000 esr: 0x56000080 Address size fault crashlog.crash
1
0
1.9k
Jul ’24
Cancel Subscriptions on Behalf of Customer like Netflix (App Store Server API)
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...
0
0
514
Jun ’24
Cannot Receive `EXPIRED` Notifications from App Store Server Notifications V2
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}") } }
1
0
701
May ’24
App Store Server Notifications V2 always retries five times
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.
3
0
1k
May ’24
My getTransactionInfo call resulted in apiError: 4040010, errorMessage: 'Transaction id not found.'
Hi, I am testing a consumable in-app purchase on my app, with a Sandbox account on an iPad device. The transaction was successful, as I saw "You're all set. Your purchase was successful. [Environment: Sandbox]. I set a break point in Xcode after the line await transaction.finish() in following code private func handle(transactionVerification result: VerificationResult ) async { switch result { case let .verified(transaction): guard let product = self.products.first(where: { $0.id == transaction.productID }) else { return } self.addPurchased(product) await transaction.finish() return. <----- breakpoint And I saw those property values for the transaction id UInt64 88*****848 originalID UInt64 437****2496 . Then I use the originalID value 437*****2496 in a server library call in node.js .... const environment = Environment.SANDBOX .... const client = new AppStoreServerAPIClient(encodedKey, keyId, issuerId, bundleId, environment) .... const response = await client.getTransactionInfo("4379072496") I got apiError: 4040010, errorMessage: 'Transaction id not found.' Could someone please tell me if I use the library call correctly with the right id? And why I got the error? Thank you very much! Kind regards, Shih-Chin Yang [Edited by Moderator]
5
0
850
May ’24