LEAF REST API — Examples#

This notebook shows how to query the LEAF Portal REST API using Python.

Prerequisites#

pip install requests pandas

Authentication#

All endpoints require a token passed as a Bearer header:

Authorization: Bearer <token>

Tokens can be generated on the API Tokens page in the portal (/tokens).

Set your token as an environment variable before running this notebook:

export API_TOKEN=your_token_here

The base URL for all endpoints is https://leaf-portal.containers.wur.nl.

%pip install requests pandas
import os
import requests
import pandas as pd

BASE_URL = "https://leaf-portal.containers.wur.nl"

# Load API token from environment variable
# Set it in your terminal: export API_TOKEN=your_token_here
TOKEN = os.getenv("API_TOKEN", "")

if not TOKEN:
    print("Warning: API_TOKEN is not set. Requests will return 401.")

HEADERS = {"Authorization": f"Bearer {TOKEN}"}

GET /api/managements#

Lists all data managements accessible to your token. Each management represents a scoped slice of data (organisation → department → entity → time window) that your token has been granted access to.

Use the returned id values to query GET /api/data by management UUID (if supported), or use the organisation and department names as parameters.

response = requests.get(f"{BASE_URL}/api/managements", headers=HEADERS)

if response.status_code != 200:
    raise RuntimeError(f"Error {response.status_code}: {response.text}")

df = pd.DataFrame(response.json())
df.head()
id organisation department entity time_start time_end
0 c6200b9a-20f3-46ed-9c69-fd55b48f0701 RWTH AVT None None None
1 37881edb-6925-48c8-b2eb-4e1c980201ef WUR SSB None None None
2 dc940e69-0a68-4db6-9ed3-d54fca8828e3 UNLOCK FDP None None None
3 02c31ce3-cb65-44a4-b80b-3627d0697fa3 UNLOCK MBP None None None

GET /api/data/recent#

Returns the most recent sensor readings across all departments accessible to your token.

Parameter

Type

Default

Description

limit

int

20

Number of rows to return (max 1000)

response = requests.get(f"{BASE_URL}/api/data/recent", headers=HEADERS, params={"limit": 20})

if response.status_code != 200:
    raise RuntimeError(f"Error {response.status_code}: {response.text}")

df = pd.DataFrame(response.json())
df["time"] = pd.to_datetime(df["time"])
df.head()
time entity metric value tags department_id organisation_id
0 2026-03-18 08:50:30+00:00 ssb.bioind4 cpu.usage_idle 9.831245e+01 {'cpu': 'cpu-total', 'topic': 'ssb/server/ssb.... 74c70fdf-12d7-4982-bb2c-2e0d46fa31f0 c9ebd03f-c9c5-412a-99c9-5b05b3fe24aa
1 2026-03-18 08:50:30+00:00 ssb.bioind4 disk.free 2.922352e+10 {'mode': 'rw', 'path': '/docker', 'label': 'Vs... 74c70fdf-12d7-4982-bb2c-2e0d46fa31f0 c9ebd03f-c9c5-412a-99c9-5b05b3fe24aa
2 2026-03-18 08:50:30+00:00 ssb.bioind4 disk.used 1.702638e+11 {'mode': 'rw', 'path': '/docker', 'label': 'Vs... 74c70fdf-12d7-4982-bb2c-2e0d46fa31f0 c9ebd03f-c9c5-412a-99c9-5b05b3fe24aa
3 2026-03-18 08:50:30+00:00 ssb.bioind4 disk.used_percent 8.535069e+01 {'mode': 'rw', 'path': '/docker', 'label': 'Vs... 74c70fdf-12d7-4982-bb2c-2e0d46fa31f0 c9ebd03f-c9c5-412a-99c9-5b05b3fe24aa
4 2026-03-18 08:50:30+00:00 ssb.bioind4 mem.used 1.598564e+10 {'topic': 'ssb/server/ssb.bioind4/mem'} 74c70fdf-12d7-4982-bb2c-2e0d46fa31f0 c9ebd03f-c9c5-412a-99c9-5b05b3fe24aa

GET /api/data#

Returns sensor data for a specific organisation and department, with optional filters.

Parameter

Type

Required

Description

organisation

str

yes

Organisation name (e.g. WUR)

department

str

yes

Department name (e.g. SSB)

entity

str

no

Filter to a single entity

metric

str

no

Filter to a single metric

from

str

no

Start time, ISO 8601 (inclusive)

to

str

no

End time, ISO 8601 (exclusive)

limit

int

no

Max rows to return (default 1000, max 10000)

response = requests.get(
    f"{BASE_URL}/api/data",
    headers=HEADERS,
    params={
        "organisation": "WUR",
        "department": "SSB",
        "entity": "ssb.bioind4",
        "metric": "cpu.usage_idle",
        "from": "2026-03-17T00:00:00Z",
        "to": "2026-03-17T05:00:00Z",
        "limit": 1000,
    },
)

if response.status_code != 200:
    raise RuntimeError(f"Error {response.status_code}: {response.text}")

df = pd.DataFrame(response.json())
df["time"] = pd.to_datetime(df["time"])
df.head()
time entity metric value tags department_id organisation_id
0 2026-03-17 04:59:50+00:00 ssb.bioind4 cpu.usage_idle 96.811435 {'cpu': 'cpu-total', 'topic': 'ssb/server/ssb.... 74c70fdf-12d7-4982-bb2c-2e0d46fa31f0 c9ebd03f-c9c5-412a-99c9-5b05b3fe24aa
1 2026-03-17 04:59:40+00:00 ssb.bioind4 cpu.usage_idle 97.173711 {'cpu': 'cpu-total', 'topic': 'ssb/server/ssb.... 74c70fdf-12d7-4982-bb2c-2e0d46fa31f0 c9ebd03f-c9c5-412a-99c9-5b05b3fe24aa
2 2026-03-17 04:59:30+00:00 ssb.bioind4 cpu.usage_idle 96.985288 {'cpu': 'cpu-total', 'topic': 'ssb/server/ssb.... 74c70fdf-12d7-4982-bb2c-2e0d46fa31f0 c9ebd03f-c9c5-412a-99c9-5b05b3fe24aa
3 2026-03-17 04:59:20+00:00 ssb.bioind4 cpu.usage_idle 96.939482 {'cpu': 'cpu-total', 'topic': 'ssb/server/ssb.... 74c70fdf-12d7-4982-bb2c-2e0d46fa31f0 c9ebd03f-c9c5-412a-99c9-5b05b3fe24aa
4 2026-03-17 04:59:10+00:00 ssb.bioind4 cpu.usage_idle 97.074690 {'cpu': 'cpu-total', 'topic': 'ssb/server/ssb.... 74c70fdf-12d7-4982-bb2c-2e0d46fa31f0 c9ebd03f-c9c5-412a-99c9-5b05b3fe24aa