Skip to main content
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 has assessment.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.