We will today learn how to validate in-app purchases using Python and an Android app. This will serve for native Android apps, ionic, kotlin, flutter, react native or any other technology you choose.
The first thing to do is create a refresh token and OAuth 2.0 token data. To follow this tutorial, we will continue with the following steps:
https://devcodelight.com/how-to-get-the-refresh-token-of-google-step-by-step-oauth-2-0
NOW we are going to implement the code that will allow us to validate purchases:
First, we need to get the access token using our refresh token (obtained in the previous step).
To get the access token is:
import requestsdef exchange_code_for_token(code: str) -> dict: url = "https://oauth2.googleapis.com/token" data = { "code": code, "client_id": "TU_CLIENT_ID", "client_secret": "TU_CLIENT_SECRET", "redirect_uri": "http://localhost:8000/auth/callback", "grant_type": "authorization_code" } response = requests.post(url, data=data) response.raise_for_status() return response.json()
You will get the access token with this.
You receive this:
{ "access_token": "...", "expires_in": 3599, "refresh_token": "...", "scope": "https://www.googleapis.com/auth/androidpublisher", "token_type": "Bearer" }
You now need to validate the following:
Validating product purchases:
Validar compra de Google Play (producto in-app)
import requests import json def validate_android_purchase( id_user: str, purchase_token: str, package_name: str, subscription_id: str, access_token: str, ) -> str: """ Returns order ID if valid, -1 if there's an error in the response, or raises exceptions if connection or request fails """ url = ( f"https://www.googleapis.com/androidpublisher/v3/applications/" f"{package_name}/purchases/products/{subscription_id}/tokens/{purchase_token}" ) headers = { "Authorization": f"Bearer {access_token}", "Accept": "application/json", "User-Agent": "SecurePythonClient/1.0" } try: response = requests.get(url, headers=headers) response.raise_for_status() except requests.HTTPError as e: print(f"HTTP Error: {response.status_code} - {response.reason}") try: print(json.dumps(response.json(), indent=2)) except Exception: print("Error parsing error response") raise except requests.RequestException as e: print(f"Connection error: {str(e)}") raise data = response.json() if 'error' in data: return "-1" return data.get("orderId", "NO_ORDER_ID")
Ejemplo de uso:
if name == "main": try: order_id = validate_android_purchase( id_user="user_123", purchase_token="PURCHASE_TOKEN_AQUÍ", package_name="com.tu.app", subscription_id="producto_id", access_token="ya29.a0AfH6SMA..." ) print("Order ID:", order_id) except Exception as e: print("Error validating purchase:", str(e))
Validating subscriptions:
import requests import json def validate_android_subscription( id_user: str, purchase_token: str, package_name: str, subscription_id: str, access_token: str, ) -> dict: """ Validates a Google Play subscription. Args: id_user (str): ID internal of the user (optional, useful for tracking) purchase_token (str): Purchase token received from the app package_name (str): Name of the app's package (com.example.app) subscription_id (str): ID of the subscription access_token (str): OAuth access token Returns: Dictionary with subscription data or raises exceptions if there's an error """ url = ( f"https://androidpublisher.googleapis.com/androidpublisher/v3/applications/" f"{package_name}/purchases/subscriptions/{subscription_id}/tokens/{purchase_token}" ) headers = { "Authorization": f"Bearer {access_token}", "Accept": "application/json", "User-Agent": "SecurePythonClient/1.0" } try: response = requests.get(url, headers=headers) response.raise_for_status() except requests.HTTPError as e: print(f"HTTP Error: {response.status_code} - {response.reason}") try: print(json.dumps(response.json(), indent=2)) except Exception: print("Error parsing error response") raise except requests.RequestException as e: print(f"Connection error: {str(e)}") raise return response.json()
Ejemplo of use:
if name == "main": try: result = validate_android_subscription( id_user="user_456", purchase_token="TOKEN_DE_COMPRA", package_name="com.ejemplo.app", subscription_id="subs_mensual", access_token="ya29.a0AfH6SMA..." ) print("Valid Subscription:") print(json.dumps(result, indent=2)) except Exception as e: print("Error validating subscription:", str(e))
