dd_tools_api
See also: JSON API v1 · Tools reference · dispatch
The tools surface: list the tools a user may open, and invoke one tool method.
Registered actions (src/core/api/handlers/dd_tools_api.ts): user_tools, tool_request.
How to call
- POST JSON to
/api/v1/jsonwithdd_api: "dd_tools_api"andactionset to one of the two. - Both require a session and pass the dispatcher's CSRF gate.
- Envelope: v2 on both. Success is
{ ok: true, request_id, data, … }; a refusal is{ ok: false, request_id, error: { code, category, message, label_key, retryable } }with the registry's HTTP status. There is noresultkey — the v1{ result, msg, errors }shape was removed on 2026-08-16.msganderrorsstill exist as handler-owned extension keys on success for the few tools that emit them; they are never an error channel.
user_tools
Purpose
Return the tools the authenticated user is allowed to open — the toolbar's list.
Accepts
options.ar_requested_tools: array of string (optional) — filter the answer down to these tool names.
Returns
data is an array of tool descriptors, each { typo: "ddo", type: "tool", name, label, model, section_tipo, mode: "edit", icon, css: { url }, show_in_inspector, show_in_component, properties? }. properties is present only when the tool declares view / open_as properties.
A global admin receives every active tool; everyone else receives the set their profile grants plus the tools marked always-active.
Example request
{
"dd_api": "dd_tools_api",
"action": "user_tools",
"options": { "ar_requested_tools": ["tool_time_machine"] }
}
Example response (truncated)
{
"ok": true,
"request_id": "c0ffee60",
"data": [
{
"typo": "ddo",
"type": "tool",
"name": "tool_time_machine",
"label": "Time Machine",
"model": "tool_time_machine",
"section_tipo": "dd1324",
"mode": "edit",
"icon": "…",
"css": { "url": "…" },
"show_in_inspector": true,
"show_in_component": true
}
]
}
tool_request
Purpose
Invoke one method of one tool. source.model names the tool, source.action the method, and options carries the method arguments.
Accepts
source.model: string (required) — the tool name; must matchtool_[a-z0-9_]+.source.action: string (required) — the method, which must be in that tool's own action registry.options: object (optional) — the method arguments. A non-object is refused.
Gates, in order
optionsmust be an object.- The tool name must match the strict pattern — checked before any lookup.
- The tool must be active and authorized for the caller. For a non-admin an unknown tool is refused as not authorized rather than unknown, so the answer leaks no existence.
- Two reserved framework methods are served here for every tool that can run in the background: the job status poll and the caller's job list. They need no per-tool registration.
- The tool must have a loaded server module.
- The method must be in the tool's explicit action registry.
- The method's declared permission (a section-level or
(section_tipo, tipo)pair gate at its declared minimum level) must pass.
Returns
The tool's own envelope-v2 body: data is the method's payload, and a tool may add its own top-level extension keys. A tool that streams (for example an export writing NDJSON) answers with a stream instead of a buffered body; the response's Content-Type is the tool's declared stream type, defaulting to application/x-ndjson; charset=utf-8.
Errors
| code | when |
|---|---|
request.invalid_options |
options is present and is not an object. |
tool.invalid_name |
the name does not match tool_[a-z0-9_]+ — or, for a global admin, names no active tool. |
tool.not_authorized |
a non-admin naming a tool their profile does not grant. |
tool.no_server_module |
the tool has no loaded server module. |
tool.method_not_allowed |
the method is not in the tool's action registry. |
perm.denied |
the method's declared permission gate refused. |
Example request
{
"dd_api": "dd_tools_api",
"action": "tool_request",
"source": { "model": "tool_time_machine", "action": "apply_value" },
"options": { "section_tipo": "oh1", "section_id": 368, "tipo": "oh16" }
}
Note
tool_time_machine declares exactly two methods, apply_value (write, level ≥ 2 on the (section_tipo, tipo) pair plus the per-record projects scope) and bulk_revert_process (write, level ≥ 2 on the section). oh1 is the Oral History section of the monedaiberica install and oh16 its component_input_text "Title".
Example response
{
"ok": true,
"request_id": "c0ffee61",
"data": true
}