App Store Server Library for Python

repository·main·Indexed 42 days ago

https://github.com/apple/app-store-server-library-python

A Python library (version 3.1.2) for interacting with Apple's App Store Server APIs, including App Store Server Notifications, Retention Messaging, and Advanced Commerce APIs. It provides tools like AppStoreServerAPIClient for API requests, SignedDataVerifier for decoding signed payloads, and PromotionalOfferSignatureCreator for generating promotional offer signatures. Supports both synchronous and asynchronous operations via AsyncAppStoreServerAPIClient.

Tokens
2.8K
Snippets
6
Records
8
Agent score
4%

What's inside App Store Server Library

  1. Obtain In-App Purchase credentials

    main

    To use the App Store Server API or create promotional offer signatures, you need a signing key from App Store Connect.

    1. Log in to App Store Connect with an Admin role.
    2. Navigate to Users and Access > Integrations > In-App Purchase.
    3. Create/manage keys to obtain your key ID and issuer ID.
    4. Download the .p8 signing key file.
  2. Install the App Store Server Library

    main

    Install the library using pip. The library requires Python 3.8 or higher.

    To enable asynchronous support (using httpx), install the library with the [async] extra.

    # Standard installation
    pip install app-store-server-library
    
    # Installation with async support
    pip install app-store-server-library[async]
  3. Retrieve transaction history using ReceiptUtility

    main

    To get transaction history, use ReceiptUtility to extract a transaction_id from an app receipt, then use AppStoreServerAPIClient.get_transaction_history to fetch the history. Use a loop to handle pagination via the hasMore property of the response.

    from appstoreserverlibrary.api_client import AppStoreServerAPIClient, APIException, GetTransactionHistoryVersion
    from appstoreserverlibrary.models.Environment import Environment
    from appstoreserverlibrary.receipt_utility import ReceiptUtility
    from appstoreserverlibrary.models.HistoryResponse import HistoryResponse
    from appstoreserverlibrary.models.TransactionHistoryRequest import TransactionHistoryRequest, ProductType, Order
    
    private_key = read_private_key("/path/to/key/SubscriptionKey_ABCDEFGHIJ.p8") # Implementation will vary
    
    key_id = "ABCDEFGHIJ"
    issuer_id = "99b16628-15e4-4668-972b-eeff55eeff55"
    bundle_id = "com.example"
    environment = Environment.SANDBOX
    
    client = AppStoreServerAPIClient(private_key, key_id, issuer_id, bundle_id, environment)
    receipt_util = ReceiptUtility()
    app_receipt = "MI.."
    
    try:    
        transaction_id = receipt_util.extract_transaction_id_from_app_receipt(app_receipt)
        if transaction_id != None:
            transactions = []
            response: HistoryResponse = None
            request: TransactionHistoryRequest = TransactionHistoryRequest(
                sort=Order.ASCENDING,
                revoked=False,
                productTypes=[ProductType.AUTO_RENEWABLE]
            )
            while response == None or response.hasMore:
                revision = response.revision if response != None else None
                response = client.get_transaction_history(transaction_id, revision, request, GetTransactionHistoryVersion.V2)
                for transaction in response.signedTransactions:
                    transactions.append(transaction)
            print(transactions)
    except APIException as e:
        print(e)
  4. Use AsyncAppStoreServerAPIClient for asynchronous requests

    main

    If you installed the library with [async] support, use AsyncAppStoreServerAPIClient for non-blocking API calls. Remember to call await client.async_close() when finished to clean up resources.

    from appstoreserverlibrary.api_client import AsyncAppStoreServerAPIClient, APIException
    from appstoreserverlibrary.models.Environment import Environment
    
    private_key = read_private_key("/path/to/key/SubscriptionKey_ABCDEFGHIJ.p8") # Implementation will vary
    
    key_id = "ABCDEFGHIJ"
    issuer_id = "99b16628-15e4-4668-972b-eeff55eeff55"
    bundle_id = "com.example"
    environment = Environment.SANDBOX
    
    client = AsyncAppStoreServerAPIClient(private_key, key_id, issuer_id, bundle_id, environment)
    
    try:    
        response = await client.request_test_notification()
        print(response)
    except APIException as e:
        print(e)
    
    # Once client use is finished
    await client.async_close()
  5. Use SignedDataVerifier to verify notifications

    main

    Use SignedDataVerifier to decode and verify signed payloads (like App Store Server Notifications).

    Parameters:

    • root_certificates: An array of Apple root certificates.
    • enable_online_checks: Boolean to enable/disable online checks.
    • environment: The Environment (e.g., Environment.SANDBOX).
    • bundle_id: Your app's bundle ID.
    • app_apple_id: The app's Apple ID (required for the Production environment).
    from appstoreserverlibrary.models.Environment import Environment
    from appstoreserverlibrary.signed_data_verifier import VerificationException, SignedDataVerifier
    
    root_certificates = load_root_certificates()
    enable_online_checks = True
    bundle_id = "com.example"
    environment = Environment.SANDBOX
    app_apple_id = None # appAppleId must be provided for the Production environment
    
    signed_data_verifier = SignedDataVerifier(root_certificates, enable_online_checks, environment, bundle_id, app_apple_id)
    
    try:
        signed_notification = "ey.."
        payload = signed_data_verifier.verify_and_decode_notification(signed_notification)
        print(payload)
    except VerificationException as e:
        print(e)
  6. Create Promotional Offer Signatures

    main

    Use PromotionalOfferSignatureCreator to generate base64-encoded signatures for promotional offers. This requires the private key, key_id, and bundle_id.

    from appstoreserverlibrary.promotional_offer import PromotionalOfferSignatureCreator
    import time
    
    private_key = read_private_key("/path/to/key/SubscriptionKey_ABCDEFGHIJ.p8") # Implementation will vary
    
    key_id = "ABCDEFGHIJ"
    bundle_id = "com.example"
    
    promotion_code_signature_generator = PromotionalOfferSignatureCreator(private_key, key_id, bundle_id)
    
    product_id = "<product_id>"
    subscription_offer_id = "<subscription_offer_id>"
    application_username = "<application_username>"
    nonce = "<nonce>"
    timestamp = round(time.time()*1000)
    base64_encoded_signature = promotion_code_signature_generator.create_signature(product_id, subscription_offer_id, application_username, nonce, timestamp)
  7. Use AppStoreServerAPIClient for API requests

    main

    Use AppStoreServerAPIClient to interact with the App Store Server API. You must provide the private key, key_id, issuer_id, bundle_id, and the Environment (e.g., Environment.SANDBOX).

    from appstoreserverlibrary.api_client import AppStoreServerAPIClient, APIException
    from appstoreserverlibrary.models.Environment import Environment
    
    private_key = read_private_key("/path/to/key/SubscriptionKey_ABCDEFGHIJ.p8") # Implementation will vary
    
    key_id = "ABCDEFGHIJ"
    issuer_id = "99b16628-15e4-4668-972b-eeff55eeff55"
    bundle_id = "com.example"
    environment = Environment.SANDBOX
    
    client = AppStoreServerAPIClient(private_key, key_id, issuer_id, bundle_id, environment)
    
    try:    
        response = client.request_test_notification()
        print(response)
    except APIException as e:
        print(e)