Torna alla Documentazione

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
file.version No
file.download_url No Sì (pre-firmato, temporaneo)
web_link.fetched_description No
video_link.duration_seconds No
video_link.fetched_title No
audio_link.duration_seconds No
audio_link.fetched_title No

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
Ricerca per tag
URL di download Sì (pre-firmati) Sì (pre-firmati)
Caricamento file No
Creazione link No
Creazione cartelle No
Impostazione tag No
Spostamento/rinomina/eliminazione No
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-key e x-user-key siano 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=true per 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=true senza un valore prima per verificare che la chiave tag esista

Il parametro tags restituisce un errore

  • Il parametro tags deve 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