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 (
tagsparam): All conditions must match (AND logic) - No value: When
tag_valueis 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-keyandx-user-keyheaders 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=trueto 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=truewithout a value first to verify the tag key exists
tags parameter returns error
- The
tagsparameter 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
keyfield;valueis optional