0

I'm in the process of setting up receipt validation for Apple's auto-renewable subscriptions on our server and noticed some inconsistencies with the official documentation. When verifying a sandbox receipt with the sandbox verifyReceipt endpoint, the response looks as follows:

{  
  "auto_renew_status": 1,  
  "status": 0,  
  "auto_renew_product_id": "app.xxx",  
  "receipt": {  
    "original_purchase_date_pst": "2020-03-18 01:11:45 America/Los_Angeles",  
    "quantity": "1",  
    "unique_vendor_identifier": "6D2xxx194",  
    "bvrs": "2",  
    "expires_date_formatted": "2020-03-20 12:27:07 Etc/GMT",  
    "is_in_intro_offer_period": "false",  
    "purchase_date_ms": "1584703627636",  
    "expires_date_formatted_pst": "2020-03-20 05:27:07 America/Los_Angeles",  
    "is_trial_period": "false",  
    "item_id": "15xxx27",  
    "unique_identifier": "cd5xxx424",  
    "original_transaction_id": "100xxx735",  
    "subscription_group_identifier": "20xxx02",  
    "transaction_id": "100xxx439",  
    "web_order_line_item_id": "100xxx419",  
    "version_external_identifier": "0",  
    "purchase_date": "2020-03-20 11:27:07 Etc/GMT",  
    "product_id": "app.xxx",  
    "expires_date": "1584707227636",  
    "original_purchase_date": "2020-03-18 08:11:45 Etc/GMT",  
    "purchase_date_pst": "2020-03-20 04:27:07 America/Los_Angeles",  
    "bid": "app.xxx",  
    "original_purchase_date_ms": "1584519105000"  
  },  
  "latest_receipt_info": {  
    "original_purchase_date_pst": "2020-03-18 01:11:45 America/Los_Angeles",  
    "quantity": "1",  
    "unique_vendor_identifier": "6D2xxx194",  
    "bvrs": "2",  
    "expires_date_formatted": "2020-03-20 12:27:07 Etc/GMT",  
    "is_in_intro_offer_period": "false",  
    "purchase_date_ms": "1584703627000",  
    "expires_date_formatted_pst": "2020-03-20 05:27:07 America/Los_Angeles",  
    "is_trial_period": "false",  
    "item_id": "15xxx27",  
    "unique_identifier": "cd5xxx424",  
    "original_transaction_id": "100xxx735",  
    "subscription_group_identifier": "20xxx02",  
    "transaction_id": "100xxx439",  
    "bid": "app.xxx",  
    "web_order_line_item_id": "100xxx419",  
    "purchase_date": "2020-03-20 11:27:07 Etc/GMT",  
    "product_id": "app.xxx",  
    "expires_date": "1584707227000",  
    "original_purchase_date": "2020-03-18 08:11:45 Etc/GMT",  
    "purchase_date_pst": "2020-03-20 04:27:07 America/Los_Angeles",  
    "original_purchase_date_ms": "1584519105000"  
  },  
  "latest_receipt": "xxx"  
} 

I especially want to point out the following fields of that response:

{  
    ...  
  "latest_receipt_info": {  
      ...  
    "expires_date": "1584707227000",  
    "expires_date_formatted": "2020-03-20 12:27:07 Etc/GMT",  
    "expires_date_formatted_pst": "2020-03-20 05:27:07 America/Los_Angeles",  
    "subscription_group_identifier": "20xxx02",  
    "bid": "app.xxx",  
      ...  
  },  
  "receipt": {  
      ...  
    "expires_date": "1584707227636",  
    "expires_date_formatted": "2020-03-20 12:27:07 Etc/GMT",  
    "expires_date_formatted_pst": "2020-03-20 05:27:07 America/Los_Angeles",  
    "subscription_group_identifier": "20xxx02",  
    "bid": "app.xxx",  
      ...  
  },  
    ...  
} 

The inconsistencies with the official documentation are:

  1. latest_receipt_info is documented to be an array, however, it is a single json object.
  2. In the latest_receipt_info, the expires_date is not in "date-time format similar to the ISO 8601" as the documentation says, but looks like it is in milliseconds since epoch (what should be the expires_date_ms). However, we can find the key expires_date_formatted that is in date-time format.
  3. The same fields as in (2) can be also found in the receipt, however, the documentation states only a key expiration_date (analogue to the expires_date in the latest_receipt_info in date-time format) and expiration_date_ms (in milliseconds since epoch).
  4. The documented bundle_id key (here and here) is not present, but a key bid is, that contains the bundle id.
  5. The key subscription_group_identifer does not contain the exact string entered in AppStoreConnect as subscription group identifer, as documented (here and here), but contains some integer value.

So according to the documentation, the response should look like this, for me:

{  
    ...  
  "latest_receipt_info": [  
    {  
        ...  
      "expires_date": "2020-03-20 12:27:07 Etc/GMT",  
      "expires_date_ms": "1584707227000",  
      "expires_date_pst": "2020-03-20 05:27:07 America/Los_Angeles",  
      "subscription_group_identifier": "MY_SUBSCRIPTION_GROUP_ID",  
      "bundle_id": "app.xxx",  
        ...  
    }  
  ],  
  "receipt": {  
      ...  
    "expiration_date": "2020-03-20 12:27:07 Etc/GMT",  
    "expiration_date_ms": "1584707227636",  
    "expiration_date_pst": "2020-03-20 05:27:07 America/Los_Angeles",  
    "subscription_group_identifier": "MY_SUBSCRIPTION_GROUP_ID",  
    "bundle_id": "app.xxx",  
      ...  
  },  
    ...  
}  
  • I am not sure how to cope with that situation, is that a bug in the API or is the documentation simply wrong?
  • Can I expect the same inconsistencies for the production endpoint (can someone share a sample response please)?
  • How about the notifications in server-to-server notifications, are there also inconsistencies?

Thanks in advance!

luke77
  • 2,255
  • 2
  • 18
  • 30
j4rv1s
  • 23
  • 6

2 Answers2

0

Where did you get that receipt example? Here is a proper receipt example from verifyReceipt endoint: https://gist.github.com/ren6/3da2d14ea629ab9add489c0e6df1917c

Also I can recommend you reading article from our blog: https://blog.apphud.com/receipt-validation/

Regarding Apple server-to-server notifications, they are now unified, i.e. data is being returned in the same structure as from verifyReceipt endpoint.

apphud
  • 625
  • 4
  • 8
  • Thank you for the example! Indeed, it is completely different to the response I got. However, I got the response after sending a request myself to the sandbox verifyReceipt endpoint with a Base64 encoded receipt. The receipt was sent to my server after making a purchase in a Nativescript Frontend using the latest version of the [Nativescript Purchase Plugin](https://npm.proplugins.org/-/web/detail/@proplugins/nativescript-purchase). The observed behaviour is consistent over several days and several attempts with different sandbox purchases. – j4rv1s Mar 24 '20 at 10:34
0

For everyone that faces the same problem: We sent the wrong receipt data to our backend since we requested the receipt via the deprecated transactionReceipt and not via appStoreReceiptURL.

Community
  • 1
  • 1
j4rv1s
  • 23
  • 6