Document API is in alpha and subject to breaking changes while the contract and adapters continue to evolve. The current API is not yet comprehensive, and more commands and namespaces are being added on an ongoing basis.
Why use Document API
- Build automations without editor-specific code.
- Work with predictable inputs and outputs defined per operation.
- Check capabilities up front and branch safely when features are unavailable.
Node addressing
Every block in a document has anodeId — a string that uniquely identifies it.
For mutation targeting and getNode(...), use NodeAddress:
find(...) returns NodeAddress values (for example kind: "block"). For text selectors, query.match(...) returns deterministic mutation-ready data: item.target as a canonical SelectionTarget, item.handle.ref as a reusable resolved handle, and item.address as the matching NodeAddress.
Mutation targeting
Core selection mutations such asreplace, delete, format.*, and selection-based mutation plans use SelectionTarget or a mutation-ready ref.
item.target from query.match(...) for single direct operations:
item.handle.ref when you want multiple operations or a mutation plan to reuse the same resolved range. When you need to construct a selection from explicit anchors, call editor.doc.ranges.resolve(...) and use its target or handle.ref.
Stable IDs across loads
For DOCX documents,nodeId is derived from the file’s native w14:paraId attribute. In practice, this is usually stable when you reopen the same unchanged DOCX across separate editor sessions, machines, or headless CLI pipelines.
For nodes created at runtime (not imported from DOCX), nodeId falls back to sdBlockId, a UUID generated when the editor opens. This fallback is volatile and changes on every load.
| ID source | Stable across loads? | When used |
|---|---|---|
paraId (from DOCX) | Best effort (usually stable for unchanged DOCX blocks) | Paragraphs and table rows imported from DOCX |
sdBlockId (runtime) | No (session-scoped) | Nodes created programmatically before first export |

