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)
A Bot, which observes your counting-abilities and controls your drinking-habits, too!

Discord Counting Bot with Beer-Counter Heavily inspired by AlexVerricos Counting_bot, but adjusted a lot for the beer drinking habits of students. Inv

Jakob Jung 3 Oct 18, 2022
gnosis safe tx builder

Ape Safe: Gnosis Safe tx builder Ape Safe allows you to iteratively build complex multi-step Gnosis Safe transactions and safely preview their side ef

228 Dec 22, 2022
This is Instagram reposter that repost TikTok videos.

from-tiktok-to-instagram-reposter This script reposts videos from Tik Tok to your Instagram account. You must enter the username and password and slee

Mohammed 19 Dec 01, 2022
A simple telegram bot that resolves video urls using yt-dlp

URL to Video Telegram Bot A simple telegram bot that resolves video urls using yt-dlp Copyright (C) 2021 Vítor Vasconcellos This program is free softw

Vítor 1 Nov 18, 2021
AWS Serverless Application Model (SAM) is an open-source framework for building serverless applications

AWS Serverless Application Model (AWS SAM) The AWS Serverless Application Model (SAM) is an open-source framework for building serverless applications

Amazon Web Services 8.9k Dec 31, 2022
Exchange indicators & Basic functions for Binance API.

binance-ema Exchange indicators & Basic functions for Binance API. This python library has been written to calculate SMA, EMA, MACD etc. functions wit

Emre MENTEŞE 24 Jan 06, 2023
Track to Detect and Segment: An Online Multi-Object Tracker (CVPR 2021)

Track to Detect and Segment: An Online Multi-Object Tracker (CVPR 2021) Track to Detect and Segment: An Online Multi-Object Tracker Jialian Wu, Jiale

Jialian Wu 520 Dec 31, 2022
search different Streaming Platforms for movie titles.

Install git clone and cd to directory install Selenium download chromedriver.exe to same directory First Run Use --setup True for the first run. Platf

34 Dec 25, 2022
New developed moderation discord bot by archisha

Monitor42 New developed moderation discord bot by αrchιshα#5518. Details Prefix: 42! Commands: Moderation Use 42!help to get command list. Invite http

Kamilla Youver 0 Jun 29, 2022
Tinkoff social pulse api wrapper

Tinkoff social pulse api wrapper

Semenov Artur 9 Dec 20, 2022
🎄 JustaGrabber - A discord token grabber written in python3

🎄 JustaGrabber - A discord token grabber written in python3 🎇 Made by kldiscord https://github.com/kldiscord 🌟 Please leave a star if you liked Jus

1 Dec 19, 2022
A discord bot with a leveling system (similar to mee6).

Discord.py A discord bot with a leveling system (like mee6) Pre-requisites Knowing how to get create an app/bot via discord's developer portal. Websit

26 Dec 11, 2022
An EmbedBuilder in Python for discord.py embeds. Pip Module.

Discord.py-MaxEmbeds An EmbedBuilder for Discord bots in Python. You need discord.py to use this module. Installation Step 1 First you have to install

Max Tischberger 6 Jan 13, 2022
Find people to play tennis with.

40Love 40Love is a full-stack web application that helps tennis players find hits at public tennis courts. Players can select public courts on the map

Tanner Schmutte 27 Jun 08, 2022
Twitter automation tool for growing organic followers.

Tiwoto Tiwoto is a simple python program that automates some kind of behaviors and keep your account active. Create an .env file in this directory and

Mehmetcan Yildiz 6 Sep 22, 2022
AWS EC2 S3 Automated With python

AWS_EC2_S3_Automated Description This programme is a Python3 script that utilizes Boto3 to automate the process of creating an AWS EC2 instance with a

niall_crowe 2 Nov 16, 2021
An script where it logs in your instagram account and follows people and likes their posts

InstaFollower An script where it logs in your instagram account and follows people and likes their posts (uses the tags to fetch people) Requirements:

Bless 3 Nov 29, 2022
My personal discord bot using discord.py

Rara-chan My personal discord bot that I use for stuff that I find interesting. Features Responds to certain messages ChatBot capabilities NHentai scr

Mikask 3 Nov 06, 2022
Select random winners for a Twitter giveaway

twitter_picker Select random winners for a Twitter giveaway Once the Twitter giveaway (or airdrop) is closed, assign a number to each participant. The

Michael Rawner 1 Dec 11, 2021
Python API Client for Close

Close API A convenient Python wrapper for the Close API. API docs: http://developer.close.com Support: Close 56 Nov 30, 2022