Sutram REST API v1
Versión: 0.89.0 Fecha: 2026-02-19 Estado: En producción
Descripción general
La API REST de Sutram proporciona endpoints JSON para el consumo externo del contenido de proyectos (carpetas, archivos, enlaces). Utiliza la misma autenticación de doble clave que el Servidor MCP (x-project-key + x-user-key), por lo que cualquier proyecto con Acceso Remoto habilitado es automáticamente accesible a través de la API REST.
Casos de uso
- Integración con plataformas APM — Consumir contenido de Sutram (eventos, noticias, podcasts, webinars) como repositorio central (SSOT)
- Dashboards personalizados — Construir páginas de listado de contenido fuera de Sutram
- Aplicaciones móviles — Obtener archivos y enlaces con URLs de descarga prefirmadas
- Automatización — Descubrimiento y obtención programática de contenido mediante scripts o CI/CD
URL base
https://sutram.io/api/v1
Desarrollo:
http://localhost:4001/api/v1
Cómo funciona
External Client (app, script, dashboard)
|
| HTTPS + JSON
v
Sutram REST API
/api/v1/*
|
| Dual Key Authentication
v
Project Content (folders, files, links, tags)
Autenticación
Cada solicitud debe incluir dos encabezados:
| Encabezado | Valor | Descripción |
|---|---|---|
x-project-key |
sk_proj_... |
Identifica el proyecto |
x-user-key |
sk_user_... |
Identifica al usuario |
Ambas claves se crean a través de la interfaz web de Sutram. Consulta la Guía de Usuario del Servidor MCP para instrucciones paso a paso.
Ejemplo
curl -H "x-project-key: sk_proj_ej8NWMisd2rJgMwAJ22T..." \
-H "x-user-key: sk_user_zQD0BjH56nQhOgX3uxni..." \
https://sutram.io/api/v1/project
Respuestas de error
Cuando la autenticación falla, la API retorna 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" }
Permisos
| Rol | Acceso |
|---|---|
| Propietario | Acceso completo de lectura |
| Administrador | Acceso completo de lectura |
| Miembro | Acceso completo de lectura |
| Visualizador | Sin acceso (401) |
La API REST v1 es de solo lectura. Las operaciones de escritura (subir, eliminar, renombrar, mover) están disponibles a través del Servidor MCP.
Endpoints
GET /api/v1/project
Retorna información sobre el proyecto autenticado.
Solicitud de ejemplo:
curl -H "x-project-key: $PROJECT_KEY" \
-H "x-user-key: $USER_KEY" \
https://sutram.io/api/v1/project
Respuesta:
{
"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
Lista las carpetas de nivel raíz del proyecto.
Solicitud de ejemplo:
curl -H "x-project-key: $PROJECT_KEY" \
-H "x-user-key: $USER_KEY" \
https://sutram.io/api/v1/folders
Respuesta:
{
"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
Retorna los detalles de una carpeta, sus subcarpetas y sus elementos de contenido.
Parámetros de ruta:
| Parámetro | Tipo | Descripción |
|---|---|---|
id |
UUID | ID de la carpeta |
Solicitud de ejemplo:
curl -H "x-project-key: $PROJECT_KEY" \
-H "x-user-key: $USER_KEY" \
https://sutram.io/api/v1/folders/f1a2b3c4-...
Respuesta:
{
"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
}
}
Respuestas de error:
| Estado | Cuerpo | Cuándo |
|---|---|---|
| 404 | {"error": "Folder not found"} |
La carpeta no existe o pertenece a otro proyecto |
GET /api/v1/content
Lista elementos de contenido con filtrado, búsqueda por etiquetas, búsqueda de texto y paginación.
Parámetros de consulta:
| Parámetro | Tipo | Predeterminado | Descripción |
|---|---|---|---|
folder_id |
UUID | — | Filtrar por carpeta. Sin este parámetro, retorna solo elementos del nivel raíz. |
all_folders |
boolean | false |
Si es true, busca en todas las carpetas (no solo en la raíz). Requerido para consultas de etiquetas/búsqueda en todo el proyecto. |
type |
string | — | Filtrar por tipo de contenido: "file", "web_link", "video_link", "audio_link" |
tag |
string | — | Clave de etiqueta única para filtrar (ej., tag=category) |
tag_value |
string | — | Valor de etiqueta a coincidir (se usa con tag). Coincidencia parcial sin distinción de mayúsculas/minúsculas. |
tags |
JSON | — | Múltiples condiciones AND como arreglo JSON (ej., tags=[{"key":"topic","value":"neuro"}]) |
search |
string | — | Buscar por nombre del elemento (coincidencia parcial sin distinción de mayúsculas/minúsculas) |
page |
integer | 1 |
Número de página |
per_page |
integer | 50 |
Elementos por página (máximo: 100) |
Comportamiento de búsqueda por etiquetas:
- Coincidencia de clave: Coincidencia exacta sin distinción de mayúsculas/minúsculas (
"Category"coincide con"category") - Coincidencia de valor: Coincidencia parcial sin distinción de mayúsculas/minúsculas (
"neuro"coincide con"Neurologia Avançada") - Múltiples condiciones (parámetro
tags): Todas las condiciones deben coincidir (lógica AND) - Sin valor: Cuando se omite
tag_value, coincide con cualquier elemento que tenga la clave de etiqueta sin importar el valor
Ejemplo — listar elementos raíz
curl -H "x-project-key: $PROJECT_KEY" \
-H "x-user-key: $USER_KEY" \
"https://sutram.io/api/v1/content"
Ejemplo — listar elementos en una carpeta
curl -H "x-project-key: $PROJECT_KEY" \
-H "x-user-key: $USER_KEY" \
"https://sutram.io/api/v1/content?folder_id=f1a2b3c4-..."
Ejemplo — filtrar por 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"
Ejemplo — búsqueda por etiqueta única
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"
Ejemplo — búsqueda AND con múltiples etiquetas
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"
El parámetro tags anterior es la versión codificada en URL de:
[{"key": "patient", "value": "joão"}, {"key": "year", "value": "2024"}]
Ejemplo — buscar por nombre
curl -H "x-project-key: $PROJECT_KEY" \
-H "x-user-key: $USER_KEY" \
"https://sutram.io/api/v1/content?search=report&all_folders=true"
Ejemplo — listado paginado
curl -H "x-project-key: $PROJECT_KEY" \
-H "x-user-key: $USER_KEY" \
"https://sutram.io/api/v1/content?page=2&per_page=20"
Respuesta:
{
"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
}
}
Campos del contentable por tipo:
El contentable se serializa bajo una clave que coincide con el tipo de elemento:
| Tipo | Clave | Campos |
|---|---|---|
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
Retorna los detalles completos de un elemento de contenido individual, incluyendo URLs de descarga prefirmadas para archivos.
Parámetros de ruta:
| Parámetro | Tipo | Descripción |
|---|---|---|
id |
UUID | ID del elemento de contenido |
Solicitud de ejemplo:
curl -H "x-project-key: $PROJECT_KEY" \
-H "x-user-key: $USER_KEY" \
https://sutram.io/api/v1/content/d5e6f7a8-...
Respuesta (archivo):
{
"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-..."
}
}
}
Respuesta (enlace de 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"
}
}
}
Respuesta (enlace de 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"
}
}
}
Respuesta (enlace 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"
}
}
}
Diferencias entre respuesta de detalle y de listado:
El endpoint /content/:id retorna campos adicionales en comparación con el endpoint de listado:
| Campo | Listado (/content) |
Detalle (/content/:id) |
|---|---|---|
folder_path |
No | Sí |
file.version |
No | Sí |
file.download_url |
No | Sí (prefirmada, temporal) |
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í |
Respuestas de error:
| Estado | Cuerpo | Cuándo |
|---|---|---|
| 404 | {"error": "Content item not found"} |
El elemento no existe o pertenece a otro proyecto |
Etiquetas de elementos de contenido
Las etiquetas son pares clave-valor de texto libre asociados a elementos de contenido y carpetas. Permiten metadatos estructurados y capacidades de búsqueda avanzadas.
Restricciones de etiquetas
| Restricción | Límite |
|---|---|
| Máximo de etiquetas por elemento | 50 |
| Longitud máxima de la clave | 100 caracteres |
| Longitud máxima del valor | 500 caracteres |
| Tipos de clave y valor | Solo cadenas de texto |
Gestión de etiquetas
Las etiquetas en los elementos de contenido se gestionan a través de las herramientas del Servidor MCP:
| Herramienta MCP | Descripción |
|---|---|
sutram_set_item_tags |
Establecer/reemplazar todas las etiquetas de un elemento de contenido |
sutram_search_items |
Buscar elementos por etiqueta (condición única o AND múltiple) |
sutram_get_item_tag_keys |
Listar todas las claves de etiquetas distintas entre los elementos |
Consulta la Guía de Usuario del Servidor MCP para más detalles sobre estas herramientas.
Consultar etiquetas a través de la API REST
Usa los parámetros de consulta tag, tag_value y tags en GET /api/v1/content:
# Find all items tagged with "category"
curl ... "https://sutram.io/api/v1/content?tag=category&all_folders=true"
# Find items where category contains "report"
curl ... "https://sutram.io/api/v1/content?tag=category&tag_value=report&all_folders=true"
# Find items matching multiple conditions (AND)
curl ... "https://sutram.io/api/v1/content?tags=[{\"key\":\"patient\",\"value\":\"joão\"},{\"key\":\"year\",\"value\":\"2024\"}]&all_folders=true"
Comparación: API REST vs. Servidor MCP
| Capacidad | API REST (/api/v1) |
Servidor MCP (/mcp) |
|---|---|---|
| Protocolo | HTTP/JSON | JSON-RPC 2.0 (MCP) |
| Leer contenido | Sí | Sí |
| Buscar por etiquetas | Sí | Sí |
| URLs de descarga | Sí (prefirmadas) | Sí (prefirmadas) |
| Subir archivos | No | Sí |
| Crear enlaces | No | Sí |
| Crear carpetas | No | Sí |
| Establecer etiquetas | No | Sí |
| Mover/renombrar/eliminar | No | Sí |
| Autenticación | Misma doble clave | Misma doble clave |
| Ideal para | Apps externas, dashboards, scripts | Asistentes de IA, automatización |
Límites de tasa
Actualmente no hay límites de tasa en la API REST. Esto podría cambiar en versiones futuras. Por favor, sé razonable con la frecuencia de las solicitudes.
Versionado
La API se versiona a través de la ruta en la URL (/api/v1). Los cambios incompatibles se introducirán en nuevas versiones (/api/v2). Adiciones no incompatibles (nuevos campos, nuevos parámetros opcionales) pueden agregarse a la versión actual sin previo aviso.
Ejemplos
Obtener todos los enlaces de video en un proyecto
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"
Obtener contenido etiquetado para un tema específico
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"
Navegar una jerarquía de carpetas
# 1. List root folders
curl ... "https://sutram.io/api/v1/folders"
# 2. Open a specific folder
curl ... "https://sutram.io/api/v1/folders/f1a2b3c4-..."
# 3. Get download URL for a file
curl ... "https://sutram.io/api/v1/content/d5e6f7a8-..."
Paginar a través de todo el contenido
# Page 1
curl ... "https://sutram.io/api/v1/content?page=1&per_page=20&all_folders=true"
# Page 2
curl ... "https://sutram.io/api/v1/content?page=2&per_page=20&all_folders=true"
# Continue until page >= total_pages from meta
Integración 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",
});
Integración 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")
Solución de problemas
401 No autorizado
- Verifica que ambos encabezados
x-project-keyyx-user-keyestén presentes - Comprueba que las claves no hayan sido revocadas
- Asegúrate de ser un miembro activo (no visualizador) del proyecto
404 No encontrado
- Verifica que el ID de carpeta/contenido pertenezca al proyecto autenticado
- Comprueba que el elemento no haya sido eliminado
Resultados vacíos en búsqueda por etiquetas
- Agrega
all_folders=truepara buscar en todas las carpetas (sin este parámetro, solo se retornan elementos del nivel raíz) - La búsqueda por etiquetas no distingue mayúsculas/minúsculas -- revisa si hay errores tipográficos en los nombres de las claves
- Usa
GET /api/v1/content?tag=TU_CLAVE&all_folders=truesin valor primero para verificar que la clave de etiqueta existe
El parámetro tags retorna error
- El parámetro
tagsdebe ser un arreglo JSON válido:[{"key": "...", "value": "..."}] - Codifica la cadena JSON en formato URL al pasarla como parámetro de consulta
- Cada condición debe tener un campo
key;valuees opcional