Sutram REST API v1
Version: 0.89.0 Datum: 2026-02-19 Status: In Produktion
Übersicht
Die Sutram REST API stellt JSON-Endpunkte für den externen Zugriff auf Projektinhalte (Ordner, Dateien, Links) bereit. Sie verwendet die gleiche Dual-Key-Authentifizierung wie der MCP-Server (x-project-key + x-user-key), sodass jedes Projekt mit aktiviertem Fernzugriff automatisch über die REST API erreichbar ist.
Anwendungsfälle
- APM-Plattform-Integration — Sutram-Inhalte (Events, Nachrichten, Podcasts, Webinare) als zentrales Repository (SSOT) nutzen
- Benutzerdefinierte Dashboards — Inhaltslistenseiten außerhalb von Sutram erstellen
- Mobile Apps — Dateien und Links mit vorsignierten Download-URLs abrufen
- Automatisierung — Programmatische Inhaltsermittlung und -abruf über Skripte oder CI/CD
Basis-URL
https://sutram.io/api/v1
Entwicklung:
http://localhost:4001/api/v1
Funktionsweise
External Client (app, script, dashboard)
|
| HTTPS + JSON
v
Sutram REST API
/api/v1/*
|
| Dual Key Authentication
v
Project Content (folders, files, links, tags)
Authentifizierung
Jede Anfrage muss zwei Header enthalten:
| Header | Wert | Beschreibung |
|---|---|---|
x-project-key |
sk_proj_... |
Identifiziert das Projekt |
x-user-key |
sk_user_... |
Identifiziert den Benutzer |
Beide Schlüssel werden über die Sutram-Weboberfläche erstellt. Siehe die MCP-Server-Benutzeranleitung für eine Schritt-für-Schritt-Anleitung.
Beispiel
curl -H "x-project-key: sk_proj_ej8NWMisd2rJgMwAJ22T..." \
-H "x-user-key: sk_user_zQD0BjH56nQhOgX3uxni..." \
https://sutram.io/api/v1/project
Fehlerantworten
Wenn die Authentifizierung fehlschlägt, gibt die API HTTP 401 zurück:
{ "error": "Missing x-project-key header" }
{ "error": "Invalid project key" }
{ "error": "Invalid user key" }
{ "error": "Viewers cannot access this API" }
{ "error": "Not a member of this project" }
Berechtigungen
| Rolle | Zugriff |
|---|---|
| Owner | Voller Lesezugriff |
| Admin | Voller Lesezugriff |
| Member | Voller Lesezugriff |
| Viewer | Kein Zugriff (401) |
Die REST API v1 ist schreibgeschützt. Schreiboperationen (Hochladen, Löschen, Umbenennen, Verschieben) sind über den MCP-Server verfügbar.
Endpunkte
GET /api/v1/project
Gibt Informationen über das authentifizierte Projekt zurück.
Beispielanfrage:
curl -H "x-project-key: $PROJECT_KEY" \
-H "x-user-key: $USER_KEY" \
https://sutram.io/api/v1/project
Antwort:
{
"project": {
"id": "a1b2c3d4-...",
"name": "Construction Site Alpha",
"description": "Main project documentation",
"your_role": "owner",
"created_at": "2026-01-15T10:00:00Z",
"updated_at": "2026-02-19T14:30:00Z"
}
}
GET /api/v1/folders
Listet die Ordner auf der Stammebene des Projekts auf.
Beispielanfrage:
curl -H "x-project-key: $PROJECT_KEY" \
-H "x-user-key: $USER_KEY" \
https://sutram.io/api/v1/folders
Antwort:
{
"folders": [
{
"id": "f1a2b3c4-...",
"name": "Reports",
"parent_id": null,
"tags": {"category": "monthly"},
"created_at": "2026-01-20T10:00:00Z"
},
{
"id": "f5e6d7c8-...",
"name": "Photos",
"parent_id": null,
"tags": {},
"created_at": "2026-01-22T08:00:00Z"
}
],
"meta": {
"total_count": 2
}
}
GET /api/v1/folders/:id
Gibt die Details eines Ordners, seine Unterordner und seine Inhaltselemente zurück.
Pfadparameter:
| Parameter | Typ | Beschreibung |
|---|---|---|
id |
UUID | Ordner-ID |
Beispielanfrage:
curl -H "x-project-key: $PROJECT_KEY" \
-H "x-user-key: $USER_KEY" \
https://sutram.io/api/v1/folders/f1a2b3c4-...
Antwort:
{
"folder": {
"id": "f1a2b3c4-...",
"name": "Reports",
"parent_id": null,
"path": "/Reports",
"tags": {"category": "monthly"},
"created_at": "2026-01-20T10:00:00Z"
},
"subfolders": [
{
"id": "a1b2c3d4-...",
"name": "2024",
"parent_id": "f1a2b3c4-...",
"tags": {"year": "2024"},
"created_at": "2026-01-25T12:00:00Z"
}
],
"items": [
{
"id": "d5e6f7a8-...",
"type": "file",
"name": "summary",
"description": null,
"tags": {"status": "final"},
"folder_id": "f1a2b3c4-...",
"created_at": "2026-02-01T10:00:00Z",
"file": {
"filename": "summary.pdf",
"content_type": "application/pdf",
"file_size": 245000
}
}
],
"meta": {
"subfolder_count": 1,
"item_count": 1
}
}
Fehlerantworten:
| Status | Body | Wann |
|---|---|---|
| 404 | {"error": "Folder not found"} |
Ordner existiert nicht oder gehört zu einem anderen Projekt |
GET /api/v1/content
Listet Inhaltselemente mit Filterung, Tag-Suche, Textsuche und Paginierung auf.
Abfrageparameter:
| Parameter | Typ | Standard | Beschreibung |
|---|---|---|---|
folder_id |
UUID | — | Nach Ordner filtern. Ohne diesen werden nur Elemente auf der Stammebene zurückgegeben. |
all_folders |
boolean | false |
Wenn true, wird über alle Ordner gesucht (nicht nur Stammebene). Erforderlich für Tag-/Suchabfragen über das gesamte Projekt. |
type |
string | — | Nach Inhaltstyp filtern: "file", "web_link", "video_link", "audio_link" |
tag |
string | — | Einzelner Tag-Schlüssel zum Filtern (z.B. tag=category) |
tag_value |
string | — | Zu vergleichender Tag-Wert (zusammen mit tag). Groß-/Kleinschreibung-unabhängige Teilstringsuche. |
tags |
JSON | — | Mehrere UND-Bedingungen als JSON-Array (z.B. tags=[{"key":"topic","value":"neuro"}]) |
search |
string | — | Nach Elementname suchen (Groß-/Kleinschreibung-unabhängige Teilstringsuche) |
page |
integer | 1 |
Seitennummer |
per_page |
integer | 50 |
Elemente pro Seite (max: 100) |
Tag-Suchverhalten:
- Schlüsselabgleich: Groß-/Kleinschreibung-unabhängiger exakter Abgleich (
"Category"stimmt mit"category"überein) - Wertabgleich: Groß-/Kleinschreibung-unabhängige Teilstringsuche (
"neuro"stimmt mit"Neurologia Avançada"überein) - Mehrere Bedingungen (
tags-Parameter): Alle Bedingungen müssen zutreffen (UND-Logik) - Ohne Wert: Wenn
tag_valueweggelassen wird, wird jedes Element mit dem Tag-Schlüssel gefunden, unabhängig vom Wert
Beispiel — Stammelemente auflisten
curl -H "x-project-key: $PROJECT_KEY" \
-H "x-user-key: $USER_KEY" \
"https://sutram.io/api/v1/content"
Beispiel — Elemente in einem Ordner auflisten
curl -H "x-project-key: $PROJECT_KEY" \
-H "x-user-key: $USER_KEY" \
"https://sutram.io/api/v1/content?folder_id=f1a2b3c4-..."
Beispiel — nach Typ filtern
curl -H "x-project-key: $PROJECT_KEY" \
-H "x-user-key: $USER_KEY" \
"https://sutram.io/api/v1/content?type=video_link&all_folders=true"
Beispiel — einzelne Tag-Suche
curl -H "x-project-key: $PROJECT_KEY" \
-H "x-user-key: $USER_KEY" \
"https://sutram.io/api/v1/content?tag=category&tag_value=cientifico&all_folders=true"
Beispiel — Multi-Tag-UND-Suche
curl -H "x-project-key: $PROJECT_KEY" \
-H "x-user-key: $USER_KEY" \
"https://sutram.io/api/v1/content?tags=%5B%7B%22key%22%3A%22patient%22%2C%22value%22%3A%22jo%C3%A3o%22%7D%2C%7B%22key%22%3A%22year%22%2C%22value%22%3A%222024%22%7D%5D&all_folders=true"
Der tags-Parameter oben ist die URL-kodierte Version von:
[{"key": "patient", "value": "joão"}, {"key": "year", "value": "2024"}]
Beispiel — nach Name suchen
curl -H "x-project-key: $PROJECT_KEY" \
-H "x-user-key: $USER_KEY" \
"https://sutram.io/api/v1/content?search=report&all_folders=true"
Beispiel — paginierte Auflistung
curl -H "x-project-key: $PROJECT_KEY" \
-H "x-user-key: $USER_KEY" \
"https://sutram.io/api/v1/content?page=2&per_page=20"
Antwort:
{
"items": [
{
"id": "d5e6f7a8-...",
"type": "file",
"name": "site-plan",
"description": null,
"tags": {"category": "planta", "year": "2024"},
"folder_id": "f1a2b3c4-...",
"created_at": "2026-02-19T10:00:00Z",
"file": {
"filename": "site-plan.pdf",
"content_type": "application/pdf",
"file_size": 2450000
}
},
{
"id": "e5f6a7b8-...",
"type": "video_link",
"name": "Site walkthrough",
"description": null,
"tags": {"topic": "neurologia"},
"folder_id": null,
"created_at": "2026-02-18T14:00:00Z",
"video_link": {
"url": "https://youtube.com/watch?v=abc",
"platform": "youtube",
"video_id": "abc",
"thumbnail_url": "https://img.youtube.com/vi/abc/hqdefault.jpg"
}
},
{
"id": "a1b2c3d4-...",
"type": "web_link",
"name": "Documentation",
"description": "Project reference docs",
"tags": {},
"folder_id": null,
"created_at": "2026-02-17T09:00:00Z",
"web_link": {
"url": "https://docs.example.com",
"fetched_title": "Documentation Hub",
"favicon_url": "https://docs.example.com/favicon.ico"
}
},
{
"id": "c9d0e1f2-...",
"type": "audio_link",
"name": "Weekly recap",
"description": null,
"tags": {"series": "weekly"},
"folder_id": null,
"created_at": "2026-02-16T16:00:00Z",
"audio_link": {
"url": "https://open.spotify.com/episode/xyz",
"platform": "spotify",
"artist_or_author": "Team Alpha",
"thumbnail_url": "https://i.scdn.co/image/abc"
}
}
],
"meta": {
"page": 1,
"per_page": 50,
"total_count": 4,
"total_pages": 1
}
}
Inhaltliche Felder nach Typ:
Das Inhaltsobjekt wird unter einem Schlüssel serialisiert, der dem Elementtyp entspricht:
| Typ | Schlüssel | Felder |
|---|---|---|
file |
file |
filename, content_type, file_size |
web_link |
web_link |
url, fetched_title, favicon_url |
video_link |
video_link |
url, platform, video_id, thumbnail_url |
audio_link |
audio_link |
url, platform, artist_or_author, thumbnail_url |
GET /api/v1/content/:id
Gibt vollständige Details eines einzelnen Inhaltselements zurück, einschließlich vorsignierter Download-URLs für Dateien.
Pfadparameter:
| Parameter | Typ | Beschreibung |
|---|---|---|
id |
UUID | Inhaltselement-ID |
Beispielanfrage:
curl -H "x-project-key: $PROJECT_KEY" \
-H "x-user-key: $USER_KEY" \
https://sutram.io/api/v1/content/d5e6f7a8-...
Antwort (Datei):
{
"item": {
"id": "d5e6f7a8-...",
"type": "file",
"name": "site-plan",
"description": null,
"tags": {"category": "planta", "year": "2024"},
"folder_id": "f1a2b3c4-...",
"folder_path": "/Reports/2024",
"created_at": "2026-02-19T10:00:00Z",
"file": {
"filename": "site-plan.pdf",
"content_type": "application/pdf",
"file_size": 2450000,
"version": 1,
"download_url": "https://storage.example.com/projects/.../site-plan.pdf?X-Amz-..."
}
}
}
Antwort (Video-Link):
{
"item": {
"id": "e5f6a7b8-...",
"type": "video_link",
"name": "Site walkthrough",
"description": null,
"tags": {"topic": "neurologia"},
"folder_id": null,
"folder_path": "/",
"created_at": "2026-02-18T14:00:00Z",
"video_link": {
"url": "https://youtube.com/watch?v=abc",
"platform": "youtube",
"video_id": "abc",
"thumbnail_url": "https://img.youtube.com/vi/abc/hqdefault.jpg",
"duration_seconds": null,
"fetched_title": "Construction Site Alpha - Full Tour"
}
}
}
Antwort (Audio-Link):
{
"item": {
"id": "c9d0e1f2-...",
"type": "audio_link",
"name": "Weekly recap",
"description": null,
"tags": {"series": "weekly"},
"folder_id": null,
"folder_path": "/",
"created_at": "2026-02-16T16:00:00Z",
"audio_link": {
"url": "https://open.spotify.com/episode/xyz",
"platform": "spotify",
"artist_or_author": "Team Alpha",
"thumbnail_url": "https://i.scdn.co/image/abc",
"duration_seconds": 1800,
"fetched_title": "Weekly Standup Recap - Feb 16"
}
}
}
Antwort (Web-Link):
{
"item": {
"id": "a1b2c3d4-...",
"type": "web_link",
"name": "Documentation",
"description": "Project reference docs",
"tags": {},
"folder_id": null,
"folder_path": "/",
"created_at": "2026-02-17T09:00:00Z",
"web_link": {
"url": "https://docs.example.com",
"fetched_title": "Documentation Hub",
"fetched_description": "Complete project documentation",
"favicon_url": "https://docs.example.com/favicon.ico"
}
}
}
Unterschiede zwischen Detail- und Listenantwort:
Der Endpunkt /content/:id gibt im Vergleich zum Listenendpunkt zusätzliche Felder zurück:
| Feld | Liste (/content) |
Detail (/content/:id) |
|---|---|---|
folder_path |
Nein | Ja |
file.version |
Nein | Ja |
file.download_url |
Nein | Ja (vorsigniert, temporär) |
web_link.fetched_description |
Nein | Ja |
video_link.duration_seconds |
Nein | Ja |
video_link.fetched_title |
Nein | Ja |
audio_link.duration_seconds |
Nein | Ja |
audio_link.fetched_title |
Nein | Ja |
Fehlerantworten:
| Status | Body | Wann |
|---|---|---|
| 404 | {"error": "Content item not found"} |
Element existiert nicht oder gehört zu einem anderen Projekt |
Tags für Inhaltselemente
Tags sind frei definierbare Schlüssel-Wert-Stringpaare, die an Inhaltselemente und Ordner angehängt werden. Sie ermöglichen strukturierte Metadaten und leistungsfähige Suchfunktionen.
Tag-Einschränkungen
| Einschränkung | Limit |
|---|---|
| Maximale Tags pro Element | 50 |
| Maximale Schlüssellänge | 100 Zeichen |
| Maximale Wertlänge | 500 Zeichen |
| Schlüssel- und Werttypen | Nur Strings |
Tags verwalten
Tags auf Inhaltselementen werden über die MCP-Server-Tools verwaltet:
| MCP-Tool | Beschreibung |
|---|---|
sutram_set_item_tags |
Alle Tags eines Inhaltselements setzen/ersetzen |
sutram_search_items |
Elemente nach Tag suchen (einzelne oder Multi-Bedingung UND) |
sutram_get_item_tag_keys |
Alle unterschiedlichen Tag-Schlüssel über Elemente auflisten |
Siehe die MCP-Server-Benutzeranleitung für Details zu diesen Tools.
Tags über die REST API abfragen
Verwenden Sie die Abfrageparameter tag, tag_value und tags bei GET /api/v1/content:
# Alle Elemente mit dem Tag "category" finden
curl ... "https://sutram.io/api/v1/content?tag=category&all_folders=true"
# Elemente finden, bei denen category "report" enthält
curl ... "https://sutram.io/api/v1/content?tag=category&tag_value=report&all_folders=true"
# Elemente finden, die mehrere Bedingungen erfüllen (UND)
curl ... "https://sutram.io/api/v1/content?tags=[{\"key\":\"patient\",\"value\":\"joão\"},{\"key\":\"year\",\"value\":\"2024\"}]&all_folders=true"
Vergleich: REST API vs. MCP-Server
| Fähigkeit | REST API (/api/v1) |
MCP-Server (/mcp) |
|---|---|---|
| Protokoll | HTTP/JSON | JSON-RPC 2.0 (MCP) |
| Inhalte lesen | Ja | Ja |
| Nach Tags suchen | Ja | Ja |
| Download-URLs | Ja (vorsigniert) | Ja (vorsigniert) |
| Dateien hochladen | Nein | Ja |
| Links erstellen | Nein | Ja |
| Ordner erstellen | Nein | Ja |
| Tags setzen | Nein | Ja |
| Verschieben/Umbenennen/Löschen | Nein | Ja |
| Authentifizierung | Gleicher Dual-Key | Gleicher Dual-Key |
| Am besten geeignet für | Externe Apps, Dashboards, Skripte | KI-Assistenten, Automatisierung |
Ratenlimits
Derzeit gibt es keine Ratenlimits für die REST API. Dies kann sich in zukünftigen Versionen ändern. Bitte gehen Sie vernünftig mit der Anfragehäufigkeit um.
Versionierung
Die API wird über den URL-Pfad versioniert (/api/v1). Breaking Changes werden in neuen Versionen eingeführt (/api/v2). Nicht-breaking Ergänzungen (neue Felder, neue optionale Parameter) können der aktuellen Version ohne Vorankündigung hinzugefügt werden.
Beispiele
Alle Video-Links in einem Projekt abrufen
curl -H "x-project-key: $PROJECT_KEY" \
-H "x-user-key: $USER_KEY" \
"https://sutram.io/api/v1/content?type=video_link&all_folders=true"
Inhalte abrufen, die für ein bestimmtes Thema getaggt sind
curl -H "x-project-key: $PROJECT_KEY" \
-H "x-user-key: $USER_KEY" \
"https://sutram.io/api/v1/content?tag=topic&tag_value=neurologia&all_folders=true"
Eine Ordnerhierarchie durchsuchen
# 1. Stammordner auflisten
curl ... "https://sutram.io/api/v1/folders"
# 2. Einen bestimmten Ordner öffnen
curl ... "https://sutram.io/api/v1/folders/f1a2b3c4-..."
# 3. Download-URL für eine Datei abrufen
curl ... "https://sutram.io/api/v1/content/d5e6f7a8-..."
Durch alle Inhalte paginieren
# Seite 1
curl ... "https://sutram.io/api/v1/content?page=1&per_page=20&all_folders=true"
# Seite 2
curl ... "https://sutram.io/api/v1/content?page=2&per_page=20&all_folders=true"
# Fortsetzen bis page >= total_pages aus meta
Integration mit JavaScript (fetch)
const PROJECT_KEY = "sk_proj_...";
const USER_KEY = "sk_user_...";
const BASE_URL = "https://sutram.io/api/v1";
async function fetchContent(params = {}) {
const query = new URLSearchParams(params).toString();
const url = `${BASE_URL}/content${query ? "?" + query : ""}`;
const response = await fetch(url, {
headers: {
"x-project-key": PROJECT_KEY,
"x-user-key": USER_KEY,
},
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.error);
}
return response.json();
}
// List all video links
const videos = await fetchContent({ type: "video_link", all_folders: "true" });
console.log(`Found ${videos.meta.total_count} videos`);
// Search by tag
const tagged = await fetchContent({
tag: "topic",
tag_value: "neurologia",
all_folders: "true",
});
Integration mit Python (requests)
import requests
PROJECT_KEY = "sk_proj_..."
USER_KEY = "sk_user_..."
BASE_URL = "https://sutram.io/api/v1"
headers = {
"x-project-key": PROJECT_KEY,
"x-user-key": USER_KEY,
}
# List root folders
folders = requests.get(f"{BASE_URL}/folders", headers=headers).json()
# Get content in a folder
folder_id = folders["folders"][0]["id"]
content = requests.get(
f"{BASE_URL}/content",
headers=headers,
params={"folder_id": folder_id},
).json()
# Search by multiple tags
import json
tags = json.dumps([
{"key": "patient", "value": "joão"},
{"key": "year", "value": "2024"},
])
results = requests.get(
f"{BASE_URL}/content",
headers=headers,
params={"tags": tags, "all_folders": "true"},
).json()
print(f"Found {results['meta']['total_count']} items")
Fehlerbehebung
401 Unauthorized
- Überprüfen Sie, ob beide Header
x-project-keyundx-user-keyvorhanden sind - Prüfen Sie, ob die Schlüssel nicht widerrufen wurden
- Stellen Sie sicher, dass Sie ein aktives Mitglied (kein Viewer) des Projekts sind
404 Not Found
- Überprüfen Sie, ob die Ordner-/Inhalts-ID zum authentifizierten Projekt gehört
- Prüfen Sie, ob das Element nicht gelöscht wurde
Leere Ergebnisse bei der Tag-Suche
- Fügen Sie
all_folders=truehinzu, um über alle Ordner zu suchen (ohne diesen werden nur Stammelemente zurückgegeben) - Die Tag-Suche ist Groß-/Kleinschreibung-unabhängig — überprüfen Sie auf Tippfehler in Schlüsselnamen
- Verwenden Sie
GET /api/v1/content?tag=YOUR_KEY&all_folders=trueohne Wert zuerst, um zu überprüfen, ob der Tag-Schlüssel existiert
tags-Parameter gibt einen Fehler zurück
- Der
tags-Parameter muss ein gültiges JSON-Array sein:[{"key": "...", "value": "..."}] - URL-kodieren Sie den JSON-String, wenn Sie ihn als Abfrageparameter übergeben
- Jede Bedingung muss ein
key-Feld haben;valueist optional