Apple iTunes In-app purchase verification tool

Overview

itunes-iap v2

Python 2 & 3 compatible! Even with :mod:`asyncio` support!

https://travis-ci.org/youknowone/itunes-iap.svg?branch=master https://coveralls.io/repos/github/youknowone/itunes-iap/badge.svg?branch=master

Quickstart

Create request to create a request to itunes verifying api.

>>> import itunesiap
>>> try:
>>>     response = itunesiap.verify(raw_data)  # base64-encoded data
>>> except itunesiap.exc.InvalidReceipt as e:
>>>     print('invalid receipt')
>>> print response.receipt.last_in_app.product_id  # other values are also available as property!
The common attributes are:
product_id, original_transaction_id and quantity.
See the full document in:

asyncio

>>> import itunesiap
>>> response = await itunesiap.aioverify(raw_data)  # verify -> aioverify

The other parts are the same.

See the full document in:

Installation

PyPI is the recommended way.

$ pip install itunes-iap
To browse versions and tarballs, visit:
https://pypi.python.org/pypi/itunes-iap/

Apple in-review mode

In review mode, your actual users who use older versions want to verify in production server but the reviewers in Apple office want to verify in sandbox server.

Note: The default env is production mode which doesn't allow any sandbox verifications.

You can change the verifying mode by specifying env.

>>> # review mode
>>> itunesiap.verify(raw_data, env=itunesiap.env.review)

Note for v1 users

There was breaking changes between v1 and v2 APIs.

  • Specify version 0.6.6 for latest v1 API when you don't need new APIs.
  • Or use import itunesiap.legacy as itunesiap instead of import itunesiap. (from itunesiap import xxx to from itunesiap.legacy import xxx)

Contributors

See https://github.com/youknowone/itunes-iap/graphs/contributors

Comments
  • Support exclude-old-transactions Request parameter

    Support exclude-old-transactions Request parameter

    This adds support for sending the exclude-old-transactions Request parameter to App Store receipt validation.

    Apple Docs https://developer.apple.com/library/content/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateRemotely.html

    opened by brandon-clair 9
  • IndexError: pop index out of range

    IndexError: pop index out of range

    I'm getting the following error when trying to validate in sandbox mode:

    Internal Server Error: /api/validate/
    Traceback (most recent call last):
      File "/Users/hanleyhansen/.virtualenvs/mkl/lib/python2.7/site-packages/django/core/handlers/base.py", line 149, in get_response
        response = self.process_exception_by_middleware(e, request)
      File "/Users/hanleyhansen/.virtualenvs/mkl/lib/python2.7/site-packages/django/core/handlers/base.py", line 147, in get_response
        response = wrapped_callback(request, *callback_args, **callback_kwargs)
      File "/Users/hanleyhansen/.virtualenvs/mkl/lib/python2.7/site-packages/django/views/decorators/csrf.py", line 58, in wrapped_view
        return view_func(*args, **kwargs)
      File "/Users/hanleyhansen/Google Drive/Work/Projects/git/mkl-web/mkl/views/api_views.py", line 99, in validate
        response = itunesiap.verify(receipt_data, IAP_SHARED_SECRET)
      File "/Users/hanleyhansen/.virtualenvs/mkl/lib/python2.7/site-packages/itunesiap/environment.py", line 39, in __exit__
        self._stack.pop(self._ctx_id)
    IndexError: pop index out of range
    

    Any ideas?

    Here is my code:

        try:
            if IAP_SANDBOX:
                with itunesiap.env.sandbox:
                    response = itunesiap.verify(receipt_data, IAP_SHARED_SECRET)
            else:
                with itunesiap.env.default:
                    response = itunesiap.verify(receipt_data, IAP_SHARED_SECRET)
        except itunesiap.exc.InvalidReceipt as e:
            return HttpResponseForbidden({'message': 'not valid', 'error': e}, content_type='application/json')
    
    opened by hanleyhansen 8
  • Why can't get latest_receipt_info

    Why can't get latest_receipt_info

    Following the Official Document: https://developer.apple.com/library/content/releasenotes/General/ValidateAppStoreReceipt/Chapters/ReceiptFields.html#//apple_ref/doc/uid/TP40010573-CH106-SW1

    There should be a latest_receipt_info data in response, but we can't directly get this attribute from the response

    opened by vincentwyshan 7
  • Allow providing an override env in Request.verify

    Allow providing an override env in Request.verify

    Enable specifying an explicit override environment "env" in the Request.verify() and call in order to avoid a pop from the environment stack. This makes cases with thread concurrency deterministic and avoids the Environment.current() stack access.

    Example:

    import itunesiap
    response = itunesiap.verify(receipt, apple_shared_secret, env=itunesiap.env.production)
    
    opened by mmeisinger 7
  • Proposed bugfix for calling response.receipt.in_app resulting in an error

    Proposed bugfix for calling response.receipt.in_app resulting in an error

    This pull request provides a proposed solution for calling response.receipt.in_app in the new receipt format. It also produces a uniform return type for python2 and python3

    opened by dlm 6
  • Installation of 2.5.0 fails on python2

    Installation of 2.5.0 fails on python2

    After the update to 2.5.0 itunes-iap cannot be upgraded anymore on python versions <3.4.2. pip2 install --upgrade itunes-iap tries to install aiohttp, which fails:

    [...]
    Collecting aiohttp (from itunes-iap)
      1 location(s) to search for versions of aiohttp:
      * https://pypi.python.org/simple/aiohttp/
      Getting page https://pypi.python.org/simple/aiohttp/
      Looking up "https://pypi.python.org/simple/aiohttp/" in the cache
      Current age based on date: 311
      Freshness lifetime from max-age: 600
      Freshness lifetime from request max-age: 600
      The response is "fresh", returning cached response
      600 > 311
      Analyzing links from page https://pypi.python.org/simple/aiohttp/
      [...]
      Using version 2.2.3 (newest of versions: 0.1, 0.2, 0.3, 0.4, 0.4.1, 0.4.2, 0.4.3, 0.4.4, 0.5.0, 0.6.0, 0.6.1, 0.6.2, 0.6.3, 0.6.4, 0.6.5,$
      Looking up "https://pypi.python.org/packages/9b/3a/b560a411b97203fb20b5eee084c1e292862b3092029d9d9faaa8714797fa/aiohttp-2.2.3.tar.gz" in $
      Current age based on date: 108202
      Freshness lifetime from max-age: 31557600
      The response is "fresh", returning cached response
      31557600 > 108202
      Using cached aiohttp-2.2.3.tar.gz
      Downloading from URL https://pypi.python.org/packages/9b/3a/b560a411b97203fb20b5eee084c1e292862b3092029d9d9faaa8714797fa/aiohttp-2.2.3.ta$
      Running setup.py (path:/tmp/pip-build-DwBsrd/aiohttp/setup.py) egg_info for package aiohttp
        Running command python setup.py egg_info
        Traceback (most recent call last):
          File "<string>", line 1, in <module>
          File "/tmp/pip-build-DwBsrd/aiohttp/setup.py", line 66, in <module>
            raise RuntimeError("aiohttp requires Python 3.4.2+")
        RuntimeError: aiohttp requires Python 3.4.2+
    Cleaning up...
    Exception information:
    Traceback (most recent call last):
      File "/home/prettyvanilla/.local/share/virtualenvs/bikemap/lib/python2.7/site-packages/pip/basecommand.py", line 215, in main
        status = self.run(options, args)
      File "/home/prettyvanilla/.local/share/virtualenvs/bikemap/lib/python2.7/site-packages/pip/commands/install.py", line 335, in run
        wb.build(autobuilding=True)
      File "/home/prettyvanilla/.local/share/virtualenvs/bikemap/lib/python2.7/site-packages/pip/wheel.py", line 749, in build
        self.requirement_set.prepare_files(self.finder)
      File "/home/prettyvanilla/.local/share/virtualenvs/bikemap/lib/python2.7/site-packages/pip/req/req_set.py", line 380, in prepare_files
        ignore_dependencies=self.ignore_dependencies))
      File "/home/prettyvanilla/.local/share/virtualenvs/bikemap/lib/python2.7/site-packages/pip/req/req_set.py", line 634, in _prepare_file
        abstract_dist.prep_for_dist()
      File "/home/prettyvanilla/.local/share/virtualenvs/bikemap/lib/python2.7/site-packages/pip/req/req_set.py", line 129, in prep_for_dist
        self.req_to_install.run_egg_info()
      File "/home/prettyvanilla/.local/share/virtualenvs/bikemap/lib/python2.7/site-packages/pip/req/req_install.py", line 439, in run_egg_info
        command_desc='python setup.py egg_info')
      File "/home/prettyvanilla/.local/share/virtualenvs/bikemap/lib/python2.7/site-packages/pip/utils/__init__.py", line 707, in call_subproce$
        % (command_desc, proc.returncode, cwd))
    InstallationError: Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-build-DwBsrd/aiohttp/
    

    Most likely the conditional in setup.py isn't working the way you'd expect when using wheels, instead environment markers seem to be the recommended way now: https://wheel.readthedocs.io/en/latest/#defining-conditional-dependencies

    opened by prettyv 5
  • Failback to sandbox only on specific status

    Failback to sandbox only on specific status

    According to iTunes documentation, their production API will return specific status in case when we are sending transaction raw data from their sandbox's environment: https://developer.apple.com/library/ios/technotes/tn2413/_index.html#//apple_ref/doc/uid/DTS40016228-CH1-RECEIPTURL

    Hence, we do not need to send any other failed transactions (those which returned status other than 21007) to sandbox in case when both production and sandbox environments are used.

    Note: while testing on my machine (excluding py2.6, 3.3 and pypi) I got FAIL for py27 in test_receipt, line assert isinstance(in_app0.original_purchase_date_ms, int) - 1432002585000L is not an int (if applicable, I'm using 32bit OS).

    opened by kmitrovic 5
  • On python 3.4 asyncio.coroutines will traceback with AttributeError …

    On python 3.4 asyncio.coroutines will traceback with AttributeError …

    …so use the alternative requests.

    Traceback (most recent call last): File "/home/silver/.local/share/virtualenvs/silver/lib/python3.4/site-packages/my_project/iap.py", line 6, in import itunesiap File "/home/silver/.local/share/virtualenvs/silver/lib/python3.4/site-packages/itunesiap/init.py", line 13, in from .request import Request File "/home/silver/.local/share/virtualenvs/silver/lib/python3.4/site-packages/itunesiap/request.py", line 6, in from itunesiap.verify_aiohttp import AiohttpVerify File "/home/silver/.local/share/virtualenvs/silver/lib/python3.4/site-packages/itunesiap/verify_aiohttp.py", line 3, in import aiohttp File "/home/silver/.local/share/virtualenvs/silver/lib/python3.4/site-packages/aiohttp/init.py", line 6, in from .client import * # noqa File "/home/silver/.local/share/virtualenvs/silver/lib/python3.4/site-packages/aiohttp/client.py", line 15, in from . import connector as connector_mod File "/home/silver/.local/share/virtualenvs/silver/lib/python3.4/site-packages/aiohttp/connector.py", line 13, in from . import hdrs, helpers File "/home/silver/.local/share/virtualenvs/silver/lib/python3.4/site-packages/aiohttp/helpers.py", line 142, in coroutines = asyncio.coroutines AttributeError: 'module' object has no attribute 'coroutines'

    opened by MihaiBalint 4
  • receipt.last_in_app is not the latest purchase

    receipt.last_in_app is not the latest purchase

    I'm not sure if this issue is an Apple problem or my my incorrect interpretation of how the receipt validation process works or a shortcoming of itunes-iap.

    If I send a receipt to get validated and get back a response and then do a response.receipt.last_in_app I get the last purchase in the in_app array contained in the receipt. The problem is that this is not the latest purchase if the receipt hasn't been refreshed on the device. Since I'm handling subscriptions I will be periodically checking the receipt from the server and do not have the ability to refresh the receipt (at least I don't think I can).

    The latest purchase information is however contained in 'latest_receipt_info' of the receipt and Pablo Rivera pointed out how to obtain this in his wiki post https://github.com/youknowone/itunes-iap/wiki/Getting-the-receipt-with-the-latest-expiration-date by doing response._.get('latest_receipt_info') you can get access to this information. However this is just the raw dictionary of the data and then I need to parse it manually which is all nicely done for the in_app part by itunes-iap.

    So my question is, when validating a receipt, is there a way to always get the last purchase history in the in_app part or if not, could itunes-iap be changed in a way to more natively access 'last_receipt_info'? I've already worked around this but I'd like to know if I'm doing something wrong or there is an easier way to do this.

    opened by jeffjvick 4
  • Proposal for encapsulating requests errors and provide user option for verifing ssl certs

    Proposal for encapsulating requests errors and provide user option for verifing ssl certs

    The original goal was to all the user to specify an option for verifying ssl certs. (relevant to issue #16)

    In the process, I ended up encapsulating the requests errors within itunes-iap.

    opened by dlm 4
  • Example doesn't work as InvalidReceipt is not imported in itunesiap/__init__.py

    Example doesn't work as InvalidReceipt is not imported in itunesiap/__init__.py

    As the title pretty much.

    The line in question is incorrect in the current state:

    >>> from itunesiap import Request, InvalidReceipt
    

    Happy to make a pull request but I'm not sure whether you:

    a) want to import that exception in the __init__.py b) change the example to import from the correct location (exceptions.py).

    Let me know, happy to do so.

    opened by djm 4
  • Aioverify error

    Aioverify error

    response = await itunesiap.aioverify(receipt, env=itunesiap.env.review, password="xxx")

                   ^
    SyntaxError: 'await' outside function
    

    How can I solve this error?

    opened by xiaohange 0
  • recruiting maintainer

    recruiting maintainer

    Hello,

    I didn't develop iOS app with in-app purchase for very long time. I maintained this project depends on patches for a few more years, but it seems not very responsible.

    Anyone who interested in this project contact me please.

    Thanks

    opened by youknowone 0
  • Error install with python version 3.5.2

    Error install with python version 3.5.2

    Getting this dependency error, going to do a manual workaround for now but thought I would let you know

    Could not find a version that satisfies the requirement aiohttp>=3.0.1 (from itunes-iap) (from versions: 0.1, 0.2, 0.3, 0.4, 0.4.1, 0.4.2, 0.4.3, 0.4.4, 0.5.0, 0.6.0, 0.6.1, 0.6.2, 0.6.3, 0.6.4, 0.6.5, 0.7.0, 0.7.1, 0.7.2, 0.7.3, 0.8.0, 0.8.1, 0.8.2, 0.8.3, 0.8.4, 0.9.0, 0.9.1, 0.9.2, 0.9.3, 0.10.0, 0.10.1, 0.10.2, 0.11.0, 0.12.0, 0.13.0, 0.13.1, 0.14.0, 0.14.1, 0.14.2, 0.14.3, 0.14.4, 0.15.0, 0.15.1, 0.15.2, 0.15.3, 0.16.0, 0.16.1, 0.16.2, 0.16.3, 0.16.4, 0.16.5, 0.16.6, 0.17.0, 0.17.1, 0.17.2, 0.17.3, 0.17.4, 0.18.0, 0.18.1, 0.18.2, 0.18.3, 0.18.4, 0.19.0, 0.20.0, 0.20.1, 0.20.2, 0.21.0, 0.21.1, 0.21.2, 0.21.4, 0.21.5, 0.21.6, 0.22.0a0, 0.22.0b0, 0.22.0b1, 0.22.0b2, 0.22.0b3, 0.22.0b4, 0.22.0b5, 0.22.0b6, 0.22.0, 0.22.1, 0.22.2, 0.22.3, 0.22.4, 0.22.5, 1.0.0, 1.0.1, 1.0.2, 1.0.3, 1.0.5, 1.1.0, 1.1.1, 1.1.2, 1.1.3, 1.1.4, 1.1.5, 1.1.6, 1.2.0, 1.3.0, 1.3.1, 1.3.2, 1.3.3, 1.3.4, 1.3.5, 2.0.0rc1, 2.0.0, 2.0.1, 2.0.2, 2.0.3, 2.0.4, 2.0.5, 2.0.6, 2.0.6.post1, 2.0.7, 2.1.0, 2.2.0, 2.2.1, 2.2.2, 2.2.3, 2.2.4, 2.2.5, 2.3.0a1, 2.3.0a2, 2.3.0a4, 2.3.0, 2.3.1a1, 2.3.1, 2.3.2b2, 2.3.2b3, 2.3.2, 2.3.3, 2.3.4, 2.3.5, 2.3.6, 2.3.7, 2.3.8, 2.3.9, 2.3.10, 3.0.0b0) No matching distribution found for aiohttp>=3.0.1 (from itunes-iap)

    opened by wdifruscio 1
  • IndexError when exiting context manager

    IndexError when exiting context manager

    I'm experiencing a similar IndexError in one of my api views when using itunesiap.env.sandbox context manager:

    # ...
    if sandbox:
        with itunesiap.env.sandbox:
            try:
                response = itunesiap.verify(raw_data, use_sandbox=True)
                return True, response
            except (ItunesServerNotAvailable, ItunesServerNotReachable):
                no_response = True
            except itunesiap.exc.InvalidReceipt as exc:
                error = exc.description
    

    Sentry actually indicates the error/exception being raised when exiting the contextmanager:

    itunesiap/environment.py in __exit__ at line 42
            self._ctx_id = len(self._stack)
            self.push()
            return self
        def __exit__(self, exc_type, exc_value, tb):
            self._stack.pop(self._ctx_id)  # this line
    

    Any clues on what might be happening?

    opened by maccinza 1
  • IndexError: list index out of range

    IndexError: list index out of range

    Hello. We got this problem with itunes-iap 2.5

    [2017-11-08 15:00:20,934] [ERROR] views.py:3308 - root: list index out of range
    Traceback (most recent call last):
      File "/home/django/atcontrol/releases/1510061996/mayak/api_v3/views.py", line 3243, in purchase_ios
        log.info(res.receipt.last_in_app)
      File "/home/django/atcontrol/releases/1510061996/venv/local/lib/python2.7/site-packages/itunesiap/receipt.py", line 245, in last_in_app	
        self.in_app, key=lambda x: x['original_purchase_date_ms'])[-1]
    IndexError: list index out of range
    

    part of view from our django rest framework api with problem line of code

    @api_view(['POST'])
    def purchase_ios(request):
        log.info('purchase_ios (%s) POST: %s' % (request.user, request.POST))
        try:
            res = itunesiap.verify(request.POST.get("receipt", None), settings.ITUNES_PASSWORD, verify_ssl=False,
                                   use_production=True, use_sandbox=True)
            log.info(res.receipt.last_in_app)
    ...
    

    Any ideas what's wrong?

    opened by aaksarin 7
Releases(2.5.0)
Collection of script to manage WLED devices

Collection of script to manage WLED devices

Daniel Poelzleithner 4 Sep 26, 2022
Force-Subscribe-Bot - A Telegram Bot to force users to join a specific channel before sending messages in a group

Introduction A Telegram Bot to force users to join a specific channel before sen

LG Bot Updates 0 Jan 16, 2022
Telegram Bot to check covid vaccine slot availability on CoWin site

Cowin Assist Telegram Bot Check the bot here @cowinassistbot. This is a simple Telegram bot to Check slots availability Get an alert when slots become

32 Jun 21, 2022
A client library for the REST API of DocuWare's DMS

docuware-client This is a client library for the REST API of DocuWare DMS. Since DocuWare's documentation regarding the REST API is very sparse (at th

Stefan Schönberger 1 Feb 23, 2022
API RestFull web de pontos turisticos de certa região

##RESTful Web API para exposição de pontos turísticos de uma região## Propor um novo ponto turístico Moderação dos pontos turísticos cadastrados Lista

Lucas Silva 2 Jan 28, 2022
Send Informative, Concise Slack Notifications With Minimal Effort

slack-templates Send Informative, Concise Slack Notifications With Minimal Effort slack-templates Slack Integration Available Templates Usage Report t

9 Nov 03, 2022
Visual Weather api. Returns beautiful pictures with the current weather.

VWapi Visual Weather api. Returns beautiful pictures with the current weather. Installation: sudo apt update -y && sudo apt upgrade -y sudo apt instal

Hotaru 33 Nov 13, 2022
Powerful Telegram Maintained UserBot in Telethon

Fire-X UserBot The Awaited Bot Fire-X userbot The Most Powerful Telegram Userbot. This Userbot is Safe to use in Your Telegram Account. It is not like

22 Oct 21, 2022
Python client and module for BGP Ranking

Python client and module for BGP Ranking THis project will make querying BGP Ranking easier. Installation pip install pybgpranking Usage Command line

D4 project 3 Dec 16, 2021
Create Multiple CF entry for multiple websites

AWS-CloudFront Problem: Deploy multiple CloudFront for account with multiple domains. Functionality: Running this script in loop and deploy CloudFront

Giten Mitra 5 Nov 18, 2022
A Discord bot written in Python to help with guild administration

forgotten-hydra A Discord bot written in Python to help with guild administration. External libraries Pycord-Development/pycord 1.7.3 djc/couchdb-pyth

1 May 14, 2022
Telegram Bot to learn English by words and more.. ( in Arabic )

Get the mp3 files Extract the mp3.rar on the same file that bot.py on install requirements pip install -r requirements.txt #Then enter you bot token

Plugin 10 Feb 19, 2022
Automatically gets clips from twitch streams and uploads them to a YouTube channel.

Twitch Stream Highlights to YT Automatic Uploader (AutoBot Clipper) This script can be used to automatically extract highlights (or clips) from a twit

Teja Swaroop 57 Dec 12, 2022
Python bindings for BigML.io

BigML Python Bindings BigML makes machine learning easy by taking care of the details required to add data-driven decisions and predictive power to yo

BigML Inc, Machine Learning made easy 271 Dec 27, 2022
Ark API Wrapper in Python

Pythark Ark API Wrapper in Python. Built with Python Requests Installation Pythark uses Arky to create a new transaction, if you want to use this feat

Jolan 14 Mar 11, 2021
User-Bot for reporting russian propaganda channels

Юзер-Бот, що автоматизує репортування Телеграм каналів пропагандистів Цей Телеграм Юзер-Бот використовується для автоматизації репорту пропагандистьск

58 Nov 07, 2022
Represents a Lavalink client used to manage nodes and connections.

lavaplayer Represents a Lavalink client used to manage nodes and connections. setup pip install lavaplayer setup lavalink you need to java 11* LTS or

HazemMeqdad 37 Nov 21, 2022
RDMAss - A Python Discord bot creating an interaction with RDM API

RDMAss A Python Discord bot creating an interaction with RDM API. Features Assig

5 Sep 21, 2022
Td-Ameritrade, Tradingview, Webhook, AWS Chalice

TDA-Autobot TDA-Autobot is an automated fire and forget trading mechanism utilizing Alex Golec's(Author) tda-api wrapper, Tradingview webhook alerts,

Kyle Jorgensen 2 Dec 12, 2021