POST /v1/workspaces/{workspace_id}/ledger-understanding starts a job whose
result is a ledger_understanding. GET on the same path returns the
latest report.
Python: client.workspaces.start_ledger_understanding /
client.workspaces.get_ledger_understanding. TypeScript:
client.workspaces.startLedgerUnderstanding /
client.workspaces.getLedgerUnderstanding. MCP:
start_ledger_understanding / get_ledger_understanding. CLI:
ndi ledger-understanding start|get.
A sibling of journal-entry testing, not a
search. JET tests a criterion over the package; this reads the package
so later tests start from a settled census. The report names table roles,
integrity findings, open questions, and optional GL-parse counts. It does
not carry the SQL behind those figures — re-run a figure with
run-sql.
Without force, a request over an unchanged package republishes the
stored report instead of scanning again.
Package scope
Start the first run without source selection. An empty request discovers all sources the caller can access; optional path selectors bound discovery. Catalog recognition does not block this first attempt, and saved workspace scope settings are not implicit request selectors. If the persisted report hasassessment.status: needs_source_selection, review
its measured candidates. Request GET /v1/workspaces/{workspace_id}/ledger-understanding/sources
with review_reading_id and the report’s scope query parameters for a reading-bound
catalog. Only review_eligible primaries have accepted complete-population key evidence.
Submit review: {reading_id, scope} with the selection body below. A stale reading,
an unmeasured source or a primary without key evidence is refused. A native_contract
primary states its own journal structure: select it without review, and neither an
identity choice nor a structural nomination applies. Confirmation starts
a new understanding run using the returned selection; it never overrides technical checks.
With the LLM discovery engine, generic source nominations can use an ordered composite
account identity, such as ["company", "account_code"]. The source editor preserves these
components and lets reviewers add or remove columns. A structural selection accepts
structure_proposal.account as either one column name or an ordered list. Shared journal/account
qualifiers are allowed; account components must be distinct, scalar columns available on every
primary member. Confirmation records intent; the following measured run still validates the
package. Parsing preserves the whole account tuple, including its order. Scalar reference
accounts alone cannot establish CoA or TB matches for a composite identity.
For an existing explicit-selection integration, list GET /v1/workspaces/{workspace_id}/ledger-understanding/sources,
then post primary_source_id, explicit supporting_source_ids, and the returned revision as
expected_catalog_revision to POST /v1/workspaces/{workspace_id}/ledger-understanding/selections.
Use the returned selection_id when starting understanding and reading its report or when
starting either JET engine. Do not combine it with path selectors.
recommended_as_primary is a structural recommendation, not proof of ownership or fitness.
primary_eligible retains the same recommendation for older clients. An unrecognized primary
requires confirm_unrecognized_primary: true; the saved selection reports
primary_recommendation_overridden: true. The run measures that exact primary and publishes
missing key, amount or grain evidence for review. Confirmation does not waive technical checks.
Recommended alternate posting populations cannot be support, and changing or revoking selected
files still prevents a new run. The selection’s members and evidence remain immutable.
Send path_prefix (a workspace-relative folder), paths (exact source files),
or both in the start body. Both selectors intersect; folder boundaries are
respected. Include supporting headers, accounts and calendars in the package.
Selecting only some parts of a native partitioned dataset is refused.
Pass the same selectors as query parameters to read the report, reviews,
decisions and derived tables; repeat paths for each file. Report fallback and
human decisions never cross package scopes. Empty selectors use the workspace’s
ledger_understanding.package_scope; its empty default means the whole workspace.
An unscoped census with multiple journal populations asks for package selection
instead of choosing one. Changing the default scope does not migrate old answers.
Policy
create and update accept a ledger_understanding block
(trigger, gl_parsing, package_confirmation, package_scope, prepared_relationships).
package_confirmation applies to the llm engine. required (default) stops discovery at
source review and parses only a mapping a person confirmed. A run that settles other columns
than the confirmed ones, or runs over a model-confirmed selection, skips parsing and reports
parsing.confirmation_required. To parse, post a structure review of that reading with
previous_selection_id and the report’s settled_structure (edited as needed). The correction
keeps the previous selection’s other human decisions. automatic lets the model confirm the
package and chain its measured run.
Updating replaces the block whole. Automatic ingestion runs use package_scope;
the console’s Properties tab can configure its folder.
trigger is auto (default), always, or off. auto chains a run
after ingestion only when the workspace already holds a journal-line
table — a document corpus costs nothing. always chains after every
ingestion that landed files. off stops chaining; it never refuses an
explicit POST.
When ingestion does chain a run, IngestionResult.ledger_understanding_job_id
names it.
The report
GET returns the report itself. A succeeded job’s result.report is the
same object.
404 ledger_understanding_not_found means the stage has never produced a
report for the requested scope. 409 ledger_understanding_in_progress means a run is already in
flight — wait for that job rather than starting another.
parsing.attempted_candidates counts candidates actually evaluated.
candidate_coverage and population_capped_share are fractions of eligible
candidates (null when there are none). cap_reason_counts counts distinct
journals per stop reason, including population_cap; reasons may overlap.
Persisted sub-journal rows carry attempted and caps_hit.
Successful orchestration does not imply complete parsing. Limits are unchanged.
parsing.cap_profiles contains journal counts and median, p95 and maximum group
and posting counts for each stop reason. These aggregate diagnostics contain no
business values. Readiness reasons distinguish unattempted candidates from
attempted journals retained whole; both limitations can appear together.
For composite references, join_graph[].left_columns and right_columns state
the ordered key tuples, and left_tables lists the measured population members.
Missing-key and duplicate-reference counts are reported separately from membership
coverage. Complete membership does not make a duplicate reference safe to join.
conventions.auxiliary_columns retains non-exclusive SAP field references without
assigning generic users a preparer or approver role.
See Workspaces and Jobs.