Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.ntropii.com/llms.txt

Use this file to discover all available pages before exploring further.

Two direct HTTP endpoints for subledger row mutations. They exist for ops tooling and legacy callers; interactive Tenant UI edits for HITL tables should go through workflow signals (POST /tasks/:taskId/row-action) so Temporal stays the source of truth — see UI and Temporal signals. :ledger is the registered subledger name (expenses, journal_proposals, runbook-owned types). :rowId is a UUID — the controller validates this with a regex check before dispatching.

Reject a row

POST /v1/subledgers/:ledger/:rowId/reject
Apply the per-ledger reject rule. For expenses, only rows in NEEDS_ATTENTION are rejectable via this endpoint (see expenses_mutations.can_reject). Other types may carry their own reject rules. Path params
ParamNotes
ledgerSubledger name (e.g. expenses).
rowIdSubledger row UUID.
Response — service-level RejectResult:
{ "status": "OK", "rowId": "…", "newStatus": "REJECTED" }

Errors

StatusWhen
400 Bad RequestrowId not a UUID, or row’s current status doesn’t allow reject (response carries currentStatus).
404 Not FoundRow not found in :ledger.

Update one cell

PATCH /v1/subledgers/:ledger/:rowId
Update one editable cell on a row. The set of editable fields is per-ledger — for expenses, see EditableExpenseField. Non-editable fields return 400 INVALID_FIELD. BodyUpdateSubledgerCellDto:
{
  "field": "amount_gross",
  "value": "12.50"
}
FieldTypeRequiredNotes
fieldstringYesColumn key. Per-ledger allow-list; coercion happens in the per-ledger adapter.
valueunknownYesNew scalar / null. Intentionally permissive — per-ledger adapters validate / coerce.
Response — service-level UpdateResult:
{ "status": "OK", "rowId": "…", "field": "amount_gross", "value": "12.50" }

Errors

StatusWhen
400 Bad RequestrowId not a UUID; field not editable on this ledger; value coercion failed; row’s current status doesn’t allow edits (response carries currentStatus).
404 Not FoundRow not found.

When to use these vs /tasks/:id/row-action

Use this endpointUse POST /tasks/:taskId/row-action
Ops tooling fixing a stuck row outside a workflow runTenant UI inline edit / reject during a HITL review step
Migration / backfill scriptsAnything that needs Temporal to be the system of record
One-off forensic correctionAll standard runbook flows
Direct mutations bypass the workflow — replay / idempotency / step lifecycle don’t see them. Prefer the row-action signal whenever a workflow is alive for the row.

SDK Subledgers

Row base, SubledgerStatus lifecycle, mutation helpers.

Tasks — row-action

The signal-based path used by the Tenant UI.