Get a demo

Get in touch

Prefer using email? Write us at hello@moveshelf.com

Developer – Querying data

    Search Knowledge Base
Getting started
  • Setting up the environment
  • Setting up a GitHub repository
  • Setting up the Moveshelf API
  • Recording - Intro to Moveshelf API
  • Using the API
  • Moveshelf API documentation
  • Configuration and authentication
  • Use built-in functions
  • Examples provided by Moveshelf
  • Importing data
  • Create subject
  • Import subject metadata
  • Create session
  • Import session metadata
  • Create trial
  • Upload data files
  • Create interactive reports
  • Querying data
  • Retrieve a filtered subset of subjects
  • Retrieve a filtered subset of sessions
  • Retrieve a subject
  • Retrieve subject metadata
  • Retrieve session
  • Retrieve session metadata
  • Export metadata to Excel
  • Retrieve trials
  • Retrieve data files
  • Deleting data
  • Delete a subject
  • Delete multiple subjects
  • Delete a session
  • Delete a trial
  • Delete all trials within a condition
  • Delete a data file
  • Example scripts
  • Public repository
  • Download data
  • Download large data sets
  • Batch upload data
  • Pre vs post intervention data export
  • Extending the Moveshelf API
  • Extending the Moveshelf API
  • Retrieve and query subjects, sessions, conditions, trials and data from Moveshelf.



    Retrieve a filtered subset of subjects

    Query execution time increases proportionally with the amount of data being retrieved. When you query a project with hundreds of subjects or more, it is highly recommended to retrieve a filtered subset.

    This section explains how to exploit the Moveshelf API's server-side filtering functionality to retrieve a subset of subjects in a project on Moveshelf that meet a set of subject metadata, session date, and session count criteria. Filtering is particularly useful when you only need to retrieve subjects with certain characteristics (such as a specific diagnosis), or subjects that have a certain number of sessions within a specific time period.
    Prerequisites
    Before implementing this example, ensure that your processing script includes all necessary setup steps. In particular, you should have:
    Implementation
    The function getFilteredProjectSubjects returns a list subjects filtered by subject metadata and by session date and session count. Subject metadata and session filters can be combined or used individually. This section explains how to construct subject metadata filters and session filters, and provides the implementation of an example use case.

    Subject metadata filters can be constructed in the following way:
    subject_metadata_filters = {
        "key": "<metadata_key>" # e.g., "subject-sex"
        "operator": "EQ" # currently, only EQ is supported
        "value": "<metadata_value>" # e.g., "Male"
    }       

    It is also possible to concatenate subject metadata filters with a certain logic. For example, to find all female patients diagnosed with Cerebral Palsy or ACL Rupture:
    subject_metadata_filters = {
        "logic": "AND", # Supported logics: AND, OR
        "filters": [
            { "key": "subject-sex", "operator": "EQ", "value": "Female" },
            {
                "logic": "OR",
                "filters": [
                    { "key": "subject-diagnosis", "operator": "EQ", "value": "Cerebral Palsy" },
                    { "key": "subject-diagnosis", "operator": "EQ", "value": "ACL Rupture" }
                ]
            }
        ]
    }   

    Session filters can be constructed in the following way. Please note that for subjects that meet the requirements defined in session_filters, ALL sessions will still be returned, as the filter operation returns a set of subjects.
    session_filters = {
        "sessionDates": {
            "startDate": None or "<startDate>"  # start date (inclusive) in "YYYY-MM-DD" format or None,
            "endDate": None or "<endDate>"  # end date (inclusive) in "YYYY-MM-DD" format or None,
        },
        "numSessions": {
            "min": None or <int> # minimum number of sessions (inclusive)
            "max": None or <int> # maximum number of sessions (inclusive)
        }
    }

    To retrieve all female patients diagnosed with Cerebral Palsy or ACL Rupture with exactly two sessions between 01-01-2013 and 30-04-2020, you could use:
    ## README: this example shows how we can retrieve sessions from Moveshelf 
    # using the Moveshelf API.
    
    ## General configuration. Set values before running the script
    my_project = "<organizationName/projectName>"  # e.g. support/demoProject
    subject_metadata_filters = {
        "logic": "AND", # Supported logics: AND, OR
        "filters": [
            { "key": "subject-sex", "operator": "EQ", "value": "Female" },
            {
                "logic": "OR",
                "filters": [
                    { "key": "subject-diagnosis", "operator": "EQ", "value": "Cerebral Palsy" },
                    { "key": "subject-diagnosis", "operator": "EQ", "value": "ACL Rupture" }
                ]
            }
        ]
    }  
    session_filters = {
        "sessionDates": {
            "startDate": "01-01-2013",
            "endDate": "30-04-2020"
        },
        "numSessions": {
            "min": 2,
            "max": 2
        }
    }
    
    ## Get available projects
    projects = api.getUserProjects()
    
    ## Select the project
    project_names = [project["name"] for project in projects if len(projects) > 0]
    idx_my_project = project_names.index(my_project)
    my_project_id = projects[idx_my_project]["id"]
    
    ## Get all subjects in the project that fullfill metadata criteria
    ## Set include_additional_data to True to also retrieve
    ## clips/trials and data files
    subjects = api.getFilteredProjectSubjects(
        my_project_id,
        subject_metadata_filters=subject_metadata_filters,
        session_filters=session_filters,
        include_additional_data=False
    )
           

    With the retrieved subset of subjects, you can proceed with further analysis. For example, you may wish to use Python to filter further by intervention metadata or session metadata, or kinematic data. Our examples below may come in helpful during the analysis, but other analysis or statistical programs such as Excel, R or SPSS may also be helpful.

    To facilitate the data export, we have provided an example demonstrating how to export subject and session metadata to an Excel spreadsheet. Another complete end-to-end example is provided in Pre vs post intervention data export, which demonstrates how to identify and extract relevant sessions around a specific intervention and export the results.
    Downloading Data Files
    To also retrieve data files (clips and additional data) for the filtered subjects, set include_additional_data=True. This is the most efficient approach for "filter once and download all" workflows:
    import requests
    from concurrent.futures import ThreadPoolExecutor
    
    # Use a requests.Session for connection pooling and helper functions
    MAX_WORKERS = 5 # Number of threads for parallel processing.
    POOL_MAXSIZE = MAX_WORKERS + 2  # Set slightly higher than max_workers to avoid connection issues
    requests_session = requests.Session()
    adapter = requests.adapters.HTTPAdapter(pool_maxsize=POOL_MAXSIZE)
    requests_session.mount('https://', adapter)
    
    def download_with_session(url: str) -> dict | None:
        return download_json_file(url, session=requests_session)
    
    def download_json_file(url: str, session: requests.Session | None = None) -> dict | None:
        try:
            response = session.get(url) if session else requests.get(url)
            decoded_content = response.content.decode()
            return json.loads(decoded_content)
        except Exception as e:
            print(f"Failed to download or parse {url}: {e}")
            return None
    
    ## Retrieve subjects with their data files
    subjects = api.getFilteredProjectSubjects(
        my_project_id,
        subject_metadata_filters=subject_metadata_filters,
        session_filters=session_filters,
        include_additional_data=True  # Include clips and data files
    )
    ## Collect download URLs and file paths
    file_extension_to_download = '.json'
    URLs = []
    
    for subject in subjects:
        for session in subject.get("sessions", []):
            for clip in session.get("clips", []):
                for ad in clip.get("additionalData", []):
                    if ad["originalDataDownloadUri"].endswith(file_extension_to_download):
                        URLs.append(ad["originalDataDownloadUri"])
    
    # Download additional data in parallel
    with ThreadPoolExecutor(max_workers=MAX_WORKERS) as executor:
        additional_data = list(executor.map(download_with_session, URLs))

    When defining MAX_WORKERS and POOL_MAXSIZE, make sure you add the following line after configuring and initializing the Moveshelf API: api.http.connection_pool_kw['maxsize'] = POOL_MAXSIZE .

    For more details on efficient parallel downloading, see Download large data sets.


     

    Retrieve a filtered subset of sessions

    Query execution time increases proportionally with the amount of data being retrieved. When you query a project with hundreds of sessions or more, it is highly recommended to retrieve a filtered subset.

    This section explains how to exploit the Moveshelf API's server-side filtering functionality to retrieve a subset of sessions in a project on Moveshelf that meet specific subject metadata, session metadata, and date range criteria. Filtering is particularly useful when you only need to retrieve sessions with certain characteristics (such as a specific session type or medical diagnosis).
    Prerequisites
    Before implementing this example, ensure that your processing script includes all necessary setup steps. In particular, you should have:
    Implementation
    The function getFilteredProjectSessions returns a list of sessions filtered by date range, session metadata, and subject metadata. For convenience, you can directly copy the URL of your filtered Sessions overview, which automatically applies all your filters.

    The getFilteredProjectSessions function also accepts an optional parameter limit, an integer that specifies the maximum number of sessions to be returned. If not specified, it defaults to 500, mimicking the behavior of the Sessions overview feature. Make sure to specify a larger number if more sessions should be retrieved.

    Method 1: Using sessions overview URL
    This is the easiest approach. After filtering sessions in Sessions overview, simply copy the URL from your browser:
    ## README: this example shows how to retrieve filtered sessions from Moveshelf 
    # using the Moveshelf API.
    
    ## Copy the URL from your filtered sessions overview page
    url = "https://moveshelf.com/project/ID123/sessions?startDate=Last_year&sessioninfo-cancellation=Cancelled"
    
    ## Extract project_id from URL (comes after /project/)
    project_id = url.split('/project/')[1].split('/')[0]
    
    ## Retrieve filtered sessions
    sessions = api.getFilteredProjectSessions(
        project_id=project_id,
        session_overview_url=url
    )
    
    print(f"Found {len(sessions)} sessions matching the filters")
           

    Method 2: Using explicit filters (alternative)
    For programmatic control, you can specify filters explicitly.
    Session metadata filters
    session_metadata_filters = {
        {
            "key": "<metadata_key>", # e.g., "sessioninfo-date-processing-completed"
            "operator": "BETWEEN", 
            "values": "<metadata_values>" # e.g., start and end dates (inclusive) as ['YYYY-MM-DD', 'YYYY-MM-DD']
        } ,
        # add more filter dicts as needed
    }
    Subject metadata filters
    patient_metadata_filters = [
        {
            "key": "<metadata_key>", # e.g., "subject-sex",
            "operator": "EQ", 
            "value": "<metadata_value>" # e.g., "Female"
        } ,
        # add more filter dicts as needed
    ]

    Supported operators include:
    • IN: Match any of the provided values
    • EQ: Match a single exact value
    • BETWEEN: Match a range (for dates)

    Note: When building filter objects, use the key values (an array) with the IN and BETWEEN operators, and use the key value (a single value) with the EQ operator.


    Example using explicit filters:
    ## Define session metadata filters
    session_metadata_filters = [
        {
            'key': 'sessioninfo-cancellation', 
            'operator': 'IN', 
            'values': ['Cancelled', 'no show']
        }, 
        {
            'key': 'sessioninfo-date-processing-completed', 
            'operator': 'BETWEEN', 
            'values': ['2025-01-01', '2025-12-31']
        }
    ]
    ## Define patient metadata filters
    patient_metadata_filters = [
        {
            'key': 'subject-sex',
            'operator': 'EQ',
            'value': 'Female'
        }
    ]
    
    ## Get filtered sessions
    sessions = api.getFilteredProjectSessions(
        my_project_id,
        start_date='2025-01-01',
        end_date='2025-12-31',
        session_metadata_filters=session_metadata_filters,
        patient_metadata_filters=patient_metadata_filters,
        include_additional_data=False
    )
    
    print(f"Found {len(sessions)} sessions matching the filters")

    With the retrieved subset of sessions, you can proceed with further analysis. For example, you may wish to Retrieve session metadata, Retrieve subject metadata, Download data files, or perform statistical analysis. Other analysis programs such as Excel, R, or SPSS may also be helpful. To facilitate the data export, we have provided an example demonstrating how to export subject and session metadata to an Excel spreadsheet.
    Download data files
    To also retrieve data files (clips and additional data) for the filtered sessions, set include_additional_data=True. This is the most efficient approach for "filter once and download all" workflows. You can then download and save files in parallel for maximum efficiency:
    import requests
    from concurrent.futures import ThreadPoolExecutor
    
    # Use a requests.Session for connection pooling and helper functions
    MAX_WORKERS = 5 # Number of threads for parallel processing.
    POOL_MAXSIZE = MAX_WORKERS + 2  # Set slightly higher than max_workers to avoid connection issues
    requests_session = requests.Session()
    adapter = requests.adapters.HTTPAdapter(pool_maxsize=POOL_MAXSIZE)
    requests_session.mount('https://', adapter)
    
    def download_with_session(url: str) -> dict | None:
        return download_json_file(url, session=requests_session)
    
    def download_json_file(url: str, session: requests.Session | None = None) -> dict | None:
        try:
            response = session.get(url) if session else requests.get(url)
            decoded_content = response.content.decode()
            return json.loads(decoded_content)
        except Exception as e:
            print(f"Failed to download or parse {url}: {e}")
            return None
    
    ## Retrieve sessions with their data files
    sessions = api.getFilteredProjectSessions(
        my_project_id,
        start_date='2025-01-01',
        end_date='2025-12-31',
        session_metadata_filters=session_metadata_filters,
        patient_metadata_filters=patient_metadata_filters,
        include_additional_data=True  # Include clips and data files
    )
    ## Collect download URLs and file paths
    file_extension_to_download = '.json'
    URLs = []
    for session in sessions:
        for clip in session.get("clips", []):
            for ad in clip.get("additionalData", []):
                if ad["originalDataDownloadUri"].endswith(file_extension_to_download):
                    URLs.append(ad["originalDataDownloadUri"])
    
    # Download additional data in parallel
    with ThreadPoolExecutor(max_workers=MAX_WORKERS) as executor:
        additional_data = list(executor.map(download_with_session, URLs))

    When defining MAX_WORKERS and POOL_MAXSIZE, make sure you add the following line after configuring and initializing the Moveshelf API: api.http.connection_pool_kw['maxsize'] = POOL_MAXSIZE .

    For more details on efficient parallel downloading, see Download large data sets.


     

    Retrieve a subject
    This section explains how to retrieve a subject from Moveshelf using the Moveshelf API, based on the subject's MRN/EHR-ID.
    • If a matching subject is found, it is retrieved
    • If no matching subject is found, a message is displayed
    Prerequisites
    Before implementing this example, ensure that your processing script includes all necessary setup steps. In particular, you should have:
    Implementation
    To retrieve an existing subject, add the following lines of code to your processing script:
    ## README: this example shows how we can retrieve a subject from Moveshelf 
    # using the Moveshelf API.
    # For a given project (my_project), retrieve a subject based on either the given MRN (my_subject_mrn) 
    # or the subject name (my_subject_name)
    
    ## General configuration. Set values before running the script
    my_project = "<organizationName/projectName>"  # e.g. support/demoProject
    my_subject_mrn = "<subjectMRN>"  # subject MRN, e.g. "1234567", set to None if you want to use the name
    my_subject_name = "<subjectName>"  # subject name, set to None if you want to use the MRN
    
    ## Get available projects
    projects = api.getUserProjects()
    
    ## Select the project
    project_names = [project["name"] for project in projects if len(projects) > 0]
    idx_my_project = project_names.index(my_project)
    my_project_id = projects[idx_my_project]["id"]
    
    ## Find the subject based on MRN or name
    subject_found = False
    if my_subject_mrn is not None:
        subject = api.getProjectSubjectByEhrId(my_subject_mrn, my_project_id)
        if subject is not None:
            subject_found = True
    if not subject_found and my_subject_name is not None:
        subjects = api.getProjectSubjects(my_project_id)
        for subject in subjects:        
            if my_subject_name == subject['name']:
                subject_found = True
                break
    if my_subject_mrn is None and my_subject_name is None:
        print("We need either subject mrn or name to be defined to be able to search for the subject.")
    
    ## Print message
    if subject_found:
        subject_details = api.getSubjectDetails(subject["id"])
        subject_metadata = json.loads(subject_details.get("metadata", "{}"))
        print(
            f"Found subject with name: {subject_details['name']},\n"
            f"id: {subject_details['id']}, \n"
            f"and MRN: {subject_metadata.get('ehr-id', None)}"
        )
    else:
        print(
            f"Couldn't find subject with MRN: {my_subject_mrn},\n"
            f"in project: {my_project}"
        )


     

    Retrieve subject metadata
    This example demonstrates how to retrieve subject metadata for an existing subject on Moveshelf via the Moveshelf API.
    Prerequisites
    Before implementing this example, ensure that your processing script includes all necessary setup steps. In particular, you should have:
    Implementation
    To retrieve subject metadata from an existing subject, add the following lines of code to your processing script:
    ## README: this example shows how we can retrieve subject metadata from an existing subject on 
    # Moveshelf using the Moveshelf Python API.
    # This code assumes you have implemented the 'Retrieve subject' example, and that you have found 
    # the subject with a given EHR-id/MRN (my_subject_mrn) or name (my_subject_name) within a given 
    # project (my_project), that you have access to the subject ID and obtained the "subject_details"
    
    
    ## General configuration. Set values before running the script
    my_project = "<organizationName/projectName>"  # e.g. support/demoProject
    my_subject_mrn = "<subjectMRN>"  # subject MRN, e.g. "1234567" or None
    my_subject_name = "<subjectName>"  # subject name, e.g. Subject1 or None
    
    ## Add here the code to retrieve the project and get the "subject_details" for that subject
    
    subject_metadata = json.loads(subject_details.get("metadata", "{}"))
    print(
        f"Found subject with name: {subject_details['name']},\n"
        f"id: {subject_details['id']}, \n"
        f"and metadata: {subject_metadata}"
    ) 
             


     

    Retrieve session
    This section explains how to retrieve a session with a specific date for a subject with a specified MRN on Moveshelf using the Moveshelf API.
    Prerequisites
    Before implementing this example, ensure that your processing script includes all necessary setup steps. In particular, you should have:
    Implementation
    To retrieve a session with a specific date from a subject, add the following lines of code to your processing script:
    ## README: this example shows how we can retrieve sessions from Moveshelf 
    # using the Moveshelf API.
    # This code assumes you have implemented the 'Retrieve subject' example, and
    # that you have found the subject with a given EHR-id/MRN (my_subject_mrn)
    # or name (my_subject_name) within a given project (my_project), and that you 
    # have access to the subject ID. 
    # Then, for that subject, retrieve the session with the specified date 
    # (my_session_date).
    
    
    ## General configuration. Set values before running the script
    my_project = "<organizationName/projectName>"  # e.g. support/demoProject
    my_subject_mrn = "<subjectMRN>"  # subject MRN, e.g. "1234567" or None
    my_subject_name = "<subjectName>"  # subject name, e.g. Subject1 or None
    my_session_date = "<sessionDate>" # "YYYY-MM-DD" format
    
    ## Add here the code to retrieve the project and find an existing subject and its "subject_details"
    # ... subject_found = True
    
    ## Get sessions
    sessions = subject_details.get("sessions", [])
    
    # Loop over sessions
    session_found = False
    for session in sessions:
        try:
            date_obj = datetime.fromisoformat(session["date"])
            session_date = date_obj.strftime('%Y-%m-%d')
        except:
            session_date = ""
        if session_date == my_session_date:
            session_found = True
            session_id = session["id"]
            print(
                f"Found session with date: {my_session_date},\n"
                f"and id: {session_id}"
            )
            break
    
    if not session_found:
        print(
            f"Couldn't find session with date: {my_session_date},\n"
            f"for subject with MRN: {my_subject_mrn}"
        ) 
           


     

    Retrieve session metadata
    This section explains how to retrieve session metadata for a specified session for a subject with a specified MRN on Moveshelf using the Moveshelf API.
    Prerequisites
    Before implementing this example, ensure that your processing script includes all necessary setup steps. In particular, you should have:
    Implementation
    To retrieve session metadata from a specific session and subject, add the following lines of code to your processing script:
    ## README: this example shows how we can retrieve session metadata from Moveshelf 
    # using the Moveshelf API.
    # This code assumes you have implemented the 'Retrieve sessopm' example, and
    # that you have found session with the specified date 
    # (my_session_date) for the subject with a given EHR-id/MRN 
    # (my_subject_mrn) or name (my_subject_name) within a given project (my_project), and 
    # that you have access to the session ID.
    
    ## General configuration. Set values before running the script
    my_project = "<organizationName/projectName>"  # e.g. support/demoProject
    my_subject_mrn = "<subjectMRN>"  # subject MRN, e.g. "1234567" or None
    my_subject_name = "<subjectName>"  # subject name, e.g. Subject1 or None
    my_session_date = "<sessionDate>" # "YYYY-MM-DD" format
    
    ## Add here the code to retrieve the project and find an existing subject and session using "getSessionById"
    
    session_id = session["id"]
    session_metadata = session.get("metadata", None)
    print(
        f"Found session with projectPath: {session['projectPath']},\n"
        f"id: {session_id},\n"
        f"and metadata: {session_metadata}"
    )
           


     

    Export metadata to Excel
    This section explains how to export subject and session metadata from a list of subjects or sessions, e.g., resulting from Retrieve a filtered subset of subjects or Retrieve a filtered subset of sessions, to an Excel spreadsheet.
    Prerequisites
    Before implementing this example, ensure that your processing script includes all necessary setup steps. In particular, you should have:
    Implementation
    To export subject and session metadata to an Excel spreadsheet, add the following lines of code to your processing script, right after having Retrieved a subject or list of subjects, OR Retrieved a session or list of sessions. The example uses the MetadataExcelExporter class which can be found in the utils folder as part of metadata_excel_exporter.py in our public GitHub repository. Copy the utils folder inside your work environment and add the following lines of code to your processing script:

    from utils import MetadataExcelExporter
    
    ## ============================================================================
    ## CONFIGURATION VARIABLES - Edit these before running
    ## ============================================================================
    OUTPUT_FILENAME = "Metadata_Export.xlsx"
    
    # Specify which fields to export (leave empty for all)
    SUBJECT_METADATA_FIELDS: list[str] = ['ehr-id', 'subject-diagnosis']
    SESSION_METADATA_FIELDS: list[str] = ['vicon-height', 'vicon-weight', 'interview-assistive-device']
    
    # Column header format configuration
    # When True: Use metadata field IDs as column headers
    # (e.g., 'sessioninfo-comments', 'vicon-leg-length-right')
    # When False: Use descriptive labels with tab context
    # (e.g., 'Session info: Comments', 'Physical exam 1: Leg length (mm) - right')
    USE_METADATA_ID_AS_COLUMN_HEADER: bool = True
    
    # Create exporter instance
    exporter = MetadataExcelExporter(
        api,
        use_metadata_id_as_column_header=USE_METADATA_ID_AS_COLUMN_HEADER
    )
    
    # Export metadata. Uncomment one of the following options (Option 1 or Option 2)
    # # Option 1: Export metadata for a list of subjects
    # subjects_list = subjects # e.g., the output from Retrieving a subset of subjects
    ## Note: It is also possible to export metadata from a single subject by assigning 
    ## subjects_list = [subject_details] # where subject_details results from the Retrieve a subject example 
    
    # exporter.export_metadata_to_excel(
    #     project_id=my_project_id,
    #     output_filename=OUTPUT_FILENAME,
    #     subjects_list=subjects_list,
    #     subject_fields=SUBJECT_METADATA_FIELDS,
    #     session_fields=SESSION_METADATA_FIELDS
    # )
    
    # # Option 2: Export metadata for a list of sessions
    # # Sessions will be automatically grouped by patient in export_metadata_to_excel
    # sessions_list = sessions # e.g., the output from Retrieving a subset of sessions
    ## Note: It is also possible to export metadata from a single session by assigning 
    ## sessions_list = [session] # where session results from the Retrieve a session example 
    
    # exporter.export_metadata_to_excel(
    #     project_id=my_project_id,
    #     output_filename=OUTPUT_FILENAME,
    #     sessions_list=sessions_list,
    #     subject_fields=SUBJECT_METADATA_FIELDS,
    #     session_fields=SESSION_METADATA_FIELDS
    # )
           

    To display descriptive labels as column headers instead of unique metadata field IDs, set USE_METADATA_ID_AS_COLUMN_HEADER to False.


     

    Retrieve trials
    This section explains how to retrieve trials within a specific condition of a specific session for a subject with a specified MRN on Moveshelf using the Moveshelf API.
    Prerequisites
    Before implementing this example, ensure that your processing script includes all necessary setup steps. In particular, you should have:
    Implementation
    To retrieve the trials within a specific condition, add the following lines of code to your processing script:
    ## README: this example shows how we can retrieve trials from Moveshelf 
    # using the Moveshelf API.
    # This code assumes you have implemented the 'Retrieve subject' example, 
    # that you have found the subject with a given EHR-id/MRN (my_subject_mrn)
    # or name (my_subject_name) within a given project (my_project), that you 
    # have access to the subject ID, and you have implemented the 
    # 'Retrieve session' example to retrieve the specified session (my_session_name).
    
    
    ## General configuration. Set values before running the script
    my_project = "<organizationName/projectName>"  # e.g. support/demoProject
    my_subject_mrn = "<subjectMRN>"  # subject MRN, e.g. "1234567" or None
    my_subject_name = "<subjectName>"  # subject name, e.g. Subject1 or None
    my_session_name = "<sessionDate>" # "YYYY-MM-DD" format
    my_condition = "<conditionName>"  # e.g. "Barefoot"
    
    ## Add here the code to retrieve the project and find an existing subject and its "subject_details"
    # ... subject_found = True
    
    ## Add here the code to retrieve an existing session and get its details using "getSessionById"
    
    # Get conditions in the session
    conditions = []
    conditions = util.getConditionsFromSession(session, conditions)
    
    condition_exists = any(c["path"].replace("/", "") == my_condition for c in conditions)
    condition = next(c for c in conditions if c["path"].replace("/", "") == my_condition) \
        if condition_exists else {"path": my_condition, "clips": []}
    trial_count = len(condition["clips"]) if condition_exists else 0
    clips_in_condition = [clip for clip in condition["clips"]] if condition_exists and trial_count > 0 else []
    
    # get the id and title of each clip
    for clip in clips_in_condition:
        clip_id = clip["id"]
        clip_title = clip["title"]
    
        print(
            f"Found a clip with title: {clip_title},\n"
            f"and id: {clip_id}"
        ) 
           


     

    Retrieve data files
    This section explains how to retrieve data (files) within a specific trial of a condition within a session of a subject (specified by MRN) on Moveshelf using the Moveshelf API.
    Prerequisites
    Before implementing this example, ensure that your processing script includes all necessary setup steps. In particular, you should have:
    Implementation
    To retrieve the additional data files with that trial, add the following lines of code to your processing script:
    ## README: this example shows how we can retrieve additional data from 
    # Moveshelf using the Moveshelf API.
    # This code assumes you have implemented the 'Retrieve subject' example, 
    # that you have found the subject with a given EHR-id/MRN (my_subject_mrn)
    # or name (my_subject_name) within a given project (my_project), that you 
    # have access to the subject ID, you have implemented the 'Retrieve session' 
    # example, and you have implemented the 'Retrieve trial' example to get or 
    # create the specified trial (my_trial) within a specific condition (my_condition).
    
    ## Import necessary modules
    import requests # Used to send HTTP requests to retrieve additional data files from Moveshelf
    
    ## General configuration. Set values before running the script
    my_project = "<organizationName/projectName>"  # e.g. support/demoProject
    my_subject_mrn = "<subjectMRN>"  # subject MRN, e.g. "1234567" or None
    my_subject_name = "<subjectName>"  # subject name, e.g. Subject1 or None
    my_session_name = "<sessionDate>" # "YYYY-MM-DD" format
    my_condition = "<conditionName>"  # e.g. "Barefoot"
    my_trial = "<trialName>"
    filter_by_extension = None
    
    ## Add here the code to retrieve the project and find an existing subject and its "subject_details"
    # ... subject_found = True
    
    ## Add here the code to retrieve an existing session and get its details using "getSessionById"
    
    ## Add here the code to retrieve an existing trial and get the ID: clip_id
    
    # get all additional data
    existing_additional_data = api.getAdditionalData(clip_id)
    # if filter_by_extension is provided, only get the data with that extension
    existing_additional_data = [
        data for data in existing_additional_data if not filter_by_extension
        or os.path.splitext(data["originalFileName"])[1].lower() == filter_by_extension]
    existing_file_names = [data["originalFileName"] for data in existing_additional_data if 
        len(existing_additional_data) > 0]
    
    print("Existing data for clip: ")
    print(*existing_file_names, sep = "\n")
    
    # Loop through the data found, and download if the "uploadStatus" is set to "Complete"
    # The data will be available in "file_data", from which it can e.g. be used to 
    # process, or written to a file on local storage
    for data in existing_additional_data:
        if data["uploadStatus"] == "Complete":
            file_data = requests.get(data["originalDataDownloadUri"]).content
           
    PDF/image files
    PDF files and image files (e.g. ".jpg" or ".png") can be stored as part of a trial and retrieved following the example before, but on Moveshelf we have a dedicated place for PDF/image files, so these are picked up e.g. when exporting to a Word document. For this, PDF/image files are stored in a condition called "Additional files" with a trial per PDF/image and a name that is typically the same as the PDF/image file name in that trial. To retrieve, the code as shown above can be used, with the following modifications:
    ## Modifications needed to extract PDF/image files stored within "Additional files"
    my_condition = "Additional files"
    filter_by_extension = ".pdf"  # to be modified based on the required extension
           
    Raw motion data - ZIP
    For raw motion data provided in a ZIP archive, we suggest to use the same "Additional files" condition that is also used for PDF/image files. Specifically, for ZIP files with raw motion data we suggest to use a trial named "Raw motion data". The code to retrieve the data from this trial is similar to the PDF/image example above, but this time specify the specific trial name my_trial you first search for the specific trial:
    ## Modifications needed to extract ZIP files stored within "Additional files"
    my_condition = "Additional files"
    my_trial = "Raw motion data"        # To be modified based on the exact trial that is required.
    
    filter_by_extension = ".zip"  # set to None to get all data in the trial