Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 6024881
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 23, 20262026-05-23T04:13:14+00:00 2026-05-23T04:13:14+00:00

Apple finally introduced the so called auto-renewable subscriptions yesterday. Since I only have few

  • 0

Apple finally introduced the so called auto-renewable subscriptions yesterday. Since I only have few (sandbox-only) experiences with in-app-purchase, I’m not sure that I got it all right here. It seems one needs a server side verification of the receipts. It seems the only way to find out if the subscription is still valid, is to store the original transaction data on server side. Apples programming guide with respect to this topic is all cryptic to me.

My expectation was, that I can work with an iOS client only, by just asking iTunes via store kit api did he/she already buy this (subscription-)product and receiving a yes/no answer together with an expiration date.

Does anyone have experiences with auto-renewable subscriptions or (because they seem somehow similar) non-consumable products? Are there any good tutorials about this?

Thank you.

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-23T04:13:15+00:00Added an answer on May 23, 2026 at 4:13 am

    I have it running in the sandbox, almost going live…

    One should use a server to verify the receipts.

    On the server you can record the device udid with the receipt data, since receipts are always freshly generated, and it will work across multiple devices, since the receipts are always freshly generated.

    On the device one does not need to store any sensitive data, and should not 🙂

    One should check the last receipt with the store whenever the app comes up. The app calls the server and the server validates with the store. As long as the store returns a valid receipt app serves the feature.

    I developed a Rails3.x app to handle the server side, the actual code for the verification looks like this:

    APPLE_SHARED_PASS = "enter_yours"
    APPLE_RECEIPT_VERIFY_URL = "https://sandbox.itunes.apple.com/verifyReceipt" #test
    # APPLE_RECEIPT_VERIFY_URL = "https://buy.itunes.apple.com/verifyReceipt"     #real
    def self.verify_receipt(b64_receipt)
      json_resp = nil
      url = URI.parse(APPLE_RECEIPT_VERIFY_URL)
      http = Net::HTTP.new(url.host, url.port)
      http.use_ssl = true
      http.verify_mode = OpenSSL::SSL::VERIFY_NONE
      json_request = {'receipt-data' => b64_receipt, 'password' => APPLE_SHARED_PASS}.to_json
      resp, resp_body = http.post(url.path, json_request.to_s, {'Content-Type' => 'application/x-www-form-urlencoded'})
      if resp.code == '200'
        json_resp = JSON.parse(resp_body)
        logger.info "verify_receipt response: #{json_resp}"
      end
      json_resp
    end
    #App Store error responses
    #21000 The App Store could not read the JSON object you provided.
    #21002 The data in the receipt-data property was malformed.
    #21003 The receipt could not be authenticated.
    #21004 The shared secret you provided does not match the shared secret on file for your account.
    #21005 The receipt server is not currently available.
    #21006 This receipt is valid but the subscription has expired.
    

    UPDATE

    My app got rejected, because the meta data was not clearly stating some info about the auto-renewable subscriptions.

    In your meta data at iTunes Connect (in your app description): You
    need to clearly and conspicuously disclose to users the following
    information regarding Your auto-renewing subscription:
     

    • Title of publication or service
    • Length of subscription (time period and/or number of deliveries during each subscription period)
    • Price of subscription, and price per issue if appropriate
    • Payment will be charged to iTunes Account at confirmation of purchase
    • Subscription automatically renews unless auto-renew is turned off at least 24-hours before the end of the current period
    • Account will be charged for renewal within 24-hours prior to the end of the current period, and identify the cost of the renewal
    • Subscriptions may be managed by the user and auto-renewal may be turned off by going to the user’s Account Settings after purchase
    • No cancellation of the current subscription is allowed during active subscription period
    • Links to Your Privacy Policy and Terms of Use
    • Any unused portion of a free trial period, if offered, will be forfeited when the user purchases a subscription to that publication.”

    UPDATE II

    App got rejected again. The subscription receipt is not verified by the production AppStore verify url. I can not reproduce this problem in the sandbox, my app works flawless. The only way to debug this, is to submit the app again for review and look at the server log.

    UPDATE III

    Another rejection. Meanwhile Apple documented two more statuses:

    #21007 This receipt is a sandbox receipt, but it was sent to the production service for verification.
    #21008 This receipt is a production receipt, but it was sent to the sandbox service for verification.
    

    Before one submits the app for review, one should not switch the server to production
    receipt verify url. if one does, one gets status 21007 returned on verification.

    This time the rejection reads like this:

    Application initiates the In App Purchase process in a non-standard manner. We have included the following details to help
    explain the issue and hope you’ll consider revising and resubmitting
    your application.

    iTunes username & password are being asked for immediately on application launch. Please refer to the attached screenshot for more
    information.

    I have no clue why this happens. Does the password dialog pop up because a previous transaction is being restored? or does it pop up at the point of requesting products information from the app store?

    UPDATE IV

    I got it right after 5 rejections. My code was doing the most obvious error. One should really make sure to always finish transactions when they are delivered to the app.

    If transactions aren’t finished, they get delivered back to the app and things go strangely wrong.

    One needs to initiate a payment first, like this:

    //make the payment
    SKPayment *payment = [SKPayment paymentWithProductIdentifier:productIdentifier];
    [[SKPaymentQueue defaultQueue] addPayment:payment];
    

    Then the app will shortly resign its active state and this method on the app delegate is called:

    - (void)applicationWillResignActive:(UIApplication *)application
    

    While the app is inactive, the App Store pops up its dialogs. as the app becomes active again:

    - (void)applicationDidBecomeActive:(UIApplication *)application
    

    The OS delivers the transaction through:

    - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
    {
    
      for (SKPaymentTransaction *transaction in transactions)
      {
    
        switch (transaction.transactionState)
        {
            case SKPaymentTransactionStatePurchased: {
                [self completeTransaction:transaction];
                break;
            }
            case SKPaymentTransactionStateFailed: {
                [self failedTransaction:transaction];
                break;
            }
            case SKPaymentTransactionStateRestored: {
                [self restoreTransaction:transaction];
                break;
            }
            default:
                break;
          }
      }
    }
    

    And then one completes the transaction:

    //a fresh purchase
    - (void) completeTransaction: (SKPaymentTransaction *)transaction
    {
        [self recordTransaction: transaction];
        [[SKPaymentQueue defaultQueue] finishTransaction: transaction]; 
    }
    

    See, how one calls the method finishTransaction right after passing the received transaction to recordTransaction, which then calls the apps server and does the subscription receipt verification with the App Store. Like this:

    - (void)recordTransaction: (SKPaymentTransaction *)transaction 
    {
        [self subscribeWithTransaction:transaction];
    }
    
    
    - (void)subscribeWithTransaction:(SKPaymentTransaction*)transaction {
    
        NSData *receiptData = [transaction transactionReceipt];
        NSString *receiptEncoded = [Kriya base64encode:(uint8_t*)receiptData.bytes length:receiptData.length];//encode to base64 before sending
    
        NSString *urlString = [NSString stringWithFormat:@"%@/api/%@/%@/subscribe", [Kriya server_url], APP_ID, [Kriya deviceId]];
    
        NSURL *url = [NSURL URLWithString:urlString];
        ASIFormDataRequest *request = [[[ASIFormDataRequest alloc] initWithURL:url] autorelease];
        [request setPostValue:[[transaction payment] productIdentifier] forKey:@"product"];
        [request setPostValue:receiptEncoded forKey:@"receipt"];
        [request setPostValue:[Kriya deviceModelString] forKey:@"model"];
        [request setPostValue:[Kriya deviceiOSString] forKey:@"ios"];
        [request setPostValue:[appDelegate version] forKey:@"v"];
    
        [request setDidFinishSelector:@selector(subscribeWithTransactionFinished:)];
        [request setDidFailSelector:@selector(subscribeWithTransactionFailed:)];
        [request setDelegate:self];
    
        [request startAsynchronous];
    
    }
    

    Previously my code was trying to call finishTransaction only after my server verified the receipt, but by then the transaction was somehow lost already. so just make sure to finishTransaction as soon as possible.

    Also another problem one can run into is the fact, that when the app is in the sandbox it calls the sandbox App Store verification url, but when it is in review, it is somehow between worlds. So i had to change my server code like this:

    APPLE_SHARED_PASS = "83f1ec5e7d864e89beef4d2402091cd0" #you can get this in iTunes Connect
    APPLE_RECEIPT_VERIFY_URL_SANDBOX    = "https://sandbox.itunes.apple.com/verifyReceipt"
    APPLE_RECEIPT_VERIFY_URL_PRODUCTION = "https://buy.itunes.apple.com/verifyReceipt"
    
      def self.verify_receipt_for(b64_receipt, receipt_verify_url)
        json_resp = nil
        url = URI.parse(receipt_verify_url)
        http = Net::HTTP.new(url.host, url.port)
        http.use_ssl = true
        http.verify_mode = OpenSSL::SSL::VERIFY_NONE
        json_request = {'receipt-data' => b64_receipt, 'password' => APPLE_SHARED_PASS}.to_json
        resp, resp_body = http.post(url.path, json_request.to_s, {'Content-Type' => 'application/x-www-form-urlencoded'})
        if resp.code == '200'
          json_resp = JSON.parse(resp_body)
        end
        json_resp
    end
    
    def self.verify_receipt(b64_receipt)
        json_resp = Subscription.verify_receipt_for(b64_receipt, APPLE_RECEIPT_VERIFY_URL_PRODUCTION)
        if json_resp!=nil
          if json_resp.kind_of? Hash
            if json_resp['status']==21007 
              #try the sandbox then
              json_resp = Subscription.verify_receipt_for(b64_receipt, APPLE_RECEIPT_VERIFY_URL_SANDBOX)
            end
          end
        end
        json_resp
    end
    

    So basically one always verifies with the production URL, but if it returns 21007 code, then it means a sandbox receipt was sent to the production URL and then one simply tries again with the sandbox URL. This way your app works the same in sandbox and production mode.

    And finally Apple wanted me to add a RESTORE button next to the subscription buttons, to handle the case of multiple devices owned by one user. This button then calls [[SKPaymentQueue defaultQueue] restoreCompletedTransactions]; and the app will be deliver with restored transactions (if any).

    Also, sometimes the test user accounts get contaminated somehow and things stop working and you may get a “Can not connect to iTunes store” message when subscribing. It helps to create a new test user.

    Here is the rest of the relevant code:

    - (void) restoreTransaction: (SKPaymentTransaction *)transaction
    {
        [self recordTransaction: transaction];
        [[SKPaymentQueue defaultQueue] finishTransaction: transaction]; 
    }
    
    - (void) failedTransaction: (SKPaymentTransaction *)transaction
    {
        if (transaction.error.code == SKErrorPaymentCancelled)
        {
            //present error to user here 
        }
        [[SKPaymentQueue defaultQueue] finishTransaction: transaction];    
    

    }

    I wish you a smooth InAppPurchase programming experience. 🙂

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I have finally figured out how to use the apple Reachability files, which is
I have an app based on Apple's PageControl sample. The first time the view
Finally, thanks to most of you, I got my first app approved by Apple.
I have read the Apple documentation. They list the apps registered, yet in their
I have been reading about exception handling on the Apple developer docs , but
So, after several hours of reading the Apple walkthrough I finally managed to deploy
I have managed (finally) to send something (a picture) to my server. This has
Following Apple's instructions, I cannot upload my app to the Mac App Store. Symptoms:
I'm a newborn developer for iPad, I finally finished an app and I want
I have a data gathering app (terrestrial magnetic field strength) that has four phases;

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.