In-App Purchase

RSS for tag

Offer extra content, digital goods, and features directly within your app using in-app purchases.

In-App Purchase Documentation

Posts under In-App Purchase tag

680 Posts
Sort by:
Post not yet marked as solved
7 Replies
3.2k Views
We are using server-to-server purchase notifications for Google Play and App Store mobile apps. User can pay for subscription in several ways: in web broswer (via third-party billing provider), in android application (via google play) and in ios/macos application (via app store). That is why we use custom user/subscription ids - it should be equal across all platforms/devices within single account.Now, everhing went just fine with other billing providers until we came to App Store. We configured server side notification with callback at our server as we did it before. And now it turns out, that there is no user information in App Store receipt data. And it seems to be no way to pass that data from mobile application. For example, Google Play have so called "developer payload" field for this purposes, other providers also have possibility to add external data into server notification request. Is there any analog for App Store notifications?Another question is about notifications itself. If there is no user information in the receipt - that means that there is no way to bind user id and receipt id data. Then what is the purpose of such notfications with external server scenario?
Posted
by
Post not yet marked as solved
4 Replies
1.1k Views
Hello guys,One of our clients has asked that if we can use bitcoin for In-app purchase functionality? Please let me know if Apple allows this kind of functionality.
Posted
by
Post not yet marked as solved
2 Replies
1.1k Views
is I am trying to do this https://developer.apple.com/documentation/storekit/in-app_purchase/generating_a_signature_for_subscription_offers in PHP.I am wondering if I did the signature generation properly. It's really specific to PHP but maybe someone can help:class Key_offer { var $appBundleId; var $keyIdentifier; var $productIdentifier; var $offerIdentifier; var $applicationUsername; var $nonce; var $timestamp; function __construct() { // Setting Data $this->appBundleId = 'bundle_id'; $this->keyIdentifier = 'XXXXXXXXXX'; $this->productIdentifier = $_POST["productIdentifier"]; $this->offerIdentifier = $_POST["offerIdentifier"]; $this->applicationUsername = $_POST["usernameHash"]; $this->nonce = strtolower( $this->gen_uuid() ); $this->timestamp = time() * 1000; } function rsa_sign($policy, $private_key_filename) { $signature = ""; // load the private key $fp = fopen($private_key_filename, "r"); $priv_key = fread($fp, 8192); fclose($fp); $pkeyid = openssl_get_privatekey($priv_key); // compute signature openssl_sign($policy, $signature, $pkeyid); // free the key from memory openssl_free_key($pkeyid); return $signature; } function gen_uuid() { return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x', // 32 bits for "time_low" mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ), // 16 bits for "time_mid" mt_rand( 0, 0xffff ), // 16 bits for "time_hi_and_version", // four most significant bits holds version number 4 mt_rand( 0, 0x0fff ) | 0x4000, // 16 bits, 8 bits for "clk_seq_hi_res", // 8 bits for "clk_seq_low", // two most significant bits holds zero and one for variant DCE1.1 mt_rand( 0, 0x3fff ) | 0x8000, // 48 bits for "node" mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ) ); } function get() { $text = utf8_encode($this->appBundleId.'\u2063'.$this->keyIdentifier.'\u2063'.$this->productIdentifier.'\u2063'.$this->offerIdentifier.'\u2063'.$this->applicationUsername.'\u2063'.$this->nonce.'\u2063'.$this->timestamp); $signature0 = $this->rsa_sign($text, "key.pem"); $signature = hash('sha256', $signature0); $array = array( 'lowUUid' => $this->nonce, 'timeStump' => $this->timestamp, 'identifier' => $this->offerIdentifier, 'keyid' => $this->keyIdentifier, 'signature' => base64_encode($signature) ); return json_encode($array); } } $obj = new Key_offer(); echo $obj->get(); ?>And in the app (Swift) preparing Offer =>public func prepareOffer(usernameHash: String, productIdentifier: String, offerIdentifier: String, completion: @escaping (SKPaymentDiscount?) -> Void) { let config = URLSessionConfiguration.default let session = URLSession.init(configuration: config) // configuration session let url = URL(string: "http://192.168.2.100/Key_Offer/genera_class.php")! var request = URLRequest(url: url) request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") request.httpMethod = "POST" let postString = "usernameHash=\(usernameHash)&productIdentifier=\(productIdentifier)&offerIdentifier=\(offerIdentifier)" request.httpBody = postString.data(using: .utf8) let task = session.dataTask(with: request) { (data, response, error) in guard let data = data, error == nil else { // check for fundamental networking error print("Send POST error= ", error ?? 1) DispatchQueue.main.async { completion(nil) } return } if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 { // check for http errors print("statusCode should be 200, but is \(httpStatus.statusCode)") print("Response = \(String(describing: response))") DispatchQueue.main.async { completion(nil) } } // DA DATA TO JSON CONVERSION let decoder = JSONDecoder.init() do { let post_response = try decoder.decode(SkProd.self, from: data) print(post_response) DispatchQueue.main.async { let lowUUid = UUID.init(uuidString: post_response.lowUUid)! let timeStump = NSNumber.init(value: post_response.timeStump) let identifier = post_response.identifier let keyID = post_response.keyid let signature = post_response.signature let paymentDiscount = SKPaymentDiscount(identifier: identifier, keyIdentifier: keyID, nonce: lowUUid, signature: signature, timestamp: timeStump) // genera la firma per poter creare l'offerta // completed with Success, return a SKPaymentDiscount completion(paymentDiscount) } } catch let error { print("Errore nella conversione del json API Login", error) DispatchQueue.main.async { completion(nil) } } } task.resume() }and this is the Purchase function to purchase the offer =>publicfunc buyProduct(product: SKProduct, usernameHash: String, discountOffer: SKProductDiscount) { let payment = SKMutablePayment.init(product: product) payment.applicationUsername = usernameHash // Add the offer to the payment. print(usernameHash) print(product.productIdentifier) print(discountOffer.identifier!) // REQUEST signature from Server self.prepareOffer(usernameHash:usernameHash, productIdentifier: product.productIdentifier, offerIdentifier: discountOffer.identifier!) { (prodottoDiscount) in if(prodottoDiscount != nil) { // set PaymentDiscount Product payment.paymentDiscount = prodottoDiscount! // Add the payment to the queue for purchase. SKPaymentQueue.default().add(payment) } } }And this is the mistake I get, I hope someone can help me find the error.https://www.tuunes.org/screen.png
Posted
by
Post not yet marked as solved
4 Replies
1.8k Views
I've been testing our app. Things were working fine until about 16 hours ago and then I was no longer getting a response SKProductsRequest. No success and no error callback. If i go to settings > iTunes & App Store and I punch in my sandbox credentials for the sandbox login, it thinks a bit and then it just goes back to the "Sign in" link without signing in. If i intentionally put in the wrong password, the popup shakes so I'm sure I have the right password. This happens on multiple devices.
Posted
by
Post not yet marked as solved
13 Replies
3.1k Views
About a year ago in my Sandbox account I "purchased" some non-consumable IAPs. Recently, I've been implementing auto-renewable subscriptions and while my receipt has filled up with dozens of subscription transactions, the original non-consumable IAPs appear to be missing from the receipt.If i try and buy them again, I get a message saying "You already own this. Do you want to get it for FREE?" and of course i acknowledge it and get a new transaction which i handle normally...but if i refresh the receipt, there's still no mention of the IAP.Lastly, if i do a restore purchases, I get all of the transactions for the IAPs to replay but again, nothing on the receipt about them.Has anyone experienced this before? I filed a radar bug but who knows.
Posted
by
Post not yet marked as solved
2 Replies
1.5k Views
The step where you create an Introductory Offer in iTunes Connect allows you to select only 1 of 3 options: Pay as you go, Pay up front, and Free trial. If my app already has a free trial period set up, can I set up an Introductory offer that's configured as "Pay as you go" with a discounted price? I'm trying to ensure that a potential customer can get both the free trial, which is already configured, AND a discounted introductory price.
Posted
by
Post not yet marked as solved
5 Replies
998 Views
Hi.Am currently struggling to get approval for our first version of an app and have hit a brick wall. Am hoping someone might be able to help point us in the right direction - any help would be greatly appreciated.Background: One of the first things our app does on startup is call SKProductsRequest to get it's IAP (it only has one). When we or any of our TestFlight users run our app everything works fine - the IAP is returned and when the user reaches the appropriate screen we give them a "Purchase" button along with localised pricing information. This has been 100% reliable.The issue: When our app gets run during the Review process it seems as though the SKProductsRequest is not returning any IAPs. If no IAPs are returned we display an error message instead of the "Purchase" button and we've now been rejected twice because the message, rather than the purchase button, is being displayed.Question: Is there anything we need to specifically code for when the app is being reviewed? Why might the response during review be different from when we are testing the app ourselves?Our initial app binary was submitted along side an IAP and the two were linked in App Store Connect when we submitted the binary. We have asked the Review team whether they have turned-over the IAP to their environment but they have referred us to Developer Support.Thanks in advance to to anyone who can give us any pointers!
Posted
by
Post marked as solved
4 Replies
4.1k Views
This is my very first time publishing my App. In-app purchase items were available during testing. But once I upload it for App review, it got rejected either because the details of the IAP items are not displaying properly or the items are not fetched at all. I am wondering how to handle the first time review of an App with IAP? Many thanks for help.
Posted
by
Post not yet marked as solved
1 Replies
434 Views
I'm using IAP with some auto-renewable subscriptions for my app. I had no problem with loading, displaying and purchasing products in development or by using TestFlight to install the app. But when it came to App Review, the app has been rejected because there is no product is displayed properly. So I guess the SKProductsRequest didn't return any valid products. Does anyone experience this issue? I've tried many times but my app still works as expected. Still could not imagine how it can happen.
Posted
by
Post not yet marked as solved
35 Replies
9.0k Views
Out of several thousand users who have made in app purchases we have one that has a pop up with "There's no information available for In-App Purchases issue. Try again later 21199" showing when they open the app.Looking at the data codes 21199 is:21100-21199Internal data access error.There is no other information shown though for this message.Has anyone else come across this? If so, what was the fix?
Posted
by
Post not yet marked as solved
5 Replies
1.3k Views
I have apps that have worked for years with non-consumable in-app purchases that users could restore. Now it no longer works.I call[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];In the store observer, it used to go here- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions { // never gets here for (SKPaymentTransaction *transaction in transactions) { switch (transaction.transactionState) { case SKPaymentTransactionStateRestored: // used to go here, no longer doesNow it goes here- (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue { // goes here with [queue.transactions count] == 0I've downloaded the example code here and it has the same problem.https://developer.apple.com/documentation/storekit/in-app_purchase/offering_completing_and_restoring_in-app_purchase
Posted
by
Post marked as solved
4 Replies
1.6k Views
Hi guys,I need some clarifications about in-app purchase currencies.We are developping an app where users post videos.Users can buy virtual coins and use them to tip other users (In-app purchase)https://developer.apple.com/app-store/review/guidelines/#in-app-purchaseUsers can also cash out their coins (via paypal).The virtual coins will be converted to real moneyThis is (almost) the same system used by tiktok and many other apps.My questions are:- Am I required to have a money transmitter license?- Am I trespassing any of Appple regulations?Thanks for your help
Posted
by
Post not yet marked as solved
7 Replies
1.2k Views
Hello,This is my first post in Apple dev forums.If you have integrated with appstore for renewable subscriptions, you probably know by now how bad the overall experience is. A couple of weeks ago I noticed that Apple updated their server-to-server notifications docs.They are going to deprecate certain notification types and introduced new/changed objects. One object in particular is `unified_receipt` https://developer.apple.com/documentation/appstoreservernotifications/unified_receiptBedides many other inconsistencies in the docs and what their API actually returns, I want to focus on unified_receipt. In Sandbox, Appstore still returns an old payload (no unified_receipt), but I noticed that in Production unified_receipt is there. How does that make any sense? Why cannot Apple get such an important, yet very simple thing get right?
Posted
by
Post not yet marked as solved
7 Replies
2.3k Views
We face an issue that are existing the same transaction id from different receipt, but the iap product is a consumable product (not non-consumable or subscription one).Suppose that transaction id should be unique, they should be not shared between different receipt (in case for consumable product), am i right?As i know this is an anormal situation, i think there is < 1% from our cs record.After the discussion between our cs and customer, his situation should like this:he have 3 devices whose are shared the same Apple Id for IAPall devices are installed the same gamehe try to purchase through IAP on his all device within 10 minutes he purchase the product A successful on device A and receive the items (server got transaction id A from receipt)he purchase the product A successful on device B but it can't receive the items (server got transaction id A from receipt and try to reject it since it is a duplicated transaction)he purchase the product A successful on device C but it can't receive the items (server got transaction id A & C from recept and try to reject it since it is more than one transaction...)So my questions are shown as belowwhy the receipt exist the previous transaction id (A) but miss the new transaction id?why the receipt have more than one transaction?Hope that anyone can assist me to solve this issue ><
Posted
by
Post not yet marked as solved
0 Replies
671 Views
I have a sandbox test user which I used to test In-App purchases. Everything was working until I upgraded to macOS Catalina (10.15.3).If I try to refresh a receipt when it's not available with SKReceiptRefreshRequest() it fails with error: Error Domain=SKErrorDomain Code=0 "(null)".Calling exit(173) shows error message: {application name} is damaged and can't be opened. Delete {application name} and download it again from the App Store.In any case I can see a warning in Console.app: Subsystem: com.apple.commerce Category: CommerceKit message: <ReceiptRefreshRequest: 0x7fb7cb439c90>: Error fetching receipt for {application name} - Error Domain=com.apple.commerce.server Code=500317 "(null)".There was no problem on Mojave so it was broken in Catalina. Did anyone found a solution?
Posted
by
Post not yet marked as solved
0 Replies
758 Views
I am setting up server-to-server notifications for auto-renewable subscriptions in my application.I recieve many of the various type of notifications: INITIAL_BUY, DID_CHANGE_RENEWAL_STATUS, RENEWAL, DID_RECOVER, etc..When I receive the notifications from apple I verify the receipt, do some business logic and return a 200 if everything goes well and a 500 if not.I've found that I often don't receive the expiration notifications for subscriptions, therefore I would have users who are not paying who will retain access to content.It also appears that the server to server notifications that I receive are not consistent.For example, if 3 users opt-in and become subscribers, the server to server notification I receive from apple from start to (a potential, but possibly never received) expiration vary in what seems to be a random way.User 1: INITIAL_BUY, RENEWAL, DID_RECOVER, DID_CHANGE_RENEWAL_STATUS, INTERACTIVE_RENEWAL (this was the cancel)User 2: INITIAL_BUY, DID_CHANGE_RENEWAL_STATUSUser 3: INITIAL_BUY, DID_RECOVER, RENEWAL There seems to be no consistency in testing subscriptions and what to expect from server to server notifications.It's also to my understanding that apple doesn't send a server to server notification if a currently active subscription succesfully renews for another month (or whatever interval). Therefore if you want to always have the most up to date expiration date, you'd have to poll their /verifyReceipt route.It seems to me that polling apple every so often after the INITIAL_BUY is the way to go and that the server to server notifications aren't actually providing that value that one would assume.Two questions that arise out of all of this are:1. Can I expect the same weirdness in the non-sandbox environment2. How have some of you solved this issue if it's actually as inconsistent and un-informative as I've experienced? Do you just rely on polling or have some of you implemented full subscription handling solutions that work just through the server to server notifications?
Posted
by
Post not yet marked as solved
0 Replies
251 Views
Hi,I am using https://buy.itunes.apple.com/verifyReceiptto verify and get the details of the receipt.. is there any way to get the total amount of the receipt or how much the user paid exactly?
Posted
by
Post not yet marked as solved
1 Replies
730 Views
I am implementing IAP for an autorenewable subscription. I decode the receipt on the device. I noticed in the sandbox that the original_transaction_id is changing for each renewal. (It is always the same as the transaction_id which differs for each renewal, as it should.) Can anyone confirm that this is NOT what happens in production?A WWDC video states that the original_transaction_id for an autorenewable subscription can be used to associate different devices owned by the same user. I had always thought that the original_transaction_id would differ from device to device. Can anyone confirm that in production the original_transaction_id is the same across all devices owned by the same user for an autorenewable subscription?
Posted
by
PBK