dd_ts_api
See also: JSON API v1 · dd_core_api · dispatch
Thesaurus / hierarchical-tree API: read a node and its children, add a child, move a node to another parent, and reorder siblings.
Registered actions (src/core/api/handlers/dd_ts_api.ts): get_node_data, get_children_data, add_child, update_parent_data, save_order. The handlers are thin wrappers over src/core/ts_object/ts_api.ts, which owns the permission gates and every refusal.
How to call
- POST JSON to
/api/v1/jsonwithdd_api: "dd_ts_api"andactionset to one of the five. - Every action requires a session and passes the dispatcher's CSRF gate.
Common contract
section_idis an int. Everysection_idin this API's body addresses a tree node, i.e. a matrix record, and is canonicalized at one door. A legacy numeric string still coerces (counted, deprecated); anything that is not an address — a synthetic token, a zero-padded external id — refuses assection_id.not_an_address.- Permission is the section grant on
source.section_tipo: reads need level ≥ 1, writes level ≥ 2. - Envelope v2. Success is
{ ok: true, request_id, data, … }; the payload the tree client consumes isdata. A refusal is{ ok: false, request_id, error: { code, category, message, label_key, retryable } }carrying the registry's HTTP status — a failure is no longer an HTTP-200 body withresult: false, and there is noresultkey (the v1{ result, msg, errors }shape was removed on 2026-08-16). - Non-fatal findings ride as the top-level
errorsextension key (an incompletesection_map, for instance). An empty set emits no key at all. A warning never becomes a refusal:add_childstill creates the node.
Errors
| code | when |
|---|---|
request.invalid_source |
the RQO carries no source. |
section_id.not_an_address |
a section_id in the body is not a record address. |
perm.denied |
section permission below the action's level. |
tree.parent_unresolved |
the section has no component_relation_parent to hang the node from. |
tree.cycle |
update_parent_data would make a node its own ancestor (self-target included). |
tree.node_write_failed |
the mutation's transaction rolled back; nothing was written. |
request.invalid_options |
save_order without parent_section_tipo / parent_section_id. |
resource.conflict |
save_order on a section whose section_map declares no order key — there is no column to write the sequence into. |
Note
The examples use the monedaiberica install: es1 is a tree section (a virtual section of the core Thesaurus section hierarchy20) and hierarchy36 is its component_relation_parent ("Dependent of"). Another install's tree sections differ; the core hierarchy* tipos do not.
get_node_data
Purpose
Return the parsed node data for one tree node.
Accepts
source: object (required)section_tipo: string — the tree section.section_id: int (optional) — the node.children_tipo: string (optional) — the relation component the node hangs from.area_model: string (optional, default"area_thesaurus").
options.thesaurus_view_mode: string (optional) —defaultormodel.
Returns
data is the parsed node-data object built by the node builder in src/core/ts_object/, or null when nothing resolves.
Example request
{
"dd_api": "dd_ts_api",
"action": "get_node_data",
"source": { "section_tipo": "es1", "section_id": 13919 },
"options": {}
}
Example response
{
"ok": true,
"request_id": "c0ffee50",
"data": { "section_tipo": "es1", "section_id": 13919, "label": "…", "ar_children": [] }
}
get_children_data
Purpose
List the children of a node — or parse a pre-built list of child locators.
Accepts
source: object (required)section_tipo: string,section_id: int (optional) — the parent node.children_tipo: string (optional) — the child relation component. Withsection_idand no explicitchildren, this is the standard resolution path (default limit 300).children: array of locator objects (optional) — a pre-built child list to parse instead.model: string (optional, default"area_thesaurus") — the area model.
options.pagination: object (optional) —limit,offset,total.options.thesaurus_view_mode: string (optional).
Returns
data is { ar_children_data: [ … ], pagination }.
Example request
{
"dd_api": "dd_ts_api",
"action": "get_children_data",
"source": { "section_tipo": "es1", "section_id": 13919, "children_tipo": "hierarchy36" },
"options": { "pagination": { "limit": 50, "offset": 0 } }
}
Example response
{
"ok": true,
"request_id": "c0ffee51",
"data": {
"ar_children_data": [],
"pagination": { "limit": 50, "offset": 0, "total": 0 }
}
}
add_child
Purpose
Create a new node under a parent.
Accepts
source: object (required)section_tipo: string (required) — the tree section the child is created in.section_id: int (required) — the parent node.
Returns
data is the new node's section_id (int). Validation runs before any write, so there is no orphan window; the node lock and the whole creation ride one transaction.
An incomplete section_map (a missing thesaurus.is_descriptor / is_indexable) is non-fatal: the child is created and the finding travels back in the errors extension key.
Example request
{
"dd_api": "dd_ts_api",
"action": "add_child",
"source": { "section_tipo": "es1", "section_id": 13919 }
}
Example response
{
"ok": true,
"request_id": "c0ffee52",
"data": 69150
}
update_parent_data
Purpose
Move a node from one parent to another.
Accepts
source: object (required) —section_tipo,section_id,old_parent_section_tipo,old_parent_section_id,new_parent_section_tipo,new_parent_section_id. Every id is an int.
Returns
data is true.
Warning
A cycle is refused before any mutation: moving a node onto itself, or onto one of its own descendants, answers tree.cycle and nothing is written.
Example request
{
"dd_api": "dd_ts_api",
"action": "update_parent_data",
"source": {
"section_tipo": "es1",
"section_id": 52661,
"old_parent_section_tipo": "es1",
"old_parent_section_id": 13919,
"new_parent_section_tipo": "es1",
"new_parent_section_id": 13920
}
}
Example response
{
"ok": true,
"request_id": "c0ffee53",
"data": true
}
save_order
Purpose
Write the sibling order of a parent's children.
Accepts
source: object (required)section_tipo: string (required) — the children's section.ar_locators: array (required) — the siblings in their new order, each{ section_tipo, section_id }. The order value is the position in this array; there is noorderkey on a locator.parent_section_tipo: string (required) andparent_section_id: int (required) — the parent whose children are being ordered. Both are mandatory: without them the write has no node to lock and no relation to resolve.
Returns
data is the list of changes actually written, each { value, locator } — a sibling already at its target position is skipped. The new sequence is mirrored into the ontology's order_number afterwards.
Example request
{
"dd_api": "dd_ts_api",
"action": "save_order",
"source": {
"section_tipo": "es1",
"parent_section_tipo": "es1",
"parent_section_id": 13919,
"ar_locators": [
{ "section_tipo": "es1", "section_id": 52663 },
{ "section_tipo": "es1", "section_id": 52661 }
]
}
}
Example response
{
"ok": true,
"request_id": "c0ffee54",
"data": [
{ "value": 1, "locator": { "section_tipo": "es1", "section_id": 52663 } },
{ "value": 2, "locator": { "section_tipo": "es1", "section_id": 52661 } }
]
}