Back to Documentation

Sutram Rest API v1

Version: 0.89.0 Date: 2026-02-19 Status: In production


Overview

The Sutram REST API provides JSON endpoints for external consumption of project content (folders, files, links). It uses the same dual-key authentication as the MCP Server (x-project-key + x-user-key), so any project with Remote Access enabled is automatically accessible via the REST API.

Use cases

  • APM Platform integration — Consume Sutram content (events, news, podcasts, webinars) as a central repository (SSOT)
  • Custom dashboards — Build content listing pages outside of Sutram
  • Mobile apps — Fetch files and links with presigned download URLs
  • Automation — Programmatic content discovery and retrieval via scripts or CI/CD

Base URL

https://sutram.io/api/v1

Development:

http://localhost:4001/api/v1

How it works

External Client (app, script, dashboard)
        |
        | HTTPS + JSON
        v
  Sutram REST API
    /api/v1/*
        |
        | Dual Key Authentication
        v
  Project Content (folders, files, links, tags)

Authentication

Every request must include two headers:

Header Value Description
x-project-key sk_proj_... Identifies the project
x-user-key sk_user_... Identifies the user

Both keys are created through the Sutram web interface. See the MCP Server User Guide for step-by-step instructions.

Example

curl -H "x-project-key: sk_proj_ej8NWMisd2rJgMwAJ22T..." \
     -H "x-user-key: sk_user_zQD0BjH56nQhOgX3uxni..." \
     https://sutram.io/api/v1/project

Error responses

When authentication fails, the API returns 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" }

Permissions

Role Access
Owner Full read access
Admin Full read access
Member Full read access
Viewer No access (401)

The REST API v1 is read-only. Write operations (upload, delete, rename, move) are available through the MCP Server.


Endpoints

GET /api/v1/project

Returns information about the authenticated project.

Example request:

curl -H "x-project-key: $PROJECT_KEY" \
     -H "x-user-key: $USER_KEY" \
     https://sutram.io/api/v1/project

Response:

{
  "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

Lists root-level folders of the project.

Example request:

curl -H "x-project-key: $PROJECT_KEY" \
     -H "x-user-key: $USER_KEY" \
     https://sutram.io/api/v1/folders

Response:

{
  "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

Returns a folder's details, its subfolders, and its content items.

Path parameters:

Parameter Type Description
id UUID Folder ID

Example request:

curl -H "x-project-key: $PROJECT_KEY" \
     -H "x-user-key: $USER_KEY" \
     https://sutram.io/api/v1/folders/f1a2b3c4-...

Response:

{
  "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
  }
}

Error responses:

Status Body When
404 {"error": "Folder not found"} Folder does not exist or belongs to another project

GET /api/v1/content

Lists content items with filtering, tag search, text search, and pagination.

Query parameters:

Parameter Type Default Description
folder_id UUID Filter by folder. Without this, returns root-level items only.
all_folders boolean false If true, searches across all folders (not just root). Required for tag/search queries across the whole project.
type string Filter by content type: "file", "web_link", "video_link", "audio_link"
tag string Single tag key to filter by (e.g., tag=category)
tag_value string Tag value to match (used with tag). Case-insensitive substring match.
tags JSON Multiple AND conditions as JSON array (e.g., tags=[{"key":"topic","value":"neuro"}])
search string Search by item name (case-insensitive substring match)
page integer 1 Page number
per_page integer 50 Items per page (max: 100)

Tag search behavior:

  • Key matching: Case-insensitive exact match ("Category" matches "category")
  • Value matching: Case-insensitive substring match ("neuro" matches "Neurologia Avançada")
  • Multiple conditions (tags param): All conditions must match (AND logic)
  • No value: When tag_value is omitted, matches any item that has the tag key regardless of value

Example — list root items

curl -H "x-project-key: $PROJECT_KEY" \
     -H "x-user-key: $USER_KEY" \
     "https://sutram.io/api/v1/content"

Example — list items in a folder

curl -H "x-project-key: $PROJECT_KEY" \
     -H "x-user-key: $USER_KEY" \
     "https://sutram.io/api/v1/content?folder_id=f1a2b3c4-..."

Example — filter by type

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"

Example — single tag search

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"

Example — multi-tag AND search

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"

The tags parameter above is the URL-encoded version of:

[{"key": "patient", "value": "joão"}, {"key": "year", "value": "2024"}]

Example — search by name

curl -H "x-project-key: $PROJECT_KEY" \
     -H "x-user-key: $USER_KEY" \
     "https://sutram.io/api/v1/content?search=report&all_folders=true"

Example — paginated listing

curl -H "x-project-key: $PROJECT_KEY" \
     -H "x-user-key: $USER_KEY" \
     "https://sutram.io/api/v1/content?page=2&per_page=20"

Response:

{
  "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
  }
}

Contentable fields by type:

The contentable is serialized under a key matching the item type:

Type Key Fields
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

Returns full details of a single content item, including presigned download URLs for files.

Path parameters:

Parameter Type Description
id UUID Content item ID

Example request:

curl -H "x-project-key: $PROJECT_KEY" \
     -H "x-user-key: $USER_KEY" \
     https://sutram.io/api/v1/content/d5e6f7a8-...

Response (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-..."
    }
  }
}

Response (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"
    }
  }
}

Response (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"
    }
  }
}

Response (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"
    }
  }
}

Detail vs. list response differences:

The /content/:id endpoint returns additional fields compared to the list endpoint:

Field List (/content) Detail (/content/:id)
folder_path No Yes
file.version No Yes
file.download_url No Yes (presigned, temporary)
web_link.fetched_description No Yes
video_link.duration_seconds No Yes
video_link.fetched_title No Yes
audio_link.duration_seconds No Yes
audio_link.fetched_title No Yes

Error responses:

Status Body When
404 {"error": "Content item not found"} Item does not exist or belongs to another project

Content Item Tags

Tags are free-form key-value string pairs attached to content items and folders. They enable structured metadata and powerful search capabilities.

Tag constraints

Constraint Limit
Maximum tags per item 50
Maximum key length 100 characters
Maximum value length 500 characters
Key and value types Strings only

Managing tags

Tags on content items are managed through the MCP Server tools:

MCP Tool Description
sutram_set_item_tags Set/replace all tags on a content item
sutram_search_items Search items by tag (single or multi-condition AND)
sutram_get_item_tag_keys List all distinct tag keys across items

See the MCP Server User Guide for details on these tools.

Querying tags via REST API

Use the tag, tag_value, and tags query parameters on 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"

Comparison: REST API vs. MCP Server

Capability REST API (/api/v1) MCP Server (/mcp)
Protocol HTTP/JSON JSON-RPC 2.0 (MCP)
Read content Yes Yes
Search by tags Yes Yes
Download URLs Yes (presigned) Yes (presigned)
Upload files No Yes
Create links No Yes
Create folders No Yes
Set tags No Yes
Move/rename/delete No Yes
Authentication Same dual-key Same dual-key
Best for External apps, dashboards, scripts AI assistants, automation

Rate Limits

There are currently no rate limits on the REST API. This may change in future versions. Please be reasonable with request frequency.


Versioning

The API is versioned via the URL path (/api/v1). Breaking changes will be introduced in new versions (/api/v2). Non-breaking additions (new fields, new optional parameters) may be added to the current version without notice.


Examples

Fetch all video links in a project

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"

Fetch content tagged for a specific topic

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"

Browse a folder hierarchy

# 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-..."

Paginate through all content

# 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

Integration with 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 with 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")

Troubleshooting

401 Unauthorized

  • Verify both x-project-key and x-user-key headers are present
  • Check that the keys haven't been revoked
  • Ensure you're an active member (not viewer) of the project

404 Not Found

  • Verify the folder/content ID belongs to the authenticated project
  • Check that the item hasn't been deleted

Empty results with tag search

  • Add all_folders=true to search across all folders (without it, only root items are returned)
  • Tag search is case-insensitive — check for typos in key names
  • Use GET /api/v1/content?tag=YOUR_KEY&all_folders=true without a value first to verify the tag key exists

tags parameter returns error

  • The tags parameter must be a valid JSON array: [{"key": "...", "value": "..."}]
  • URL-encode the JSON string when passing it as a query parameter
  • Each condition must have a key field; value is optional