Sutram REST API v1
Versione: 0.89.0 Data: 2026-02-19 Stato: In produzione
Panoramica
La REST API di Sutram fornisce endpoint JSON per il consumo esterno dei contenuti del progetto (cartelle, file, link). Utilizza la stessa autenticazione a doppia chiave del Server MCP (x-project-key + x-user-key), quindi qualsiasi progetto con Accesso Remoto abilitato è automaticamente accessibile tramite la REST API.
Casi d'uso
- Integrazione con piattaforme APM — Consumare contenuti Sutram (eventi, notizie, podcast, webinar) come repository centrale (SSOT)
- Dashboard personalizzate — Costruire pagine di elenco contenuti al di fuori di Sutram
- App mobili — Recuperare file e link con URL di download pre-firmati
- Automazione — Scoperta e recupero programmatico dei contenuti tramite script o CI/CD
URL Base
https://sutram.io/api/v1
Sviluppo:
http://localhost:4001/api/v1
Come funziona
External Client (app, script, dashboard)
|
| HTTPS + JSON
v
Sutram REST API
/api/v1/*
|
| Dual Key Authentication
v
Project Content (folders, files, links, tags)
Autenticazione
Ogni richiesta deve includere due intestazioni:
| Intestazione | Valore | Descrizione |
|---|---|---|
x-project-key |
sk_proj_... |
Identifica il progetto |
x-user-key |
sk_user_... |
Identifica l'utente |
Entrambe le chiavi vengono create attraverso l'interfaccia web di Sutram. Consultare la Guida Utente del Server MCP per le istruzioni passo-passo.
Esempio
curl -H "x-project-key: sk_proj_ej8NWMisd2rJgMwAJ22T..." \
-H "x-user-key: sk_user_zQD0BjH56nQhOgX3uxni..." \
https://sutram.io/api/v1/project
Risposte di errore
Quando l'autenticazione fallisce, l'API restituisce HTTP 401:
{ "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" }
Permessi
| Ruolo | Accesso |
|---|---|
| Owner | Accesso completo in lettura |
| Admin | Accesso completo in lettura |
| Member | Accesso completo in lettura |
| Viewer | Nessun accesso (401) |
La REST API v1 è in sola lettura. Le operazioni di scrittura (caricamento, eliminazione, rinomina, spostamento) sono disponibili attraverso il Server MCP.
Endpoint
GET /api/v1/project
Restituisce informazioni sul progetto autenticato.
Esempio di richiesta:
curl -H "x-project-key: $PROJECT_KEY" \
-H "x-user-key: $USER_KEY" \
https://sutram.io/api/v1/project
Risposta:
{
"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
Elenca le cartelle di primo livello del progetto.
Esempio di richiesta:
curl -H "x-project-key: $PROJECT_KEY" \
-H "x-user-key: $USER_KEY" \
https://sutram.io/api/v1/folders
Risposta:
{
"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
Restituisce i dettagli di una cartella, le sue sottocartelle e i suoi elementi di contenuto.
Parametri del percorso:
| Parametro | Tipo | Descrizione |
|---|---|---|
id |
UUID | ID della cartella |
Esempio di richiesta:
curl -H "x-project-key: $PROJECT_KEY" \
-H "x-user-key: $USER_KEY" \
https://sutram.io/api/v1/folders/f1a2b3c4-...
Risposta:
{
"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
}
}
Risposte di errore:
| Stato | Corpo | Quando |
|---|---|---|
| 404 | {"error": "Folder not found"} |
La cartella non esiste o appartiene a un altro progetto |
GET /api/v1/content
Elenca gli elementi di contenuto con filtri, ricerca per tag, ricerca testuale e paginazione.
Parametri di query:
| Parametro | Tipo | Predefinito | Descrizione |
|---|---|---|---|
folder_id |
UUID | — | Filtra per cartella. Senza questo, restituisce solo gli elementi di primo livello. |
all_folders |
boolean | false |
Se true, cerca in tutte le cartelle (non solo nella radice). Necessario per query tag/ricerca sull'intero progetto. |
type |
string | — | Filtra per tipo di contenuto: "file", "web_link", "video_link", "audio_link" |
tag |
string | — | Singola chiave tag per il filtro (es. tag=category) |
tag_value |
string | — | Valore del tag da abbinare (usato con tag). Corrispondenza sottostringa case-insensitive. |
tags |
JSON | — | Condizioni AND multiple come array JSON (es. tags=[{"key":"topic","value":"neuro"}]) |
search |
string | — | Ricerca per nome dell'elemento (corrispondenza sottostringa case-insensitive) |
page |
integer | 1 |
Numero di pagina |
per_page |
integer | 50 |
Elementi per pagina (max: 100) |
Comportamento della ricerca per tag:
- Corrispondenza chiave: Corrispondenza esatta case-insensitive (
"Category"corrisponde a"category") - Corrispondenza valore: Corrispondenza sottostringa case-insensitive (
"neuro"corrisponde a"Neurologia Avançada") - Condizioni multiple (parametro
tags): Tutte le condizioni devono corrispondere (logica AND) - Senza valore: Quando
tag_valueè omesso, corrisponde a qualsiasi elemento che abbia la chiave tag indipendentemente dal valore
Esempio — elencare elementi di primo livello
curl -H "x-project-key: $PROJECT_KEY" \
-H "x-user-key: $USER_KEY" \
"https://sutram.io/api/v1/content"
Esempio — elencare elementi in una cartella
curl -H "x-project-key: $PROJECT_KEY" \
-H "x-user-key: $USER_KEY" \
"https://sutram.io/api/v1/content?folder_id=f1a2b3c4-..."
Esempio — filtrare per tipo
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"
Esempio — ricerca per singolo tag
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"
Esempio — ricerca AND multi-tag
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"
Il parametro tags qui sopra è la versione URL-encoded di:
[{"key": "patient", "value": "joão"}, {"key": "year", "value": "2024"}]
Esempio — ricerca per nome
curl -H "x-project-key: $PROJECT_KEY" \
-H "x-user-key: $USER_KEY" \
"https://sutram.io/api/v1/content?search=report&all_folders=true"
Esempio — elenco paginato
curl -H "x-project-key: $PROJECT_KEY" \
-H "x-user-key: $USER_KEY" \
"https://sutram.io/api/v1/content?page=2&per_page=20"
Risposta:
{
"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
}
}
Campi contentable per tipo:
Il contentable è serializzato sotto una chiave corrispondente al tipo dell'elemento:
| Tipo | Chiave | Campi |
|---|---|---|
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
Restituisce i dettagli completi di un singolo elemento di contenuto, inclusi gli URL di download pre-firmati per i file.
Parametri del percorso:
| Parametro | Tipo | Descrizione |
|---|---|---|
id |
UUID | ID dell'elemento di contenuto |
Esempio di richiesta:
curl -H "x-project-key: $PROJECT_KEY" \
-H "x-user-key: $USER_KEY" \
https://sutram.io/api/v1/content/d5e6f7a8-...
Risposta (file):
{
"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-..."
}
}
}
Risposta (link video):
{
"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"
}
}
}
Risposta (link audio):
{
"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"
}
}
}
Risposta (link web):
{
"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"
}
}
}
Differenze tra risposta dettaglio ed elenco:
L'endpoint /content/:id restituisce campi aggiuntivi rispetto all'endpoint di elenco:
| Campo | Elenco (/content) |
Dettaglio (/content/:id) |
|---|---|---|
folder_path |
No | Sì |
file.version |
No | Sì |
file.download_url |
No | Sì (pre-firmato, temporaneo) |
web_link.fetched_description |
No | Sì |
video_link.duration_seconds |
No | Sì |
video_link.fetched_title |
No | Sì |
audio_link.duration_seconds |
No | Sì |
audio_link.fetched_title |
No | Sì |
Risposte di errore:
| Stato | Corpo | Quando |
|---|---|---|
| 404 | {"error": "Content item not found"} |
L'elemento non esiste o appartiene a un altro progetto |
Tag degli Elementi di Contenuto
I tag sono coppie chiave-valore di testo libero associate agli elementi di contenuto e alle cartelle. Consentono metadati strutturati e potenti funzionalità di ricerca.
Vincoli dei tag
| Vincolo | Limite |
|---|---|
| Numero massimo di tag per elemento | 50 |
| Lunghezza massima della chiave | 100 caratteri |
| Lunghezza massima del valore | 500 caratteri |
| Tipi di chiave e valore | Solo stringhe |
Gestione dei tag
I tag sugli elementi di contenuto vengono gestiti attraverso gli strumenti del Server MCP:
| Strumento MCP | Descrizione |
|---|---|
sutram_set_item_tags |
Imposta/sostituisce tutti i tag su un elemento di contenuto |
sutram_search_items |
Cerca elementi per tag (singolo o AND multi-condizione) |
sutram_get_item_tag_keys |
Elenca tutte le chiavi tag distinte tra gli elementi |
Consultare la Guida Utente del Server MCP per i dettagli su questi strumenti.
Interrogazione dei tag tramite REST API
Utilizzare i parametri di query tag, tag_value e tags su GET /api/v1/content:
# Trovare tutti gli elementi con tag "category"
curl ... "https://sutram.io/api/v1/content?tag=category&all_folders=true"
# Trovare elementi dove category contiene "report"
curl ... "https://sutram.io/api/v1/content?tag=category&tag_value=report&all_folders=true"
# Trovare elementi che corrispondono a condizioni multiple (AND)
curl ... "https://sutram.io/api/v1/content?tags=[{\"key\":\"patient\",\"value\":\"joão\"},{\"key\":\"year\",\"value\":\"2024\"}]&all_folders=true"
Confronto: REST API vs. Server MCP
| Funzionalità | REST API (/api/v1) |
Server MCP (/mcp) |
|---|---|---|
| Protocollo | HTTP/JSON | JSON-RPC 2.0 (MCP) |
| Lettura contenuti | Sì | Sì |
| Ricerca per tag | Sì | Sì |
| URL di download | Sì (pre-firmati) | Sì (pre-firmati) |
| Caricamento file | No | Sì |
| Creazione link | No | Sì |
| Creazione cartelle | No | Sì |
| Impostazione tag | No | Sì |
| Spostamento/rinomina/eliminazione | No | Sì |
| Autenticazione | Stessa doppia chiave | Stessa doppia chiave |
| Ideale per | App esterne, dashboard, script | Assistenti IA, automazione |
Limiti di Frequenza
Attualmente non ci sono limiti di frequenza sulla REST API. Questo potrebbe cambiare nelle versioni future. Si prega di essere ragionevoli con la frequenza delle richieste.
Versionamento
L'API è versionata tramite il percorso URL (/api/v1). Le modifiche incompatibili verranno introdotte in nuove versioni (/api/v2). Aggiunte non incompatibili (nuovi campi, nuovi parametri opzionali) possono essere aggiunte alla versione corrente senza preavviso.
Esempi
Recuperare tutti i link video in un progetto
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"
Recuperare contenuti con tag per un argomento specifico
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"
Navigare una gerarchia di cartelle
# 1. Elencare le cartelle di primo livello
curl ... "https://sutram.io/api/v1/folders"
# 2. Aprire una cartella specifica
curl ... "https://sutram.io/api/v1/folders/f1a2b3c4-..."
# 3. Ottenere l'URL di download per un file
curl ... "https://sutram.io/api/v1/content/d5e6f7a8-..."
Paginare attraverso tutti i contenuti
# Pagina 1
curl ... "https://sutram.io/api/v1/content?page=1&per_page=20&all_folders=true"
# Pagina 2
curl ... "https://sutram.io/api/v1/content?page=2&per_page=20&all_folders=true"
# Continuare fino a page >= total_pages dal meta
Integrazione con 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",
});
Integrazione con 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")
Risoluzione dei Problemi
401 Non Autorizzato
- Verificare che entrambe le intestazioni
x-project-keyex-user-keysiano presenti - Controllare che le chiavi non siano state revocate
- Assicurarsi di essere un membro attivo (non viewer) del progetto
404 Non Trovato
- Verificare che l'ID della cartella/contenuto appartenga al progetto autenticato
- Controllare che l'elemento non sia stato eliminato
Risultati vuoti con ricerca per tag
- Aggiungere
all_folders=trueper cercare in tutte le cartelle (senza questo, vengono restituiti solo gli elementi di primo livello) - La ricerca per tag è case-insensitive — controllare eventuali errori di battitura nei nomi delle chiavi
- Utilizzare
GET /api/v1/content?tag=YOUR_KEY&all_folders=truesenza un valore prima per verificare che la chiave tag esista
Il parametro tags restituisce un errore
- Il parametro
tagsdeve essere un array JSON valido:[{"key": "...", "value": "..."}] - Codificare in URL la stringa JSON quando la si passa come parametro di query
- Ogni condizione deve avere un campo
key;valueè opzionale