Volver a la Documentación

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
file.version No
file.download_url No Sí (prefirmada, temporal)
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

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
Buscar por etiquetas
URLs de descarga Sí (prefirmadas) Sí (prefirmadas)
Subir archivos No
Crear enlaces No
Crear carpetas No
Establecer etiquetas No
Mover/renombrar/eliminar No
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-key y x-user-key esté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=true para 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=true sin valor primero para verificar que la clave de etiqueta existe

El parámetro tags retorna error

  • El parámetro tags debe 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; value es opcional