Webcall and Eikon Library Parallel Usage Not Possible?

amroeser
amroeser Newcomer
edited March 13 in Refinitiv Data Platform

Dear Dev Community,

I'm currently facing issues when trying to use both the Eikon Python library and direct Web API calls in parallel. The Refinitiv application runs continuously in the background, and while the Python library functions work as expected, direct API calls fail with authentication issues.

Eikon Initialization

  • The initialization is done using an API key from the environment variables (EIKON_API_KEY).
  • A proxy status check ensures that the Eikon proxy is active before proceeding.
  • After successful initialization, a test API call verifies the connection.
  • The Bearer token is automatically captured and stored.

Data Retrieval via the Python Library

  • Functions like ek.get_data() and ek.get_symbology() are used to retrieve data via the Eikon library.
  • These calls work consistently and return valid data.

Parallel Attempt: Direct API Calls to Refinitiv

  • I am also trying to access Refinitiv data via direct Web API calls.
  • A test endpoint was implemented to call:
    https://api.refinitiv.com/user-framework/mobile/overview-service/v1/corp/filings/MBGn.DE using the current Bearer token.
  • However, when testing via curl, I receive the following error:
{  "success": false,  "message": "API request failed with status code: 401",  "details": "{\"error\":{\"id\":\"44c34bb1-2cab-4b0a-a856-b059ec3c783e\",\"code\":\"401\",\"message\":\"token expired\",\"status\":\"Unauthorized\"}}\n"}

The error "token expired" suggests that the Bearer token may not be valid for direct API calls or requires a different handling process.

Additional Questions:

  1. Are the Bearer tokens for the Eikon Python library and Web API calls different? If so, how do they differ in terms of usage and expiration?
  2. How can I authenticate via Web API calls without logging out the local Refinitiv application? When I try to authenticate via OAuth or another method, the active session is terminated, which causes the Python library to stop working. Is there a way to prevent this?
  3. How can the token be refreshed for direct API calls without interrupting existing queries through the Eikon library?
  4. Are there alternative endpoints or methods to access the required company data?

Any insights or solutions would be greatly appreciated. Thanks in advance for your support! :)

Best regards,

Alex

Answers

  • Hello @amroeser

    Which Python library are you using? And by direct API call, I am presuming you are making API calls to LSEG Data Platform (RDP).

    From your description, it looks like you might be using a Platform Session in the library with the same credentials that you are using in the RDP REST (Web) calls. This might be invalidating the previous token. The solution is to use different credentials for both the applications.

    If the Library calls are indeed requesting data from the local instance of Eikon/Workspace a.k.a Desktop Session, then this issue should not happen.

  • amroeser
    amroeser Newcomer

    Hello @Gurpreet!

    I am using the Eikon Python library, version 1.1.18, and I initialize it as follows:

    def _init_eikon_in_thread(api_key: str) -> tuple:    logger.info("=== Eikon Thread gestartet ===")    try:        ek.set_app_key(api_key)        test_isin = "DE0007100000"  # Mercedes-Benz Group AG        df = ek.get_symbology(            [test_isin],            from_symbol_type='ISIN',            to_symbol_type='RIC'        )        return True, df    except Exception as e:        logger.error(f"Fehler in Eikon Thread: {str(e)}")        handler.flush()        return False, str(e)
    

    With this initialization, I can successfully retrieve data using the Eikon library. However, when trying to make a direct API call to https://api.refinitiv.com/user-framework/mobile/overview-service/v1/corp/filings/MBGn.DEError using the same credentials, I receive a 401 Unauthorized error.

    Does the Eikon initialization (ek.set_app_key(api_key)) provide the necessary authentication for this API call, or do I need a separate authentication method (e.g., OAuth 2.0 via the Refinitiv Data Platform)? If so, should I use a different library instead of Eikon for this request?

    Best regards,
    Alex

  • Jirapongse
    Jirapongse ✭✭✭✭✭

    @amroeser

    You can use the LSEG Data Libaray for Python.

    I tested it and found the LSEG Data Libaray for Python can retrieve data from the endpoint (https://api.refinitiv.com/user-framework/mobile/overview-service/v1/corp/filings/MBGn.DE) with the desktop session (an application key) by using the following code.

    import lseg.data as ld
    from lseg.data.delivery import endpoint_request
    ld.open_session()
    
    filing_url = 'https://api.refinitiv.com/user-framework/mobile/overview-service/v1/corp/filings/MBGn.DE'
    
    request_definition = ld.delivery.endpoint_request.Definition(
        url = filing_url,
        method = ld.delivery.endpoint_request.RequestMethod.GET
    )
    response = request_definition.get_data()
    response.data.raw
    
    image.png

    The examples are on GitHub.

  • amroeser
    amroeser Newcomer

    Hello @Jirapongse!

    Thank you for your response and for testing the LSEG Data Library for Python. I will try it out and see if it resolves the issue.

    Would you recommend switching to the LSEG Data Library for all data retrieval tasks currently handled via the Eikon library, or does Eikon have advantages in certain use cases?

    Best regards,

    Alex

  • Jirapongse
    Jirapongse ✭✭✭✭✭

    Yes, I would recommend switching to the LSEG Data Library for Python because the Eikon Data API is quite old. The LSEG Data Library for Python provides more capabilities than Eikon Data API.

    However, for some data, they use different endpoints to retrive data. It is better to test it before switching to the LSEG Data Library for Python.

  • amroeser
    amroeser Newcomer
    edited March 12

    Thank you for the clarification. One last question: When I try to access the 'fileUrl' programmatically, the download fails due to an unexpected content type (text/html;charset=utf-8 instead of application/pdf). However, when I open the link in a browser, I need to sign in before I can access and download the file. Is there a way to automate this download using Python while handling authentication?

  • Jirapongse
    Jirapongse ✭✭✭✭✭

    @amroeser

    Where did you get this endpoint (https://api.refinitiv.com/user-framework/mobile/overview-service/v1/corp/filings/)?

    I checked the document and found that "The service is available for Refinitiv Workspace mobile only."

    Therefore, it may not work with the API.

  • amroeser
    amroeser Newcomer

    @Jirapongse

    I found this API endpoint in the Refinitiv API Playground while exploring available services. My goal is to programmatically download and analyze annual reports using Python.

    The API does return a link to the respective document, but the issue is that this link requires an additional authentication step before downloading. This prevents me from directly retrieving the file in my Python workflow.

    So far, I haven’t found a clear solution in the forum discussions. Do you have any alternative suggestions on how I could automate the download of these documents in Python?

  • Jirapongse
    Jirapongse ✭✭✭✭✭

    The endpoint is undocumented. I am not if it is opened to use by other applications. You need to contact the RDP support team directly via MyAccount to confirm it.

    For filings, you can check the Filings API and the Introduction To Filings - Python article.

  • amroeser
    amroeser Newcomer

    Hi @Jirapongse,

    I previously reached out to LSEG Support regarding the issue of automating the download of annual report PDFs via the API. However, they reviewed my request and stated that the API function itself is working correctly but that they only provide support for technical API issues like connection problems. They explicitly referred me back to the Developer Community for further assistance.

    Here is the response I received from LSEG Support:

    Hi Alexander,This is Thomas from the LSEG technical team.Thank you for reaching out. We reviewed your query and the text file attached to this case. It appears that the API function is working properly, but specific changes need to be made to your code.The technical team can only assist with technical issues related to the API (e.g., connection issues).If you were unable to find a satisfactory answer to your query, I would highly suggest posting your query on the Dev portal. Our developer team will be able to assist you once posted.

    Since my main goal is to automate the PDF download via Python, and the support team directed me here, I wanted to ask if you could help with this issue.

    Code Example:

    Here is the Python script I am using to test the filing retrieval via the LSEG Data Library (LDL):

    """
    LSEG Data Library (LDL) Test für Filings.
    """
    
    import logging
    import threading
    import os
    from pathlib import Path
    from dotenv import load_dotenv
    
    logger = logging.getLogger(__name__)
    logger.setLevel(logging.INFO)
    
    if not logger.handlers:
        handler = logging.StreamHandler()
        handler.setLevel(logging.INFO)
        formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
        handler.setFormatter(formatter)
        logger.addHandler(handler)
    
    logger.propagate = False
    
    _session_active = False
    _session_lock = threading.Lock()
    
    try:
        import lseg.data as ld
        LSEG_AVAILABLE = True
        logger.info("LSEG Data Library erfolgreich importiert")
    except ImportError:
        LSEG_AVAILABLE = False
        logger.warning("LSEG Data Library nicht gefunden")
    
    
    def download_filing(ric: str):
        """Test-Funktion für den Abruf und Download von LSEG Filings"""
        try:        
            filing_url = f'https://api.refinitiv.com/user-framework/mobile/overview-service/v1/corp/filings/{ric}'
            
            request_definition = ld.delivery.endpoint_request.Definition(
                url=filing_url,
                method=ld.delivery.endpoint_request.RequestMethod.GET,
                query_parameters={
                    'formName': 'Full Year'  
                }
            )
            
            logger.info(f"Rufe Filings für {ric} ab...")
            response = request_definition.get_data()
            
            if response and response.data and response.data.raw:
                logger.info("Antwort erhalten!")
                
                if isinstance(response.data.raw, dict) and 'data' in response.data.raw:
                    filings = response.data.raw['data']
                    logger.info(f"Gefundene Filings: {len(filings)}")
                    
                    for filing in filings[:3]:
                        logger.info("\nFiling Details:")
                        for key, value in filing.items():
                            logger.info(f"- {key}: {value}")
                
                return response.data.raw
                
        except Exception as e:
            logger.error(f"Fehler beim Abrufen der Filings: {str(e)}")
            return None
    
    if __name__ == "__main__":
        download_filing("MBGn.DE")
    
    Attempts So Far:
    • I followed the Filings API instructions, but they seem to be based on an older API version that no longer works as described.
    • I also tested different authentication flows but was unable to automate the download.
    • Since the support team directed me here, I wanted to check if there is any workaround or best practice for handling this.
      Questions:
    1. Has anyone successfully automated the download of PDFs provided via the fileUrl?
    2. Is there a way to authenticate programmatically before accessing the document link?
    3. Does LSEG provide an alternative API or approach for this type of request?

    Since I was referred back to the Developer Community, I would truly appreciate any insights or guidance you can provide.

    Thanks in advance for your help!

    Best regards,

    Alexander

  • Jirapongse
    Jirapongse ✭✭✭✭✭

    @amroeser

    You can access the API Playground so I assume that you have an account to access the Data Platform session.

    I can access the files by using the Data Platform session.

    ld.open_session('platform.ldp')
    

    Now, you can get the file URLs.

      'fileUrl': 'https://amers2-apps.platform.refinitiv.com/Apps/AdvFilings/FRS_GET?DocumentId=82606913&ContentFormat=pdf',
    

    The URL contains a DocumentId (82606913). You can use the DocumentId with the following endpoint to get a signed URL.

    file_url  = 'https://api.refinitiv.com/data/filings/v1/retrieval/search/docId/82606913'
    file_definition = ld.delivery.endpoint_request.Definition(
        url = file_url,
        header_parameters  = {'ClientID':'api_playground','X-API-Key':'<key>','Accept':'*/*'},
        method = ld.delivery.endpoint_request.RequestMethod.GET
    )
    response1 = file_definition.get_data()
    response1.data.raw
    

    You can the the X-API-Key from the API Playground.

    image.png

    The response contains the signed URLs.

    image.png

    Finally, you can directly download a file from the signedUrl.

  • amroeser
    amroeser Newcomer
    edited March 14

    Hi @Jirapongse

    Thanks for your detailed response! I followed your suggested approach, but I am still facing an issue with retrieving the signed URL for the document.

    1. bashKopierenBearbeitenhttps://api.refinitiv.com/user-framework/mobile/overview-service/v1/corp/filings/{RIC}The response correctly contains multiple filings along with documentId values and downloadUrl links.
    2. bashKopierenBearbeitenhttps://api.refinitiv.com/data/filings/v1/retrieval/search/docId/82606913I receive an empty response ({}) instead of the expected signed URL.
    Debugging Details:
    • I used the same X-API-Key from the API Playground as you suggested.
    • Since I already have access to filings in general, I would assume this is not a licensing issue. However, does this specific API require a different license or additional entitlements?
    • Here is my logging output:
    2025-03-14 17:28:20,470 - __main__ - INFO - Getting signed URL for first filing (DocumentId: 82606913)2025-03-14 17:28:20,470 - __main__ - INFO - Fetching signed URL for document 82606913...2025-03-14 17:28:20,573 - __main__ - INFO - Response received!2025-03-14 17:28:20,573 - __main__ - INFO - === DEBUG: Response.data.raw ===2025-03-14 17:28:20,573 - __main__ - INFO - Raw Content: {}
    

    This suggests that the API call is working but not returning any data.

    Questions:
    1. Is there any known issue with the filings/v1/retrieval/search/docId/{documentId} API that could cause it to return an empty response?
    2. Is there an alternative way to retrieve a secure URL to download the PDF?
    3. Do I need special entitlements to use this endpoint, or does it require a different license than general filings access?

    Any insights would be greatly appreciated!

    Thanks in advance for your help.

    Best regards,
    Alexander

  • Jirapongse
    Jirapongse ✭✭✭✭✭

    @amroeser

    Are you using the desktop.workspace or platorm.ldp session?

    I ran this code.

    file_url  = 'https://api.refinitiv.com/data/filings/v1/retrieval/search/docId/82606913'
    file_definition = ld.delivery.endpoint_request.Definition(
        url = file_url,
        header_parameters  = {'ClientID':'api_playground','X-API-Key':'xxx','Accept':'*/*'},
        method = ld.delivery.endpoint_request.RequestMethod.GET
    )
    response1 = file_definition.get_data()
    response1.data.raw
    

    The desktop.workspace session returns {}.

    image.png

    If I use the platform.ldp session, it returns the data properly.

    image.png
  • amroeser
    amroeser Newcomer

    Hi @Jirapongse!

    Thanks for your response!

    I am using the platform.ldp session, as you suggested. Here’s the relevant part of my config file and initialization:

    Bildschirmfoto 2025-03-17 um 10.27.21.png Bildschirmfoto 2025-03-17 um 10.25.17.png

    However, the response is still the same—an empty {} instead of the expected data.

    Would there be any additional configuration required for platform.ldp, or is there another possible reason why the API is returning an empty response in my case?

    Thanks again for your support!

    Best regards,

    Alexander

  • Jirapongse
    Jirapongse ✭✭✭✭✭

    @amroeser

    Can you enable the debug log in the library by adding the following configurations?

    {    
        "logs": {
            "level": "debug",
            "transports": {
                "console": {
                    "enabled": false
                },
                "file": {
                    "enabled": true,
                    "name": "lseg-data-lib.log"
                }
            }
        }
    

    The lseg-data-lib.log file will be created.

    Please remove your credentials from the log and then share it.

  • amroeser
    amroeser Newcomer

    Hi @Jirapongse

    Thanks for your help! I checked my logs, and it looks like the session is initializing correctly with platform.ldp. However, I am receiving a 403 Forbidden error when trying to retrieve the signed URL:

    [2025-03-17T12:25:14.832861+01:00] - [ld] - [DEBUG] - [8557611072 - MainThread] - [_configure] - [log_debug] - LD version is 2.0.1; Python version is 3.12.3 | packaged by Anaconda, Inc. | (main, May  6 2024, 14:46:42) [Clang 14.0.6 ][2025-03-17T12:25:14.833211+01:00] - [ld] - [DEBUG] - [8557611072 - MainThread] - [_configure] - [log_debug] - Installed packages (144): absl-py==2.1.0,anyio==4.2.0,appdirs==1.4.4,appnope==0.1.3,...[2025-03-17T12:25:14.833254+01:00] - [ld] - [DEBUG] - [8557611072 - MainThread] - [_configure] - [log_debug] - Read configs: ./lseg-data.config.json, /Users/.../Downloads/ldp test/lseg-data.config.json, /Users/.../lseg-data.config.json[2025-03-17T12:25:16.725018+01:00] - [session] - [DEBUG] - [8557611072 - MainThread] - [_session] - [__init__] - Creating session "sessions.platform.ldp.0" based on session.platform.Definition("platform.ldp")[2025-03-17T12:25:16.728202+01:00] - [sessions.platform.ldp.0] - [DEBUG] - [8557611072 - MainThread] - [_platform_session] - [_connection] - Created session connection SessionCxnType.PLATFORM_DATA[2025-03-17T12:25:16.728375+01:00] - [sessions.platform.ldp.0] - [DEBUG] - [8557611072 - MainThread] - [_session_provider] - [session_provider] - Session created: PlatformSessionname = ldpconnection = PlatformDataConnectionstream_auto_reconnection = Trueauthentication_token_endpoint_url = [REDACTED]signon_control = Trueserver_mode = Falsestate = OpenState.Closedsession_id = 0logger_name = sessions.platform.ldp.0[2025-03-17T12:25:16.728478+01:00] - [sessions.platform.ldp.0] - [DEBUG] - [8557611072 - MainThread] - [_session] - [open] - Open session[2025-03-17T12:25:16.763966+01:00] - [sessions.platform.ldp.0] - [DEBUG] - [8557611072 - MainThread] - [_auth_manager] - [authorize] - AuthManager: start authorize[2025-03-17T12:25:16.764183+01:00] - [sessions.platform.ldp.0] - [DEBUG] - [6210351104 - AuthManager-Thread] - [_auth_manager] - [_do_authorize] - AuthManager: Access token will be requested in 1e-05 seconds[2025-03-17T12:25:16.764319+01:00] - [sessions.platform.ldp.0] - [DEBUG] - [6210351104 - AuthManager-Thread] - [http_service] - [build_request] - HTTP Request id 0url = [REDACTED]method = POSTheaders = { 'Accept': 'application/json', 'x-tr-applicationid': '[REDACTED]' }data = { 'scope': 'trapi', 'grant_type': 'password', 'username': '[REDACTED]', 'password': '[REDACTED]', 'client_id': '[REDACTED]' }[2025-03-17T12:25:17.407485+01:00] - [sessions.platform.ldp.0] - [DEBUG] - [6210351104 - AuthManager-Thread] - [http_service] - [request] - HTTP Response id 0status_code = 200text = { "access_token":"[REDACTED]", "refresh_token":"[REDACTED]", "expires_in":"600" , "scope":"[REDACTED]", "token_type":"Bearer" }[2025-03-17T12:25:20.580776+01:00] - [sessions.platform.ldp.0] - [DEBUG] - [8557611072 - MainThread] - [http_service] - [request] - HTTP Response id 1status_code = 403text = {"error":{"id":"98f33373-9d88-4eff-a48f-878c9e0c70e1","code":"insufficient_scope","message":"access denied. Scopes required to access the resource: [trapi.data.filings.retrieval]. Missing scopes: [trapi.data.filings.retrieval]","status":"Forbidden"}}
    
    1. Does platform.ldp require additional permissions or a different license to access the filings/v1/retrieval/search/docId/{documentId} endpoint?
    2. Is there a way to check or request missing entitlements for this API?
    3. Is there an alternative way to programmatically download the filings (e.g., another API, direct download method, or a different session configuration)?

    I’d really appreciate any guidance on this—thanks again for your help!

    Best regards,
    Alexander

  • Jirapongse
    Jirapongse ✭✭✭✭✭

    @amroeser

    The "missing scopes" message indicates that the RDP account doesn't have permission to access the requested endpoint.

    Missing scopes: [trapi.data.filings.retrieval]
    

    Please contact your LSEG acount team or sales team directly to verify the permission.