π¬ Understand Tree
Runs AI-powered compression across an entire tree. The AI reads every node, summarizes leaf content, then merges summaries layer by layer until a single root encoding remains β a holistic understanding of the whole tree from a given perspective.
Example perspectives:
translate to Chinesesummarize this into 30 wordsfind all the places where marketing strategy is mentionedextract every action item and deadlineidentify contradictions or conflicting ideas
POST/api/v1/root/:rootId/understandings
Create a new understanding run. Pass a perspective in the request body to tell the AI what lens to use. Set incremental totrue to reuse an existing completed run and only reprocess nodes that changed since the last run.
Request Body
{ "perspective": "summarize this into 30 words", "incremental": true }
When incremental is true, the system finds the most recent completed run for the same root and perspective, detects which nodes have new contributions, and only reprocesses dirty nodes and their ancestors. If no prior run exists, a fresh run is created. Defaults to false.
POST/api/v1/root/:rootId/understandings/run/:runId/orchestrate
Run the AI understanding orchestrator on an existing run. The AI compresses all nodes layer by layer until a single root encoding remains. Only one orchestration can run at a time per run.
Success Response
{
"success": true,
"understandingRunId": "abc123",
"perspective": "summarize this into 30 words",
"nodeCount": 12,
"nodesProcessed": 11,
"rootEncoding": "Compressed summary of the treeβ¦"
}
Already Complete
{ "success": true, "alreadyComplete": true, "rootEncoding": "β¦" }
Create a run first via POST /api/v1/root/:rootId/understandings, then trigger orchestration. This is a long-running request β the AI processes every node in the tree. Idempotent β if the run was interrupted, calling again picks up where it left off. If already complete, returns the final result immediately.
POST/api/v1/root/:rootId/understandings/run/:runId/stop
Stop an active understanding orchestration. Aborts the in-flight session and halts processing. Progress is preserved -- calling orchestrate again will resume from where it stopped.
Success Response
{ "success": true }
No Active Session
{ "success": false, "error": "No active session found for this run" }
π€ User Endpoints
Profile, roots, API keys, contributions, notes, tags, raw ideas, invites, chat history, and custom LLM configuration.
Profile
GET/api/v1/user/:userId
Returns user profile, root nodes, and account metadata.
Create Root
POST/api/v1/user/:userId/createRoot
Create a new root tree for the user.
Request Body
{ "name": "My New Tree" }
API Keys
POST/api/v1/user/:userId/api-keys
Create a new API key.
Request Body
{ "name": "optional descriptive name" }
Response
{ "apiKey": "fcd8a7c7...", "message": "Store this key securely. You will not see it again." }
The full key is only shown once at creation time.
GET/api/v1/user/:userId/api-keys
List all API keys (active and revoked) for the user.
DELETE/api/v1/user/:userId/api-keys/:keyId
Revoke an API key. It will no longer authenticate requests.
Share Token
The URL token used for ?token= authentication on GET routes.
POST/api/v1/user/:userId/shareToken
Create or refresh the URL share token. Invalidates the previous token.
Contributions
GET/api/v1/user/:userId/contributions
All contributions made by the user across all trees.
Query Parameters
?limit=NUMBERMax results to return
?startDate=YYYY-MM-DDFilter from date
?endDate=YYYY-MM-DDFilter to date
Notes
GET/api/v1/user/:userId/notes
List or search all notes posted by the user.
Query Parameters
?q=SEARCHFull-text search query
?limit=NUMBERMax results to return
?startDate=YYYY-MM-DDFilter from date
?endDate=YYYY-MM-DDFilter to date
Tagged Notes (Inbox)
GET/api/v1/user/:userId/tags
Notes where the user has been @tagged by another user.
Raw Ideas
Unstructured inputs (text or files) that can later be converted into notes and placed into a tree.
POST/api/v1/user/:userId/raw-ideas
Create a new raw idea. Accepts multipart form data.
Form Fields
content: "text string"
file: (optional file upload)
GET/api/v1/user/:userId/raw-ideas
List or search raw ideas. Defaults to pending ideas.
Query Parameters
?status=VALUEFilter by status. One of: pending (default), processing, succeeded, stuck, deleted, all
?q=SEARCHFull-text search query (searches within content)
?limit=NUMBERMax results to return (max 200, default 200)
?startDate=YYYY-MM-DDFilter from date
?endDate=YYYY-MM-DDFilter to date
Succeeded ideas are sorted by placement date (placedAt) descending. All others sort by creation date.
GET/api/v1/user/:userId/raw-ideas/:rawIdeaId
View a single raw idea including its status and AI session link.
POST/api/v1/user/:userId/raw-ideas/:rawIdeaId/transfer
Manually convert a raw idea into a note on a target node.
Request Body
{ "nodeId": "targetNodeId" }
Returns 409 if the idea is currently being processed by AI.
DELETE/api/v1/user/:userId/raw-ideas/:rawIdeaId
Permanently delete a raw idea.
Returns 409 if the idea has status processing or succeeded.
Deleted Branches
Deleted branches are soft-deleted and can be restored.
GET/api/v1/user/:userId/deleted
List all soft-deleted branches for the user.
POST/api/v1/user/:userId/deleted/:nodeId/revive
Restore a deleted branch under a parent node.
Request Body
{ "targetParentId": "nodeId" }
POST/api/v1/user/:userId/deleted/:nodeId/reviveAsRoot
Restore a deleted branch as a new root tree.
Invites & Collaboration
GET/api/v1/user/:userId/invites
List pending invitations to collaborate on other users' trees.
POST/api/v1/user/:userId/invites/:inviteId
Accept or decline a collaboration invite.
Request Body
{ "accept": true } // true to accept, false to decline
Energy
GET/api/v1/user/:userId/energy
View current energy balance, plan tier, profile type, and custom LLM connection status.
Custom LLM Connections
Connect your own LLM providers for AI features. Each user can have up to 15 connections and assign them to different slots. Any OpenAI-compatible endpoint works.
GET/api/v1/user/:userId/custom-llm
List all custom LLM connections for the user.
Response
{ "success": true, "connections": [
{ "_id": "...", "name": "GPT-4o", "baseUrl": "https://api.openai.com/v1", "model": "gpt-4o", ... }
] }
POST/api/v1/user/:userId/custom-llm
Create a new custom LLM connection.
Request Body
{
"name": "My GPT-4o",
"baseUrl": "https://api.openai.com/v1",
"apiKey": "sk-...",
"model": "gpt-4o"
}
Max 15 connections per user. API key is encrypted at rest.
PUT/api/v1/user/:userId/custom-llm/:connectionId
Update an existing connection's name, URL, key, or model.
Request Body
{
"name": "Updated Name",
"baseUrl": "https://api.openai.com/v1",
"apiKey": "sk-new-key",
"model": "gpt-4o-mini"
}
Only apiKey and name are optional β omit apiKey to keep the existing key.
DELETE/api/v1/user/:userId/custom-llm/:connectionId
Permanently delete a connection. Auto-removes it from all user slots and root tree assignments.
POST/api/v1/user/:userId/llm-assign
Assign a connection to a user-level LLM slot, or unassign by passing null.
Request Body
{ "slot": "main", "connectionId": "connection-id-here" }
Allowed Slots
main β Default slot used for tree chat/profile
rawIdea β Used for raw idea auto-placement
Pass connectionId: null to unassign the slot.
AI Chat History
GET/api/v1/user/:userId/chats
View AI chat history grouped by session.
Notifications
Notifications are generated automatically after tree dreams complete. Each dream produces a summary and a thought for the tree owner and contributors.
GET/api/v1/user/:userId/notifications
List notifications for the user, newest first.
Query Parameters
?rootId=IDFilter to a specific tree
?limit=NUMBERMax results (default 20, max 100)
?offset=NUMBERSkip N results for pagination
Response
{ "notifications": [
{ "type": "dream-summary", "title": "...", "content": "...", "rootId": "...", "createdAt": "..." },
{ "type": "dream-thought", "title": "...", "content": "...", "rootId": "...", "createdAt": "..." }
], "total": 12, "limit": 20, "offset": 0 }
Types: dream-summary (recap of what the dream did) and dream-thought (a reflective insight based on the dream activity).
π³ Root Endpoints
Roots are the top-level entry point of a tree. Most tree-wide operations happen at this scope.
Tree Data
GET/api/v1/root/:rootId
Full tree including all children, metadata, notes, and contributions.
Query Parameters
?active=true|falseFilter by active status
?completed=true|falseFilter by completed status
?trimmed=true|falseFilter by trimmed status
Global Values
GET/api/v1/root/:rootId/values
All values aggregated across every child node in the tree.
Contributors & Ownership
POST/api/v1/root/:rootId/invite
Invite a collaborator to the tree.
Request Body
{ "userReceiving": "username-or-userId" }
POST/api/v1/root/:rootId/transfer-owner
Transfer tree ownership to another contributor.
Request Body
{ "userReceiving": "username-or-userId" }
POST/api/v1/root/:rootId/remove-user
Remove a contributor from the tree.
Request Body
{ "userReceiving": "username-or-userId" }
POST/api/v1/root/:rootId/retire
Archive the root (soft delete entire tree). Only the owner can do this when there are no other contributors.
Transaction Policy
POST/api/v1/root/:rootId/transaction-policy
Set the approval policy for transactions on this tree.
Request Body
{ "policy": "OWNER_ONLY" }
Allowed Values
OWNER_ONLY β Only the tree owner can approve
ANYONE β Any contributor can approve
MAJORITY β Majority of contributors must approve
ALL β All contributors must approve
Tree AI Models
POST/api/v1/root/:rootId/llm-assign
Assign a custom LLM connection to a tree slot. Owner-only, requires paid plan.
Request Body
{ "slot": "placement", "connectionId": "connection-id-here" }
Allowed Slots
placement β Tree chat, navigation, node placement, classification
understanding β Understanding runs (falls back to placement)
respond β Final user-facing responses (falls back to placement)
notes β Note creation and editing (falls back to placement)
cleanup β Cleanup analysis and expansion (falls back to placement)
drain β Short-term memory drain placement (falls back to placement)
notification β Dream notification summary and thought (falls back to placement)
Pass connectionId: null to unassign and revert to the user's default. The connection must belong to the root owner. Unset slots fall back to placement, then to the user's default LLM.
Dream Time
POST/api/v1/root/:rootId/dream-time
Set or clear the nightly dream schedule for a tree. When set, the tree will automatically run cleanup and understanding processes at the specified time. Owner-only.
Request Body
{ "dreamTime": "03:00" }
Use 24-hour HH:MM format. Pass null or omit to disable dreaming.
Calendar
GET/api/v1/root/:rootId/calendar
All scheduled dates across every node in the tree.
Query Parameters
?month=0β11Filter by month (0 = Jan)
?year=YYYYFilter by year
?day=YYYY-MM-DDFilter by day (HTML mode)
βοΈ Scripts
Nodes can have attached scripts β small JavaScript programs that run in a sandboxed VM. Scripts can read and mutate node values, goals, status, schedule, and prestige.
POST/api/v1/node/:nodeId/script/create
Create or update a script on this node.
Request Body
{
"name": "dailyReset",
"script": "setValueForNode('streak', 0);"
}
Max 2000 characters. Scripts are node-scoped (not version-scoped).
GET/api/v1/node/:nodeId/script/:scriptId
View a script's source code and metadata.
POST/api/v1/node/:nodeId/script/:scriptId/execute
Execute a script on this node.
Response
{
"message": "Script executed successfully",
"logs": ["console output line 1", "..."],
"node": { "...updated node data" }
}
Script environment: Sandboxed VM, 3-second timeout, up to 200 console.log lines captured.
Available Functions Inside Scripts
getApi()
setValueForNode(key, value)
setGoalForNode(key, goal)
editStatusForNode(status)
addPrestigeForNode()
updateScheduleForNode(datetime | null)
Scripts run under the permissions of the calling user or API key. Failures are logged with captured output and error messages.
π Node Version Endpoints
Version-scoped operations for status, schedule, prestige, notes, values, goals, and contributions.
Status & Schedule
POST/api/v1/node/:nodeId/:version/editStatus
Change status for this node. Optionally apply to all children.
Request Body
{
"status": "active | completed | trimmed",
"isInherited": true
}
isInherited (optional, default false) β when true, the status change cascades to all children.
POST/api/v1/node/:nodeId/:version/editSchedule
Set or clear the scheduled date for this node.
Request Body
{
"newSchedule": "2026-03-15T09:00:00Z",
"reeffectTime": 24
}
// clear schedule:
{ "newSchedule": null }
reeffectTime is optional β hours until the schedule repeats after prestige (recurring interval).
POST/api/v1/node/:nodeId/:version/prestige
Add a new version (prestige) to this node. Creates version N+1.
Notes
GET/api/v1/node/:nodeId/:version/notes
List all notes on this version.
Query Parameters
?limit=NUMBERMax results
?startDate=YYYY-MM-DDFilter from date
?endDate=YYYY-MM-DDFilter to date
POST/api/v1/node/:nodeId/:version/notes
Create a new note. Supports text or file upload via multipart form data.
Text Note β JSON Body
{ "content": "Your note text here" }
File Note β Multipart Form
content: (file)
Content-Type: multipart/form-data
GET/api/v1/node/:nodeId/:version/notes/:noteId
View a single note. Text notes return content; file notes return the file.
PUT/api/v1/node/:nodeId/:version/notes/:noteId
Edit an existing text note. File notes cannot be edited.
Request Body
{ "content": "Updated note text" }
Response
{ "success": true, "_id": "...", "message": "Note updated successfully" }
DELETE/api/v1/node/:nodeId/:version/notes/:noteId
Permanently delete a note.
POST/api/v1/node/:nodeId/:version/notes/:noteId/transfer
Transfer a note to a different node in the same tree. Logs contributions on both source and target.
Request Body
{ "targetNodeId": "destination-node-id", "prestige": 0 }
Response
{ "success": true, "noteId": "...", "from": { "nodeId": "...", "version": 0 }, "to": { "nodeId": "...", "version": 0 } }
GET/api/v1/node/:nodeId/:version/notes/book
Book view β all notes in hierarchical format including children nodes.
GET/api/v1/node/:nodeId/:version/notes/editor
Open the full-page note editor for creating a new note.
HTML only. Add ?token=...&html to access.
GET/api/v1/node/:nodeId/:version/notes/:noteId/editor
Open the full-page editor for an existing note.
HTML only. File notes redirect to the view page.
Contributions
GET/api/v1/node/:nodeId/:version/contributions
List all contributions on this node version.
Query Parameters
?limit=NUMBERMax results
?startDate=YYYY-MM-DDFilter from date
?endDate=YYYY-MM-DDFilter to date
Values & Goals
Version-scoped keyβvalue pairs for metrics, automation, and computed state. Keys prefixed with _auto__ are read-only and system-generated.
GET/api/v1/node/:nodeId/:version/values
List all values and goals on this version.
POST/api/v1/node/:nodeId/:version/value
Set a value on this version.
Request Body
{ "key": "revenue", "value": 42000 }
POST/api/v1/node/:nodeId/:version/goal
Set a goal on this version.
Request Body
{ "key": "revenue", "goal": 100000 }
π€ Transactions
Transactions are value trades between two sides. Each side is either a NODE (an internal tree node with keyβvalue pairs) or OUTSIDE (an external source like a Solana wallet). Approval follows the tree's transaction policy.
How sides work:
β’ NODE β trades node values (keyβvalue pairs). Requires nodeId and versionIndex.
β’ OUTSIDE β represents an external source (e.g. a Solana wallet). Uses sourceType and sourceId. Cannot carry values β only the NODE side sends/receives.
Values: valuesA and valuesB are objects mapping value keys to amounts (e.g. { "gold": 100 }). Each side's values represent what that side gives. At least one side must include values. An OUTSIDE side cannot have values.
List & View
GET/api/v1/node/:nodeId/:version/transactions
List all transactions (pending, accepted, and rejected) for this node version.
GET/api/v1/node/:nodeId/:version/transactions/:transactionId
View a single transaction including both sides, traded values, approval groups, and status.
Create
POST/api/v1/node/:nodeId/:version/transactions
Create a new transaction proposal between two sides.
Node β Node Example
{
"sideA.kind": "NODE",
"sideA.nodeId": "node-id-A",
"versionAIndex": 1,
"valuesA": { "gold": 100 },
"sideB.kind": "NODE",
"sideB.nodeId": "node-id-B",
"versionBIndex": 2,
"valuesB": { "wood": 50 }
}
Node β Outside (Solana) Example
{
"sideA.kind": "NODE",
"sideA.nodeId": "node-id-A",
"versionAIndex": 1,
"valuesA": { "gold": 100 },
"sideB.kind": "OUTSIDE",
"sideB.sourceType": "SOLANA",
"sideB.sourceId": "So1anaWa11etAddr3ss..."
}
Field Reference
sideX.kindNODE or OUTSIDE β only one side may be OUTSIDE
sideX.nodeIdRequired when kind is NODE
sideX.sourceTypeExternal source type (currently SOLANA). Used when kind is OUTSIDE
sideX.sourceIdExternal identifier (e.g. Solana wallet address). Used when kind is OUTSIDE
versionXIndexRequired for NODE sides. Side B defaults to latest version if omitted
valuesXObject of { key: amount } that this side gives. OUTSIDE sides cannot have values
Self-trades (same node + same version on both sides) are not allowed. If all approval groups resolve immediately, the transaction executes on creation.
Approve & Deny
Approval follows the tree's transaction policy (set via POST /api/v1/root/:rootId/transaction-policy). Depending on the policy, one or more approvals may be needed. Status transitions: pending β accepted or rejected.
POST/api/v1/node/:nodeId/:version/transactions/:transactionId/approve
Approve a pending transaction. When enough approvals are collected (per policy), the transaction executes and values are exchanged.
POST/api/v1/node/:nodeId/:version/transactions/:transactionId/deny
Deny a pending transaction. Sets the transaction status to rejected.
π Blog
Public endpoints for reading blog posts. No authentication required.
GET/api/v1/blog/posts
List all published blog posts, sorted by newest first.
Response
{
"success": true,
"posts": [
{
"title": "Why I Built Tree",
"slug": "why-i-built-tree",
"summary": "...",
"publishedAt": "2026-03-15T...",
"authorName": "tabor"
}
]
}
GET/api/v1/blog/posts/:slug
Get a single published blog post by its slug, including full content.
Response
{
"success": true,
"post": {
"title": "Why I Built Tree",
"slug": "why-i-built-tree",
"content": "<p>Full HTML content...</p>",
"summary": "...",
"publishedAt": "2026-03-15T...",
"authorName": "tabor"
}
}