Quick start

API credentials

Before accessing IHME Portal API you need to obtain credentials in the API Accessarrow-up-right tab on the Profilearrow-up-right page. If you don't see such tab, please contact your organization manager to enable API access for you.

First choose a data collection

Before querying any data, first call the Data Collection API to list the data collections shared with your organization and pick one to work with. The collection tells you which datasets and filters are available so you can construct valid queries. Start with GET /my-organization/group-content-data-collection-resources, then drill into granularity for the dataset you plan to query.

Example

Explore the IHME Portal API using the following Python code snippet:

import base64
import json
import hmac
import hashlib

from requests import Request, Session
from datetime import date
from urllib import parse

ACCESS_KEY = '<put your access key here>'
SECRET_KEY = '<put your secret key here>'
BASE_URL = 'https://portal-api.ihme.services'

class IhmePortalApi:
    def __init__(self, base_url, access_key, secret_key):
        self.session = Session()
        self.base_url = base_url
        self.access_key = access_key
        self.secret_key = secret_key

    def calculate_request_signature(self, request):
        todays_date = date.today() \
            .strftime('%Y-%m-%d')

        string_to_sign = ' ' \
            .join([
                request.method, 
                request.path_url, 
                todays_date
            ]) \
            .encode('utf-8')

        secret_key_bytes = base64.b64decode(self.secret_key)

        signature_bytes = hmac \
            .new(secret_key_bytes, string_to_sign, hashlib.sha256) \
            .digest()

        return base64 \
            .b64encode(signature_bytes) \
            .decode('utf-8')

    def request(self, method, endpoint, params={}, headers={}):
        request = Request(method, self.base_url + endpoint, params=params, headers=headers) \
            .prepare()

        signature = self.calculate_request_signature(request)

        request.headers['Authorization'] = 'IHME ' + self.access_key + ':' + signature

        return self.session.send(request)

    def get(self, endpoint, params={}):
        response = self.request('GET', endpoint, params)
        decoded = json.loads(response.content)

        if response:
            return decoded['data']
        else:
            raise Exception(decoded['error']['message'])

api = IhmePortalApi(BASE_URL, ACCESS_KEY, SECRET_KEY)

# Get a list of data collections shared with my organization
data_collections = api.get('/my-organization/group-content-data-collection-resources')['results']

# Pick which one we want to query
data_collection = data_collections[0]

# Data collection is a collection of several datasets, select which dataset we want to query
dataset = next((d for d in data_collection['datasets'] if d['data_type'] == 'cause_outcome'))

# Get the id of the round we are interested in
rounds = api.get('/rounds')
gbd2023_round_id = next((r['id'] for r in rounds if r['name'] == 'GBD 1990-2024')) # 9

# Get the ids of the causes we are interested in
causes = api.get('/causes')
malaria_cause_id = next((c['id'] for c in causes if c['name'] == 'Malaria')) # 345
tuberculosis_cause_id = next((c['id'] for c in causes if c['name'] == 'Tuberculosis')) # 297

# You can also use constants for the ids as they never change
usa_location_id = 102
all_ages_age_group_id = 22
female_gender_id = 2
male_gender_id = 1
daly_measure_id = 2
rate_metric_id = 3
reference_forecast_scenario_id = 1

# Dataset has data only for values that are present in the granularity. The filter values should be picked based on it
assert gbd2023_round_id in dataset['granularity']['round_id']
assert malaria_cause_id in dataset['granularity']['cause_id']
assert tuberculosis_cause_id in dataset['granularity']['cause_id']

# For the rest of the filters it's possible to refine available granularity based on the selected cause and round
# to minimize the chance of choosing a combination of filters that do not return data
refined_granularity = api.get(
    '/my-organization/data-collection-resources/{:d}/datasets/cause_outcome/granularity'.format(data_collection['id']),
    {
        'primary_entity_id': ','.join(map(str, [malaria_cause_id, tuberculosis_cause_id])),
        'round_id': gbd2023_round_id
    }
)

assert usa_location_id in refined_granularity['location_id']

# Query the data we are interested in
data = api.get(
    '/my-organization/data-collection-resources/{:d}/datasets/cause_outcome/data'.format(data_collection['id']),
    {
        'round_id': gbd2023_round_id,
        'location_id': usa_location_id,
        'age_group_id': all_ages_age_group_id,
        'gender_id': ','.join(map(str, [female_gender_id, male_gender_id])),
        'measure_id': daly_measure_id,
        'metric_id': rate_metric_id,
        'cause_id': ','.join(map(str, [malaria_cause_id, tuberculosis_cause_id])),
        'forecast_scenario_id': reference_forecast_scenario_id
    }
)

Last updated