question

Upvotes
Accepted
1 0 0 0

403 error when trying to download filing

I am running the script displayed here:

https://github.com/LSEG-API-Samples/Example.RDPAPI.Python.IntroductionToFilings/blob/main/IntroToFilings.ipynb

It works fine until:

# Define Helper Function retrieveURL

def retrieveURL(token, retrievalParameters):

ENDPOINT_DOC_RETRIEVAL = RDP_BASE_URL+'/data/filings'+RDP_FILINGS_VERSION + '/retrieval/search/' + retrievalParameters

headers = {

"Authorization": "Bearer " + token,

"X-API-Key": "155d9dbf-f0ac-46d9-8b77-f7f6dcd238f8",

"ClientID" : "api_playground"

}

...

# Retrieve URL by FilingId

jsonFullResp = retrieveURL(accessToken,'filingId/97661417885')


where I get:

Next we retrieve: https://api.refinitiv.com/data/filings/v1/retrieval/search/filingId/97661417885

Response status code =403


Questions:

1) Why does the author of that post set the ClientID to api_playground? My understanding of GraphQL playgrounds is that they serve to try things and to understand data structure, not to launch downloads of filings via systematic API access.

2) Why do I get the 403 error? I also tried substituting the X-API-Key and ClientID with my credentials that worked well further up the code when I was obtaining the token, but same result.


Thank you.

#producterror-403download-filedocument-url
icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Upvotes
Accepted
23.7k 61 15 21

Hello @user2,

Please try to use the filings Python and Postman sample in the downloads tab of developers portal. The Python sample shows the complete GraphQL search and subsequent download and saving of the file. You can read about the structure of filings request in the document.

The client ID used in the filings request header is just a unique identified and can be any text that specifically identifies your application name.

icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Upvotes
1 0 0 0

Dear Gurpreet,

Thank you very much.

I ran the filings.py. Before that, I dumped my username, password and appKey as v1 authentication parameters in the credential file.

Executing the code from filings.py yields no error (authentification seems to work) but a docId that is a NoneType object. I would have expected something different. I also tried the other example from the filings.py file - same result.

Best

Thomas


Here the code, it is 1:1 copy-paste from the sample file:

#=============================================================================

# Refinitiv Data Platform demo app to get filings data

#-----------------------------------------------------------------------------

# This source code is provided under the Apache 2.0 license

# and is provided AS IS with no warranty or guarantee of fit for purpose.

# Copyright (C) 2021 Refinitiv. All rights reserved.

#=============================================================================

import requests

import json

import rdpToken


# Application Constants

RDP_version = "/v1"

base_URL = "https://api.refinitiv.com"

DOC_CLIENT_ID = "my_application_name"

DOC_API_KEY = "155d9dbf-f0ac-46d9-8b77-f7f6dcd238f8"


#==============================================

def requestSearch(searchPayload):

#==============================================

category_URL = "/data-store"

endpoint_URL = "/graphql"

RESOURCE_ENDPOINT = base_URL + category_URL + RDP_version + endpoint_URL

requestData = {

"query": searchPayload

}


# get the latest access token

accessToken = rdpToken.getToken()

hdrs = {

'Authorization': "Bearer " + accessToken,

'Content-Type': "application/json",

'cache-control': "no-cache"

}


sResp = requests.post(RESOURCE_ENDPOINT, headers=hdrs, data = json.dumps(requestData))


if sResp.status_code != 200:

raise ValueError("Unable to search. Code %s, Message: %s" % (sResp.status_code, sResp.text))

else:

jResp = json.loads(sResp.text)

documentID = jResp["data"]["FinancialFiling"][0]["FilingDocument"]["DocId"]

return documentID



#==============================================

def retrieveDocURL(documentID):

#==============================================

category_URL = "/data/filings/"

endpoint_URL = "/retrieval/search/docId/"

RESOURCE_ENDPOINT = base_URL + category_URL + RDP_version + endpoint_URL + documentID


# get the latest access token

accessToken = rdpToken.getToken()

hdrs = {

'Authorization': "Bearer " + accessToken,

"X-API-Key": DOC_API_KEY,

"ClientID" : DOC_CLIENT_ID

}


rResp = requests.get(RESOURCE_ENDPOINT, headers = hdrs)


if rResp.status_code != 200:

raise ValueError("Unable to get document URL. Code %s, Message: %s" % (rResp.status_code, rResp.text))

else:

jResp = json.loads(rResp.text)

fName = list(jResp.keys())[0]

sURL = jResp[list(jResp.keys())[0]]["signedUrl"]

return fName, sURL



#==============================================

def retrieveSaveDoc(fileName, signedUrl):

#==============================================

dResp = requests.get(signedUrl, allow_redirects=True)


if dResp.status_code != 200:

raise ValueError("Unable to download the document. Response: " % (dResp.status_code, dResp.text))

else:

with open(fileName, 'wb') as f:

f.write(dResp.content)

f.close()

print("The document [%s], has been downloaded" % fileName)




#==============================================

if __name__ == "__main__":

#==============================================

documentSearchText = """

{

FinancialFiling(

sort: {FilingDocument: {DocumentSummary: {FilingDate: DESC}}},

filter: {FilingDocument: {DocumentSummary: {FilingDate: {BETWN: {FROM: "2020-07-01T00:00:00Z", TO: "2020-08-01T00:00:00Z"}}}}},

keywords: {searchstring: "FinancialFiling.FilingDocument.DocumentText:COVID-19"},

limit: 5) {

_metadata {

totalCount

}

FilingOrganization {

Names {

Name {

OrganizationName(

filter: {AND: [ {

OrganizationNameLanguageId: {EQ: "505062"}}, {

OrganizationNameTypeCode: {EQ: "LNG"}}]})

{

OrganizationName

}

}

}

}

FilingDocument {

DocId

DocumentSummary {

DocumentTitle

FilingDate

FormType

FeedName

}

DocumentText

}

}

}

"""


# search for the document first

print("Performing a document search using document-text...")

docId = requestSearch(documentSearchText)

icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Upvotes
23.7k 61 15 21

Hi @user2,

Do you have access to the filings API. I just executed the sample without any modification, and am able to download the file:

>> python filings.py
Performing a document search using document-text...
Read credentials from file
Getting a new token using Password Grant...
Saving the new token
Document ID is: 54938820

Retrieving the document URL for this DocID...
Existing token read from: token.txt
Document fileName is: 20200801_5000601244_97659617443_1_12_INTRM_raw.pdf
Retrieval signedUrl is: https://*****

Downloading the document: 20200801_5000601244_97659617443_1_12_INTRM_raw.pdf...
The document [20200801_5000601244_97659617443_1_12_INTRM_raw.pdf], has been downloaded


For the OAuth access token that you get - does it have filings related scope associated with it. Namely -

trapi.data.filings.metadata
trapi.data.filings.retrieval
trapi.data.filings.search


icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Dear Gurpreet,


Thank you. It seems that the token does not have these features, see below.


How can I extend the scope to filings?

Best

Thomas

"scope": "trapi.alerts.history.crud trapi.alerts.preferences.crud trapi.alerts.publication.crud trapi.alerts.subscription.crud trapi.auth.cloud-credentials trapi.cfs.claimcheck.read trapi.data.average-volume-analytics.ava_read trapi.data.benchmark.bmk_read trapi.data.get.data.read trapi.data.historical-pricing.events.read trapi.data.historical-pricing.summaries.read trapi.data.quantitative-analytics.read trapi.data.symbology.advanced.read trapi.data.symbology.read trapi.frtb.sentimarization trapi.graphql.subscriber.access trapi.messenger trapi.metadata.read trapi.sdbold trapi.search.explore.read trapi.search.lookup.read trapi.search.metadata.read trapi.search.read trapi.searchcore.lookup.read trapi.searchcore.metadata.read trapi.searchcore.read trapi.streaming.prcperf.read trapi.streaming.synthetic.read trapi.synthetic.crud trapi.user-framework.application-metadata.raplib trapi.user-framework.mobile.crud trapi.user-framework.recently-used.crud trapi.user-framework.workspace.crud trapi.userdata.portfolio-management.read"

Hello @user2

Please contact your LSEG representative to help you with the RDP Filing service permission.

Upvotes
1 0 0 0

Dear Gurpreet,

It seems that my token does not have these features, see below. How can I extend the scope to filings?

"scope": "trapi.alerts.history.crud trapi.alerts.preferences.crud trapi.alerts.publication.crud trapi.alerts.subscription.crud trapi.auth.cloud-credentials trapi.cfs.claimcheck.read trapi.data.average-volume-analytics.ava_read trapi.data.benchmark.bmk_read trapi.data.get.data.read trapi.data.historical-pricing.events.read trapi.data.historical-pricing.summaries.read trapi.data.quantitative-analytics.read trapi.data.symbology.advanced.read trapi.data.symbology.read trapi.frtb.sentimarization trapi.graphql.subscriber.access trapi.messenger trapi.metadata.read trapi.sdbold trapi.search.explore.read trapi.search.lookup.read trapi.search.metadata.read trapi.search.read trapi.searchcore.lookup.read trapi.searchcore.metadata.read trapi.searchcore.read trapi.streaming.prcperf.read trapi.streaming.synthetic.read trapi.synthetic.crud trapi.user-framework.application-metadata.raplib trapi.user-framework.mobile.crud trapi.user-framework.recently-used.crud trapi.user-framework.workspace.crud trapi.userdata.portfolio-management.read"

icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

@user2

Please contact your LSEG representative to help you with the RDP Filing service permission.

Write an Answer

Hint: Notify or tag a user in this post by typing @username.

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.