I am trying to work with the PayPal REST API and integrate it into my Python script.
What I want to have sounds pretty simple at first, but at some point I got bogged down:
With my created application (Live Dashboard I want to retrieve invoice details from my account by ID. PayPal provides the following endpoint for it: https://api-m.paypal.com/v2/invoicing/invoices/{invoice_id} (Docs)
I already got my access token through a previous function, and it works so far. My app has access to all the necessary things:
However, I am not able to receive information about a certain invoice ID with the following code:
async def get_invoice_info(self, access_token, invoice_id: str):
url = f"https://api-m.paypal.com/v2/invoicing/invoices/{invoice_id}"
headers = {
'Content-Type': 'application/json',
'Authorization': f'Bearer {access_token}'
}
async with aiohttp.ClientSession() as session:
async with session.get(url, headers=headers) as resp:
print(resp.text)
if resp.status != 200:
raise Exception("Failed to retrieve invoice information!")
return await resp.json()
Printing out the scopes, I get even more confused:
{'scope': 'https://uri.paypal.com/services/checkout/one-click-with-merchant-issued-token https://uri.paypal.com/services/payments/realtimepayment https://uri.paypal.com/services/payments/payment/authcapture openid https://uri.paypal.com/services/payments/refund https://api.paypal.com/v1/vault/credit-card https://uri.paypal.com/services/billing-agreements https://api.paypal.com/v1/payments/.* https://uri.paypal.com/services/reporting/search/read https://api.paypal.com/v1/vault/credit-card/.* https://uri.paypal.com/services/shipping/trackers/readwrite https://uri.paypal.com/services/applications/webhooks', 'access_token': 'XXX', 'token_type': 'Bearer', 'app_id': 'XXX', 'expires_in': XXX, 'nonce': 'XXX'}
I can see that the endpoint is not listed, but can't explain the behavior to myself. I also tried to change the scope
parameter when requesting the access token, but nothing worked:
async def get_paypal_access_token(self):
d = {"grant_type" : "client_credentials"} # also included the scope neede here
h = {"Accept": "application/json", "Accept-Language": "en_US"}
async with aiohttp.ClientSession() as session:
async with session.post('https://api.paypal.com/v1/oauth2/token', auth=aiohttp.BasicAuth(CLIENT_ID, SECRET), headers=h, data=d) as resp:
r = await resp.json()
print(r)
access_token = r['access_token']
return access_token
I read through the documentation and could not find something that states I could not do such an action with a developer/personal account. Did I miss something somewhere?
I get the following error code:
<bound method ClientResponse.text of <ClientResponse(https://api-m.paypal.com/v2/invoicing/invoices/) [403 Forbidden]>
For working with live PayPal REST apps, you need a live PayPal business account, that is correct.
The scope for invoicing is https://uri.paypal.com/services/invoicing
. Access tokens without this scope cannot use the invoicing API and 403 is the expected response.
After making any changes to the Features of any REST app, if you have previously requested an API access token for that app you need to wait 9 hours or delete/reset that access token from cache before any changes will take effect.