{ "cells": [ { "cell_type": "markdown", "id": "be7fdc69", "metadata": {}, "source": [ "# LEAF REST API — Examples\n", "\n", "This notebook shows how to query the LEAF Portal REST API using Python.\n", "\n", "## Prerequisites\n", "\n", "```bash\n", "pip install requests pandas\n", "```\n", "\n", "## Authentication\n", "\n", "All endpoints require a token passed as a Bearer header:\n", "\n", "```\n", "Authorization: Bearer \n", "```\n", "\n", "Tokens can be generated on the **API Tokens** page in the portal (`/tokens`).\n", "\n", "Set your token as an environment variable before running this notebook:\n", "\n", "```bash\n", "export API_TOKEN=your_token_here\n", "```\n", "\n", "The base URL for all endpoints is `https://leaf-portal.containers.wur.nl`." ] }, { "cell_type": "code", "execution_count": null, "id": "022bbb36", "metadata": {}, "outputs": [], "source": [ "%pip install requests pandas" ] }, { "cell_type": "code", "execution_count": null, "id": "35165b97", "metadata": {}, "outputs": [], "source": "import os\nimport requests\nimport pandas as pd\n\nBASE_URL = \"https://leaf-portal.containers.wur.nl\"\n\n# Load API token from environment variable\n# Set it in your terminal: export API_TOKEN=your_token_here\nTOKEN = os.getenv(\"API_TOKEN\", \"\")\n\nif not TOKEN:\n print(\"Warning: API_TOKEN is not set. Requests will return 401.\")\n\nHEADERS = {\"Authorization\": f\"Bearer {TOKEN}\"}" }, { "cell_type": "markdown", "id": "tu8qzr2m4mh", "metadata": {}, "source": [ "## GET /api/managements\n", "\n", "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.\n", "\n", "Use the returned `id` values to query `GET /api/data` by management UUID (if supported), or use the `organisation` and `department` names as parameters." ] }, { "cell_type": "code", "execution_count": 74, "id": "ca1d7416", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
idorganisationdepartmententitytime_starttime_end
0c6200b9a-20f3-46ed-9c69-fd55b48f0701RWTHAVTNoneNoneNone
137881edb-6925-48c8-b2eb-4e1c980201efWURSSBNoneNoneNone
2dc940e69-0a68-4db6-9ed3-d54fca8828e3UNLOCKFDPNoneNoneNone
302c31ce3-cb65-44a4-b80b-3627d0697fa3UNLOCKMBPNoneNoneNone
\n", "
" ], "text/plain": [ " id organisation department entity \\\n", "0 c6200b9a-20f3-46ed-9c69-fd55b48f0701 RWTH AVT None \n", "1 37881edb-6925-48c8-b2eb-4e1c980201ef WUR SSB None \n", "2 dc940e69-0a68-4db6-9ed3-d54fca8828e3 UNLOCK FDP None \n", "3 02c31ce3-cb65-44a4-b80b-3627d0697fa3 UNLOCK MBP None \n", "\n", " time_start time_end \n", "0 None None \n", "1 None None \n", "2 None None \n", "3 None None " ] }, "execution_count": 74, "metadata": {}, "output_type": "execute_result" } ], "source": [ "response = requests.get(f\"{BASE_URL}/api/managements\", headers=HEADERS)\n", "\n", "if response.status_code != 200:\n", " raise RuntimeError(f\"Error {response.status_code}: {response.text}\")\n", "\n", "df = pd.DataFrame(response.json())\n", "df.head()" ] }, { "cell_type": "markdown", "id": "cgi8g93so57", "metadata": {}, "source": [ "## GET /api/data/recent\n", "\n", "Returns the most recent sensor readings across all departments accessible to your token.\n", "\n", "| Parameter | Type | Default | Description |\n", "|-----------|------|---------|-------------|\n", "| `limit` | int | 20 | Number of rows to return (max 1000) |" ] }, { "cell_type": "code", "execution_count": 75, "id": "ba6ff976", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
timeentitymetricvaluetagsdepartment_idorganisation_id
02026-03-18 08:50:30+00:00ssb.bioind4cpu.usage_idle9.831245e+01{'cpu': 'cpu-total', 'topic': 'ssb/server/ssb....74c70fdf-12d7-4982-bb2c-2e0d46fa31f0c9ebd03f-c9c5-412a-99c9-5b05b3fe24aa
12026-03-18 08:50:30+00:00ssb.bioind4disk.free2.922352e+10{'mode': 'rw', 'path': '/docker', 'label': 'Vs...74c70fdf-12d7-4982-bb2c-2e0d46fa31f0c9ebd03f-c9c5-412a-99c9-5b05b3fe24aa
22026-03-18 08:50:30+00:00ssb.bioind4disk.used1.702638e+11{'mode': 'rw', 'path': '/docker', 'label': 'Vs...74c70fdf-12d7-4982-bb2c-2e0d46fa31f0c9ebd03f-c9c5-412a-99c9-5b05b3fe24aa
32026-03-18 08:50:30+00:00ssb.bioind4disk.used_percent8.535069e+01{'mode': 'rw', 'path': '/docker', 'label': 'Vs...74c70fdf-12d7-4982-bb2c-2e0d46fa31f0c9ebd03f-c9c5-412a-99c9-5b05b3fe24aa
42026-03-18 08:50:30+00:00ssb.bioind4mem.used1.598564e+10{'topic': 'ssb/server/ssb.bioind4/mem'}74c70fdf-12d7-4982-bb2c-2e0d46fa31f0c9ebd03f-c9c5-412a-99c9-5b05b3fe24aa
\n", "
" ], "text/plain": [ " time entity metric value \\\n", "0 2026-03-18 08:50:30+00:00 ssb.bioind4 cpu.usage_idle 9.831245e+01 \n", "1 2026-03-18 08:50:30+00:00 ssb.bioind4 disk.free 2.922352e+10 \n", "2 2026-03-18 08:50:30+00:00 ssb.bioind4 disk.used 1.702638e+11 \n", "3 2026-03-18 08:50:30+00:00 ssb.bioind4 disk.used_percent 8.535069e+01 \n", "4 2026-03-18 08:50:30+00:00 ssb.bioind4 mem.used 1.598564e+10 \n", "\n", " tags \\\n", "0 {'cpu': 'cpu-total', 'topic': 'ssb/server/ssb.... \n", "1 {'mode': 'rw', 'path': '/docker', 'label': 'Vs... \n", "2 {'mode': 'rw', 'path': '/docker', 'label': 'Vs... \n", "3 {'mode': 'rw', 'path': '/docker', 'label': 'Vs... \n", "4 {'topic': 'ssb/server/ssb.bioind4/mem'} \n", "\n", " department_id organisation_id \n", "0 74c70fdf-12d7-4982-bb2c-2e0d46fa31f0 c9ebd03f-c9c5-412a-99c9-5b05b3fe24aa \n", "1 74c70fdf-12d7-4982-bb2c-2e0d46fa31f0 c9ebd03f-c9c5-412a-99c9-5b05b3fe24aa \n", "2 74c70fdf-12d7-4982-bb2c-2e0d46fa31f0 c9ebd03f-c9c5-412a-99c9-5b05b3fe24aa \n", "3 74c70fdf-12d7-4982-bb2c-2e0d46fa31f0 c9ebd03f-c9c5-412a-99c9-5b05b3fe24aa \n", "4 74c70fdf-12d7-4982-bb2c-2e0d46fa31f0 c9ebd03f-c9c5-412a-99c9-5b05b3fe24aa " ] }, "execution_count": 75, "metadata": {}, "output_type": "execute_result" } ], "source": [ "response = requests.get(f\"{BASE_URL}/api/data/recent\", headers=HEADERS, params={\"limit\": 20})\n", "\n", "if response.status_code != 200:\n", " raise RuntimeError(f\"Error {response.status_code}: {response.text}\")\n", "\n", "df = pd.DataFrame(response.json())\n", "df[\"time\"] = pd.to_datetime(df[\"time\"])\n", "df.head()" ] }, { "cell_type": "markdown", "id": "imskvkl6vb", "metadata": {}, "source": [ "## GET /api/data\n", "\n", "Returns sensor data for a specific organisation and department, with optional filters.\n", "\n", "| Parameter | Type | Required | Description |\n", "|-----------|------|----------|-------------|\n", "| `organisation` | str | yes | Organisation name (e.g. `WUR`) |\n", "| `department` | str | yes | Department name (e.g. `SSB`) |\n", "| `entity` | str | no | Filter to a single entity |\n", "| `metric` | str | no | Filter to a single metric |\n", "| `from` | str | no | Start time, ISO 8601 (inclusive) |\n", "| `to` | str | no | End time, ISO 8601 (exclusive) |\n", "| `limit` | int | no | Max rows to return (default 1000, max 10000) |" ] }, { "cell_type": "code", "execution_count": 76, "id": "7e9501a2", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
timeentitymetricvaluetagsdepartment_idorganisation_id
02026-03-17 04:59:50+00:00ssb.bioind4cpu.usage_idle96.811435{'cpu': 'cpu-total', 'topic': 'ssb/server/ssb....74c70fdf-12d7-4982-bb2c-2e0d46fa31f0c9ebd03f-c9c5-412a-99c9-5b05b3fe24aa
12026-03-17 04:59:40+00:00ssb.bioind4cpu.usage_idle97.173711{'cpu': 'cpu-total', 'topic': 'ssb/server/ssb....74c70fdf-12d7-4982-bb2c-2e0d46fa31f0c9ebd03f-c9c5-412a-99c9-5b05b3fe24aa
22026-03-17 04:59:30+00:00ssb.bioind4cpu.usage_idle96.985288{'cpu': 'cpu-total', 'topic': 'ssb/server/ssb....74c70fdf-12d7-4982-bb2c-2e0d46fa31f0c9ebd03f-c9c5-412a-99c9-5b05b3fe24aa
32026-03-17 04:59:20+00:00ssb.bioind4cpu.usage_idle96.939482{'cpu': 'cpu-total', 'topic': 'ssb/server/ssb....74c70fdf-12d7-4982-bb2c-2e0d46fa31f0c9ebd03f-c9c5-412a-99c9-5b05b3fe24aa
42026-03-17 04:59:10+00:00ssb.bioind4cpu.usage_idle97.074690{'cpu': 'cpu-total', 'topic': 'ssb/server/ssb....74c70fdf-12d7-4982-bb2c-2e0d46fa31f0c9ebd03f-c9c5-412a-99c9-5b05b3fe24aa
\n", "
" ], "text/plain": [ " time entity metric value \\\n", "0 2026-03-17 04:59:50+00:00 ssb.bioind4 cpu.usage_idle 96.811435 \n", "1 2026-03-17 04:59:40+00:00 ssb.bioind4 cpu.usage_idle 97.173711 \n", "2 2026-03-17 04:59:30+00:00 ssb.bioind4 cpu.usage_idle 96.985288 \n", "3 2026-03-17 04:59:20+00:00 ssb.bioind4 cpu.usage_idle 96.939482 \n", "4 2026-03-17 04:59:10+00:00 ssb.bioind4 cpu.usage_idle 97.074690 \n", "\n", " tags \\\n", "0 {'cpu': 'cpu-total', 'topic': 'ssb/server/ssb.... \n", "1 {'cpu': 'cpu-total', 'topic': 'ssb/server/ssb.... \n", "2 {'cpu': 'cpu-total', 'topic': 'ssb/server/ssb.... \n", "3 {'cpu': 'cpu-total', 'topic': 'ssb/server/ssb.... \n", "4 {'cpu': 'cpu-total', 'topic': 'ssb/server/ssb.... \n", "\n", " department_id organisation_id \n", "0 74c70fdf-12d7-4982-bb2c-2e0d46fa31f0 c9ebd03f-c9c5-412a-99c9-5b05b3fe24aa \n", "1 74c70fdf-12d7-4982-bb2c-2e0d46fa31f0 c9ebd03f-c9c5-412a-99c9-5b05b3fe24aa \n", "2 74c70fdf-12d7-4982-bb2c-2e0d46fa31f0 c9ebd03f-c9c5-412a-99c9-5b05b3fe24aa \n", "3 74c70fdf-12d7-4982-bb2c-2e0d46fa31f0 c9ebd03f-c9c5-412a-99c9-5b05b3fe24aa \n", "4 74c70fdf-12d7-4982-bb2c-2e0d46fa31f0 c9ebd03f-c9c5-412a-99c9-5b05b3fe24aa " ] }, "execution_count": 76, "metadata": {}, "output_type": "execute_result" } ], "source": [ "response = requests.get(\n", " f\"{BASE_URL}/api/data\",\n", " headers=HEADERS,\n", " params={\n", " \"organisation\": \"WUR\",\n", " \"department\": \"SSB\",\n", " \"entity\": \"ssb.bioind4\",\n", " \"metric\": \"cpu.usage_idle\",\n", " \"from\": \"2026-03-17T00:00:00Z\",\n", " \"to\": \"2026-03-17T05:00:00Z\",\n", " \"limit\": 1000,\n", " },\n", ")\n", "\n", "if response.status_code != 200:\n", " raise RuntimeError(f\"Error {response.status_code}: {response.text}\")\n", "\n", "df = pd.DataFrame(response.json())\n", "df[\"time\"] = pd.to_datetime(df[\"time\"])\n", "df.head()" ] } ], "metadata": { "kernelspec": { "display_name": ".venv", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.12" } }, "nbformat": 4, "nbformat_minor": 5 }