27

I'm getting 2 kinds of receipt formats from Apple when i try to verify purchases on the server.

Any idea what's the difference ?

1)

  content: {
    status: 0,
    receipt: {
      item_id: "662554154",
      original_purchase_date: "2012-10-12 08:32:12 Etc/GMT",
      purchase_date_pst: "2012-10-12 01:32:12 America/Los_Angeles",
      purchase_date: "2012-10-12 08:32:12 Etc/GMT",
      product_id: "com.example.mygame.tool1",
      bid: "com.example.mygame",
      version_external_identifier: "5647854",
      bvrs: "1.0",
      quantity: "1",
      transaction_id: "8844567822225544",
      app_item_id: "659563252",
      original_purchase_date_ms: "1350030732000",
      original_transaction_id: "8844567822225544",
      purchase_date_ms: "1350030732000",
      original_purchase_date_pst: "2012-10-12 01:32:12 America/Los_Angeles"
    }
  }

2)

content: {
  receipt: {
    in_app: [
      {
        is_trial_period: "false",
        original_purchase_date_pst: "2013-10-09 20:55:27 America/Los_Angeles",
        original_purchase_date_ms: "1386571707000",
        original_purchase_date: "2013-10-09 04:55:27 Etc/GMT",
        purchase_date_pst: "2013-10-09 20:55:27 America/Los_Angeles",
        purchase_date_ms: "1386571707000",
        purchase_date: "2013-10-09 04:55:27 Etc/GMT",
        original_transaction_id: "654888452251325",
        transaction_id: "654888452251325",
        product_id: "com.example.mygame.tool1",
        quantity: "1"
      }
    ],
    original_application_version: "1.0",
    original_purchase_date_pst: "2013-10-09 20:55:27 America/Los_Angeles",
    original_purchase_date_ms: "1386569706000",
    original_purchase_date: "2013-10-09 04:55:27 Etc/GMT",
    request_date_pst: "2013-10-09 20:55:27 America/Los_Angeles",
    request_date_ms: "1386571710087",
    request_date: "2013-10-09 04:55:27 Etc/GMT",
    download_id: 215425636588954,
    application_version: "1.0",
    bundle_id: "com.example.mygame",
    adam_id: 654225311,
    receipt_type: "Sandbox"
  },
  environment: "Sandbox",
  status: 0
}
refaelos
  • 7,927
  • 7
  • 36
  • 55
  • Question I have... the _ms timestamps are not unix timestamps are they? When converting `1386571707000` you get `Wed, 16 Sep 45908 15:30:00 GMT` How the hell does apple want us to validate purchased timeframe? – Cmag Oct 02 '14 at 16:27
  • @Cmag The timestamp is in ms, you have to divide it by 1000 – cache.zero Apr 14 '15 at 13:27
  • https://developer.apple.com/library/archive/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateRemotely.html#//apple_ref/doc/uid/TP40010573-CH104-SW1 – LF00 Aug 22 '19 at 08:39

1 Answers1

30

In iOS 6 each IAP (in-app purchase) transaction would have its own receipt (SKPaymentTransaction.transactionReceipt in the StoreKit API). When you send this receipt data over to their validation API, you get the former response.

In iOS 7, Apple has started using something they call the “Grand Unified Receipt”. This means that apps have one receipt that contains information about the purchase of the app itself, as well as IAPs. You use the -[NSBundle appStoreReceiptURL] API to load this receipt data from disk (and possibly SKReceiptRefreshRequest to get it if it doesn't seem to exist). When you send this receipt data over to their validation API, you get the latter response.

The main difference is that the former receipt format represents one IAP transaction, while the latter represents an array of them (as well as the purchase of the application itself).

See more info in the “Using Receipts to Protect Your Digital Sales” WWDC 2013 session.

hasseg
  • 6,787
  • 37
  • 41
  • These receipts are returned from Apple's validation service. Does it return a receipt according to the iOS version on the device? – refaelos Dec 09 '13 at 16:42
  • The _receipt itself_ originates from the device — iOS 6 devices get it from `SKPaymentTransaction` and iOS 7 devices by reading the contents of the file located at `-[NSBundle appStoreReceiptURL]`. The device then sends the receipt to a server that performs the validation by forwarding the receipt to Apple's validation service, which responds with either of the two examples in the original question (depending on whether the receipt is a "classic" iOS 6 receipt, or an iOS 7+ "Grand Unified Receipt"). – hasseg Dec 10 '13 at 09:54
  • Ok. Thanks. But why don't i get an 'environment' indication ? – refaelos Dec 10 '13 at 10:54
  • Does anyone know what means field is_trial_period: "false", why it always false ? – viq Jul 02 '15 at 12:02
  • The field is_trial_period is for subscriptions. It will be set to true during the trial period (either 1 week or 1 month) which is applied at the beginning if this option is used. See the options for subscription IAPs in iTunes Connect. – Simon Tillson Nov 02 '15 at 12:07
  • @refaelos In sandbox test account auto-renewable subscription successfully excuted ( initial transaction and + 5 renews after it ) but after that i can not get latest_expired_receipt_info so how I can validate that auto-renewable subscription is expired In Response I get status,environment,receipt,latest_receipt,latest_receipt_info I did not get latest_expired_receipt_info – Ankur Patel Jun 21 '17 at 11:39
  • @SimonTillson In sandbox test account auto-renewable subscription successfully excuted ( initial transaction and + 5 renews after it ) but after that i can not get latest_expired_receipt_info so how I can validate that auto-renewable subscription is expired In Response I get status,environment,receipt,latest_receipt,latest_receipt_info I did not get latest_expired_receipt_info – Ankur Patel Jun 21 '17 at 11:40
  • @AnkurPatel I'm not sure, mate. Maybe you should ask a new question and provide as much detail as possible so that others may help you. Good luck. – Simon Tillson Jul 04 '17 at 11:29
  • @hasseg so then how do we validate the most current purchase if it keeps the users entire purchase history?! – Famic Tech Nov 17 '17 at 14:25