I'm encountering an authentication failure issue while using the PayPal API to create billing plans and handle subscriptions. Here's the error message I'm receiving:
{"name":"AUTHENTICATION_FAILURE","message":"Authentication failed due to invalid authentication credentials or a missing Authorization header.","links":[{"href":"https://developer.paypal.com/docs/api/overview/#error","rel":"information_link"}]}
This error occurs when attempting to access the URLhttps://api.sandbox.paypal.com/v1/billing/plans/P-054793526X109145CMXEAUWQ
Below is the my code:
def get_access_token(client_id, client_secret): auth_url = 'https://api.sandbox.paypal.com/v1/oauth2/token' headers = {'Accept': 'application/json','Accept-Language': 'en_US', } data = {'grant_type': 'client_credentials' } auth = (client_id, client_secret) response = requests.post(auth_url, headers=headers, data=data, auth=auth) if response.status_code == 200: access_token_data = response.json() access_token = access_token_data.get('access_token') if access_token: return access_token else: print("Failed to obtain access token: Access token not found in response.") return None else: print(f"Failed to obtain access token: {response.text}") return None@app.route('/purchase', methods=['POST'])@login_requireddef purchase_subscription(): plan = request.form.get('plan') selected_gateway = request.form.get('payment_gateway') plan_settings = get_plan_settings() if not plan_settings: flash('Failed to fetch plan settings from the database.', 'danger') return redirect(url_for('subscription')) credits_to_add = 0 credits_price = 0 subscription_type = None subscription_start_date = None subscription_end_date = None subscription_type_mapping = {'plan1': 'monthly','plan2': 'monthly','plan3': 'monthly','plan4': 'yearly','plan5': 'yearly','plan6': 'yearly' } if plan in subscription_type_mapping: subscription_type = subscription_type_mapping[plan] if subscription_type == 'monthly': frequency = "MONTH" elif subscription_type == 'yearly': frequency = "YEAR" credits_to_add = plan_settings[plan +"_credits"] credits_price = plan_settings[plan +"_price"] else: flash('Invalid plan selected.', 'danger') return redirect(url_for('subscription')) ACCESS_TOKEN = get_access_token(PAYPAL_CLIENT_ID, PAYPAL_CLIENT_SECRET) if ACCESS_TOKEN: print("Access token obtained successfully:", ACCESS_TOKEN) product_id = create_product(plan, credits_price, ACCESS_TOKEN) if product_id: billing_plan = create_billing_plan(plan, frequency, credits_price, product_id, ACCESS_TOKEN) if billing_plan: print("Redirecting to: ", billing_plan) return redirect(billing_plan) else: flash('Failed to initiate payment.', 'danger') return redirect(url_for('subscription')) else: flash('Failed to create product.', 'danger') return redirect(url_for('subscription')) else: print("Failed to obtain access token.") flash('Failed to obtain access token.', 'danger') return redirect(url_for('subscription'))def create_product(plan, amount, access_token): auth_url = 'https://api.sandbox.paypal.com/v1/oauth2/token' product_url = 'https://api.sandbox.paypal.com/v1/catalogs/products' print(f"Access token in app.py {access_token}") headers = {'Content-Type': 'application/json','Accept-Language': 'en_US','Authorization': f'Bearer {access_token}' } # Create product product_data = {"name": f"{plan.capitalize()} Subscription","description": f"{plan.capitalize()} Subscription","type": "SERVICE","category": "SOFTWARE" } response = requests.post(product_url, headers=headers, json=product_data) if response.status_code == 201: return response.json().get('id') else: print(f"Failed to create product: {response.text}") return Nonedef create_billing_plan(plan, frequency, amount, product_id, access_token): auth_url = 'https://api.sandbox.paypal.com/v1/oauth2/token' plan_url = 'https://api.sandbox.paypal.com/v1/billing/plans' headers = {'Accept': 'application/json','Accept-Language': 'en_US','Authorization': f'Bearer {access_token}' } # Create billing plan plan_data = {"product_id": product_id,"name": f"{plan.capitalize()} Subscription","description": f"{plan.capitalize()} Subscription","billing_cycles": [{"frequency": {"interval_unit": frequency,"interval_count": 1 },"tenure_type": "REGULAR","sequence": 1,"total_cycles": 0,"pricing_scheme": {"fixed_price": {"value": str(amount),"currency_code": "USD" } } }],"payment_preferences": {"auto_bill_outstanding": True,"setup_fee": {"value": "0","currency_code": "USD" },"setup_fee_failure_action": "CONTINUE","payment_failure_threshold": 3 },"quantity_supported": False,"taxes": {"percentage": "0","inclusive": False } } print("Plan data (params): ",plan_data) print("Plan url: ",plan_url) response = requests.post(plan_url, headers=headers, json=plan_data) if response.status_code == 201: print("Response: ", response) plan_response = response.json() for link in plan_response.get('links', []): if link.get('rel') == 'self': return link.get('href') # If no URL with rel='self' is found print("Failed to find billing plan URL in response.") return None else: print(f"Failed to create billing plan: {response.text}") return None
Console log:
Access token obtained successfully: HIDDENAccess token in app.py: HIDDENPlan data (params): {'product_id': 'PROD-6T149159N1656222J', 'name': 'Plan2 Subscription', 'description': 'Plan2 Subscription', 'billing_cycles': [{'frequency': {'interval_unit': 'MONTH', 'interval_count': 1}, 'tenure_type': 'REGULAR', 'sequence': 1, 'total_cycles': 0, 'pricing_scheme': {'fixed_price': {'value': '19.99', 'currency_code': 'USD'}}}],'payment_preferences': {'auto_bill_outstanding': True, 'setup_fee': {'value': '0', 'currency_code': 'USD'}, 'setup_fee_failure_action': 'CONTINUE', 'payment_failure_threshold': 3}, 'quantity_supported': False, 'taxes': {'percentage': '0', 'inclusive': False}}Plan url: https://api.sandbox.paypal.com/v1/billing/plansResponse: <Response [201]>Redirecting to: https://api.sandbox.paypal.com/v1/billing/plans/P-7LY37792X0654533CMXESLWQ
Im' 100% sure the access token & client id and secret are correctAny insights or suggestions on how to troubleshoot and resolve this issue would be greatly appreciated.
Thank you!