Skip to main content
All writes go through a single endpoint. The action field determines the operation.

Add a Node

Creates a new node with an auto-generated ID.
Response:

Parent rules

Update a Node

PATCH semantics. Only include fields you want to change. Existing fields are preserved.
To mark a job as not done, set status to null.

Delete a Node

Hard delete. The node is removed from the table, but the full node is kept in the changelog, so a delete is recoverable with restore (below).

Restore a Node

Recover a hard-deleted node from the changelog. It returns with its original id, type, parentId, and data. Identify it by nodeId (restores the most recent deletion of that node) or by a specific changelogId.
  • 409 if a node with that id already exists (nothing to restore). 404 if no deletion is on record.
  • If the node’s original parent was also deleted, it comes back orphaned (dangling parentId). Restore the parent too, or reparent. The response _meta._tip flags this.
  • Restore does not cascade. It brings back the single node, not its former children.

Batch Mutations

Multiple operations in a single request. All-or-nothing. If any mutation fails validation, the entire batch is rejected.

Idempotency

Make any mutate call (single or batch) safe to retry by sending an Idempotency-Key header. An opaque per-operation string (a UUID is ideal):
  • Replay. A second request with the same key and the same body returns the original response unchanged (with an Idempotent-Replayed: true header) instead of applying again. An agent that retries after a timeout never double-creates.
  • Conflict. The same key with a different body returns 409 (you reused a key for a new operation. Generate a fresh one).
  • In flight. If the first request is still running, a retry returns 409 (“in progress, retry shortly”).
  • Window. Keys are remembered for 24 hours, then expire. Scope is per user.
Without an Idempotency-Key, retries are not deduplicated, re-read with GET /api/v1/nodes or search and re-submit only what’s missing.

Validation

The API validates all mutations before applying them:
  • Label is required on all nodes
  • Parent must exist and be the correct type (need under goal, approach under need, etc.)
  • Fields must match node type, setting iteration on a goal or maturity on a task is rejected
  • Kano values: must-have, performance, delighter
  • Size values: skateboard, vespa, car, truck, antonov
  • Maturity values: mvp, releasable
  • Approach status values: development, validation, resolved, retired
Validation errors return { "success": false, "errors": ["..."] }.