POST /api/node
Create a new node, optionally under a parent node. Equivalent to node:add in WebSocket.
Behavior
-
If
targetis provided, the new node is attached as a child of the given parent. -
If no target is provided, node is owned solely by the creator with full access by default.
-
ACL:
- Caller must have at least editor access to the parent node.
- New node inherits the owner and ACL from the parent node.
- View-only is insufficient.
infoYou can create a stand-alone node (without specifying
target) and later attach it to a read-only branch usingPOST /api/link.In this case:
"source"→ your new node’sid,"target"→ the read-only node’sid,"type": 1→ secondary link (keeps your graph consistent without changing branch ACLs).
This way, you remain the owner of the new node, while still preserving graph consistency and task dependencies.
-
History batch records node creation, the link (if any) and all side effects like blocking parent (if any).
REST API
Endpoint: POST /api/node
Auth: API token
Rate limit: 300 requests per minute
Request body:
{
"target": "<uuid>", // optional parent node id
"title": "string",
"description": "string",
"status": 0,
"dueDate": "2025-09-13T10:00:00Z",
"tags": ["backend", "urgent"],
"priority": 5,
"independent": false,
"volume": 5,
"assignee": ["user-id"],
"pinned": false,
"collapsed": false
}
200 OK
{
"ok": true,
"diff": {
"batchId": "uuid", // ID of the history batch
"actor": {
"username": "alice",
"email": "alice@example.com"
},
"ts": "2025-09-25T10:00:00Z", // timestamp of the operation
"nodes": [
{
"op": 0, // History operation type NODE_ADD=0
"before": {},
"after": {
"id": "uuid",
"title": "string",
"description": "string",
"status": 0,
"dueDate": "2025-09-13T10:00:00Z",
"tags": ["backend", "urgent"],
"priority": 5,
"independent": false,
"volume": 5,
"assignee": ["user-id"],
"pinned": false,
"collapsed": false,
"createdTime": "2025-09-13T10:00:00Z",
"lastEditedTime": "2025-09-13T10:00:00Z",
"version": 0,
"shareRoots": ["uuid1", "uuid2"]
}
},
{
"op": 2, // History operation type NODE_STATUS=2
"before": {
"id": "uuid",
"status": 1, // Node status InProgress=1
"version": 2
},
"after": {
"id": "uuid",
"status": 2, // Node status Blocked=2
"version": 3,
"shareRoots": ["root-uuid-1", "root-uuid-2"],
"lastEditedTime": "2025-09-13T10:00:00Z"
}
}
],
"links": [
{
"op": 10, // History operation type LINK_ADD=10
"before": {},
"after": {
"id": "uuid",
"source": "nodeId",
"target": "nodeId",
"type": 0,
"wasBlocker": false,
"version": 0,
"shareRoots": ["uuid1", "uuid2"],
"createdTime": "2025-09-13T10:00:00Z",
"lastEditedTime": "2025-09-13T10:00:00Z"
}
}
],
"user": [],
"access": [],
}
}
The diff includes the newly created node (with all props). Existing nodes that were affected are also included with minimal snapshots (only changed fields). Existing nodes that were modified as a side effect (e.g., a parent being blocked) are also included, but only with the updated fields. Each diff may include existing nodes with partial updates (only changed fields). Consumers must merge by id+version, not overwrite blindly.
Errors: see error codes
Example (JavaScript)
async function createNode(apiBaseUrl, apiToken, payload, target) {
const resp = await fetch(`${apiBaseUrl}/node`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiToken}`,
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify({ ...payload, target })
});
if (!resp.ok) {
const err = await resp.json().catch(() => ({}));
throw new Error(`Node create failed: ${resp.status} ${err.error || ''}`);
}
return resp.json();
}
// usage
createNode('https://synaptask.space/api', '<YOUR_API_TOKEN>', { title: 'My Task' }, null)
.then(data => console.log('Created node diff:', data.diff))
.catch(console.error);
Example (Python)
import requests
API_BASE = "https://synaptask.space/api"
API_TOKEN = "<YOUR_API_TOKEN>"
payload = {
"title": "My Task",
"description": "A new task",
"status": 0,
}
resp = requests.post(
f"{API_BASE}/node",
headers={
"Authorization": f"Bearer {API_TOKEN}",
"Content-Type": "application/json"
},
json=payload
)
if resp.status_code != 200:
try:
err = resp.json()
except Exception:
err = {}
raise RuntimeError(f"Node create failed: {resp.status_code} {err}")
data = resp.json()
print("Created node diff:", data["diff"])
See also Node concept