Uutter API Documentation
Base URL: https://uutter.com/api/v1
Authentication
All API requests require a Bearer token. Generate an API key at /settings/api. Include it in the Authorization header:
curl -H "Authorization: Bearer uut_your_key_here" https://uutter.com/api/v1/me
Rate Limits
Hourly limits scale with your account tier: 200 requests/hour (Sapling), 500 (Oak), 1,000 (Grove), or 2,000 (Forest) — sliding window, plus a burst cap of 5 requests per second. Rate limit headers are included on every response:
X-RateLimit-Limit: 500 X-RateLimit-Remaining: 487 X-RateLimit-Reset: 2026-03-25T19:00:00.000Z
Discovery
/meReturns your user info, API key metadata, rate limit status, and all collections you have access to with their permissions and field configurations.
{
"data": {
"user": { "id": "uuid", "username": "jonathan" },
"apiKey": {
"prefix": "uut_d0f1",
"createdAt": "2026-03-23T...",
"lastUsedAt": "2026-03-25T...",
"requestCount": 42
},
"rateLimit": { "limit": 500, "remaining": 487, "resetAt": "..." },
"collections": [
{
"id": "uuid",
"name": "Terence McKenna",
"url": "terence-mckenna",
"role": "owner",
"apiEnabled": true,
"permissions": ["create_entry", "get_entry", "search"],
"fields": {
"title": "required",
"introduction": "disabled",
"description": "optional",
"image": "optional",
"audio": "optional",
"contentCategory": "optional",
"people": "optional"
}
}
]
}
}Collections
Create Collection
/collectionsCreates a new collection. Private by default. API and MCP access are enabled by default with all endpoint permissions seeded, so the collection is immediately usable via both API and MCP.
name(string)required— 3-42 charactersurl(string)required— 3-42 chars, lowercase alphanumeric + hyphensisPrivate(boolean)— Default: truedescription(string)— 7-159 characterstheme(string)— Hex colorcollaborationType(string)— open | approval | contributors | privateisOpenToRequests(boolean)— Default: falseshouldAutoTranscribe(boolean)— Default: trueshouldAutoProcessDocuments(boolean)— Default: trueallowsCrossPosting(boolean)— Default: falseapiAccessEnabled(boolean)— Default: true. All endpoint permissions are seeded regardless of this flag.mcpAccessEnabled(boolean)— Default: true. Requires apiAccessEnabled to also be true.hasTableView(boolean)— Enable table view on the collection pagehasLibraryView(boolean)— Enable library view on the collection pagedefaultView(string)— post | table | libraryhideEntryAuthors(boolean)— Hide the poster + date on entry cards. Default: falseisEntity(boolean)— Mark the collection as representing a real-world person/entity (drives schema.org Person JSON-LD). Default: falseentityName(string)— Display name of the entity (used with isEntity)entitySameAs(array)— schema.org sameAs URLs identifying the entity, e.g. its Wikipedia / Wikidata pages. Max 8allowedContentTypes(object)— Field name to "required" | "optional" | "disabled"mediaLimits(object)— image/video/audio/document limits (1-10)links(array)— Resource links (max 6). Array of { url, name } objects — name is shown in the UI (legacy title also accepted)tags(array)— Up to 8 tags. Each value is an existing tag id OR a tag name — unknown names are created automatically.curl -X POST https://uutter.com/api/v1/collections \
-H "Authorization: Bearer uut_..." \
-H "Content-Type: application/json" \
-d '{"name": "My Archive", "url": "my-archive"}'Get Collection
/collections/{collectionId}Returns full collection settings including field configuration, media limits, and feature flags.
Update Collection
/collections/{collectionId}Partial update — only provided fields are changed. Owner or admin required.
name(string)description(string | null)— 7-159 characters; null to cleartheme(string | null)isPrivate(boolean)collaborationType(string)shouldAutoTranscribe(boolean)enableContentAnalytics(boolean)hasTableView(boolean)hasLibraryView(boolean)defaultView(string)— post | table | library — must point at an enabled viewhideEntryAuthors(boolean)— Hide the poster + date on entry cardsisEntity(boolean)— Mark the collection as representing a real-world person/entityentityName(string | null)— Display name of the entity; null to clearentitySameAs(array)— schema.org sameAs URLs (Wikipedia / Wikidata, etc.). Max 8; empty array clearsavatarUrl(string | null)— URL of the collection avatar image; null to clear. Prefer avatarFile to upload an image.coverImageUrl(string | null)— URL of the collection cover image; null to clear. Prefer coverFile to upload an image.avatarFile(string | null)— Avatar image file name (jpg/jpeg/png/gif/webp) to upload. The response returns an uploads array with a signed PUT URL — PUT the bytes to it with the returned Content-Type. null clears.coverFile(string | null)— Cover image file name to upload (same flow as avatarFile). null clears.tags(array)— Full replacement of tags. Max 8. Each value is an existing tag id OR a tag name — unknown names are created. Pass an empty array to clear.links(array | null)— Resource links (max 6, null to clear). Array of { url, name } objects (legacy title also accepted)allowedContentTypes(object)— Merges with existing (partial update)Entries
List Entries
/collections/{collectionId}/entriesPermission: get_entryPaginated list of entries with metadata, people, media, and engagement.
page(number)— Default: 1limit(number)— Default: 20, max: 100The id in each entry is the collection_entries ID (matches the web URL). Use this for GET/PUT single entry.
Get Single Entry
/collections/{collectionId}/entries/{entryId}Permission: get_entryFull entry including editorText, media with transcripts, people, and engagement. The entryId is the collection_entries ID from the list.
Create Entry (Text Only)
/collections/{collectionId}/entriesPermission: create_entrySend a JSON body with text fields. Creates and publishes immediately.
introduction(string)description(string)title(string)editorText(string)date(object)— { day, month, year }location(string)contentCategory(string)— interview, lecture, speech, etc.medium(string)— radio, television, podcast, etc.sourceName(string)sourceUrl(string)contextLabel(string)people(array)— [{ name, role }] — speaker, host, guest, etc.curl -X POST https://uutter.com/api/v1/collections/{id}/entries \
-H "Authorization: Bearer uut_..." \
-H "Content-Type: application/json" \
-d '{
"introduction": "Alan Watts on consciousness",
"contentCategory": "lecture",
"medium": "radio",
"people": [{"name": "Alan Watts", "role": "speaker"}]
}'Create Entry (With Media)
Two-step flow: create draft with file names, upload files, then publish.
Step 1: Include a files array with file names. Returns upload URLs.
// Request
{"introduction": "...", "files": ["photo.jpg", "audio.mp3"]}
// Response
{
"data": {
"id": "entry-id",
"status": "draft",
"uploads": [
{
"mediaId": "uuid",
"fileName": "photo.jpg",
"mediaType": "IMAGE",
"uploadUrl": "https://...signed-url...",
"method": "PUT",
"headers": { "Content-Type": "image/jpeg" }
}
]
}
}Step 2: Upload each file to its uploadUrl using the specified method and headers.
Step 3: Publish the draft:
{"entryId": "entry-id-from-step-1"}Supported file types: jpg, png, gif, webp, mp3, wav, ogg, m4a, flac, mp4, mov, webm, pdf, epub. Videos return a TUS upload URL.
Update Entry
/collections/{collectionId}/entries/{entryId}Permission: update_entryPartial update. Set a field to null to clear it. People array replaces all existing people.
Search
/collections/{collectionId}/searchPermission: searchHybrid semantic + full-text search across transcripts and documents. Uses OpenAI embeddings with PostgreSQL pgvector. 60 searches/hour limit.
query(string)required— Search texttype(string)— all | transcripts | documents (default: all)page(number)— Default: 1curl -X POST https://uutter.com/api/v1/collections/{id}/search \
-H "Authorization: Bearer uut_..." \
-H "Content-Type: application/json" \
-d '{"query": "psychedelics and consciousness"}'Returns ranked results with text snippets, entry context, and score. Cached queries are faster on repeat searches.
Media
/media/{mediaId}Permission: get_entryCheck processing status of a media file. Useful for polling video transcoding progress.
{
"data": {
"mediaId": "uuid",
"status": "linked | transcoding | uploading | error",
"mediaType": "VIDEO",
"fileName": "lecture.mp4",
"fileSize": 12345678
}
}Analytics
Entry Analytics
/collections/{collectionId}/entries/{entryId}/analyticsPermission: get_entry_analyticsDetailed NLP analytics per entry: readability scores, sentiment, topics, entities, vocabulary, filler words. Requires content analytics enabled on the collection.
Collection Analytics
/collections/{collectionId}/analyticsPermission: get_collection_analyticsAggregated analytics across all entries: average readability, sentiment distribution, top topics, engagement stats.
MCP (Model Context Protocol)
Uutter supports MCP for LLM agents like Claude Desktop. The MCP server exposes all API endpoints as JSON-RPC tools. Configure it in API Settings.
MCP endpoint: https://uutter.com/api/mcp/v1
Requires OAuth 2.1 + PKCE authentication. Collections must have both API access and MCP access enabled.
Permissions
API access is controlled at three levels: collection toggle, collection allowlist, and per-member grants.
Collection owners inherit all collection-level permissions. Members need explicit grants from the owner/admin via the collaborators page.
Error Handling
Errors return a JSON object with an error field:
{ "error": "Description of what went wrong" }