API: Read models
Capability state: every operation in this file is
staging-durable. Read models project durable membrane evidence into Koerper-safe summaries. They never expose raw database rows, raw connector payloads, raw biometric material, or cross-tenant graphs.
The read-models cluster is the surface a Koerper renders against when it needs list, detail, or dashboard views over durable membrane state. Each route reads through the membrane (no SQL, no DB driver, no cross-tenant access) and returns a projection that survives schema and atom-shape changes.
A Koerper that renders state should call these endpoints rather than
reconstructing projections from raw commit.recent results.
All read-model endpoints require the bearer token. They are all GET,
take no request body, and return outcome: "verified".
read.standing.active
Section titled “read.standing.active”Active standing grants for the authenticated tenant.
GET /v1/read/standing/activestate: staging-durablesdk_role: Koerper-safe active standing read modelrequest_record: (empty body)responses: standings | receiptResponse
Section titled “Response”{ "operation": "read.standing.active", "outcome": "verified", "body": { "standings": [ { "standing": "standing:anna_geschaeftsfuehrer_fixture", "actor": "human_person:anna", "company": "company_geist:rheinwerk_calibration", "office": "geschaeftsfuehrer", "powers": ["..."], "status": "active", "source": "fixture_world | local_overlay | remote_durable", "standing_created_by_human_presence": false, "production_admission": false } ] }, "receipt": {...}}standing_created_by_human_presence is always false. HumanAuth
presence does not create standing.
SDK example
Section titled “SDK example”const standings = await client.readActiveStandings({ tenant });read.mandates.active
Section titled “read.mandates.active”Active mandate records for the authenticated tenant.
GET /v1/read/mandates/activestate: staging-durablesdk_role: Koerper-safe active mandate read modelrequest_record: (empty body)responses: mandates | receiptResponse
Section titled “Response”{ "operation": "read.mandates.active", "outcome": "verified", "body": { "mandates": [ { "mandate": "mandate:...", "principal": "...", "delegate": "...", "scope": ["..."], "status": "active", "production_admission": false } ] }, "receipt": {...}}Mandate state is always separate from session identity; a Koerper must not derive mandate from a bearer session.
SDK example
Section titled “SDK example”const mandates = await client.readActiveMandates({ tenant });read.economy.periodCloseReadiness
Section titled “read.economy.periodCloseReadiness”Derived period-close readiness from durable obligations and closure surfaces. The read model is the membrane-safe equivalent of the “can I close this period?” question a back-office UI would otherwise need to answer client-side.
GET /v1/read/economy/period-close-readinessstate: staging-durablesdk_role: derived period-close readiness from durable obligations and closure surfacesrequest_record: (empty body)responses: readiness | receiptResponse
Section titled “Response”{ "operation": "read.economy.periodCloseReadiness", "outcome": "verified", "body": { "tenant": "tenant_node:rheinwerk_calibration", "ready": false, "open_obligations": [ { "obligation": "obligation:...", "invoice": "invoice:...", "amount_cents": 11900, "currency": "EUR", "source": "remote_durable", "commitment": "sha256:..." } ], "open_closure_surfaces": [ { "closure_surface": "closure_surface:...", "kind": "receivable", "status": "active", "required_evidence": ["payment_observation"], "source": "remote_durable", "commitment": "sha256:..." } ], "period_closes": ["period_close:..."], "required_resolution_evidence": [ "payment_observation", "steuerberater_review", "closure_clearance" ], "raw_db_exposed": false, "raw_connector_payload_exposed": false, "production_admission": false }, "receipt": {...}}ready is true only when both open_obligations and
open_closure_surfaces are empty. A period-close UI should block the
close button until ready: true.
SDK example
Section titled “SDK example”const readiness = await client.readPeriodCloseReadiness({ tenant: "tenant_node:rheinwerk_calibration", period: "2026-04",});read.connectors.evidenceGaps
Section titled “read.connectors.evidenceGaps”Connector evidence gap summary. Lists the required evidence kinds for the tenant alongside which kinds are present and which are missing, without exposing raw connector payloads.
GET /v1/read/connectors/evidence-gapsstate: staging-durablesdk_role: connector evidence gap summary without raw connector payload exposurerequest_record: (empty body)responses: gaps | receiptResponse
Section titled “Response”{ "operation": "read.connectors.evidenceGaps", "outcome": "verified", "body": { "tenant": "tenant_node:rheinwerk_calibration", "required": [ { "kind": "invoice_payload", "present": true, "evidence": ["evidence_bundle:..."] }, { "kind": "steuerberater_review", "present": false, "evidence": [] } ], "gaps": [ { "kind": "steuerberater_review", "present": false } ], "evidence_kinds": { "invoice_payload": ["evidence_bundle:..."] }, "raw_connector_payload_exposed": false, "raw_db_exposed": false, "production_admission": false }, "receipt": {...}}The required-evidence list (currently invoice_payload,
payment_observation, steuerberater_review, closure_clearance) is
fixed in the fixture runtime; production scope will derive it from the
admitted authority package.
SDK example
Section titled “SDK example”const gaps = await client.readConnectorEvidenceGaps({ tenant });read.proofs.history
Section titled “read.proofs.history”Proof bundle manifest history for the authenticated tenant. Returns manifest commitments and audit-kernel summaries; raw DB rows, raw connector payloads, and biometric material are never disclosed.
GET /v1/read/proofs/historystate: staging-durablesdk_role: proof bundle manifest history without raw DB, connector payload, or biometric disclosurerequest_record: (empty body)responses: proof_history | receiptResponse
Section titled “Response”{ "operation": "read.proofs.history", "outcome": "verified", "body": { "tenant": "tenant_node:rheinwerk_calibration", "manifests": [ { "bundle": "proof_bundle:...", "manifest_commitment": "sha256:...", "redaction_verified": true, "audit_kernel_present": true, "production_admission": false } ] }, "receipt": {...}}SDK example
Section titled “SDK example”const history = await client.readProofHistory({ tenant });What read models do not do
Section titled “What read models do not do”- They do not expose raw DB rows.
- They do not expose raw connector payloads.
- They do not expose biometric material or credential bytes.
- They do not return cross-tenant data; the bearer’s tenant scope bounds every projection.
- They do not flip production admission. Every read model returns
production_admission: falsetoday.
Where to read next
Section titled “Where to read next”- SDK: TypeScript —
readActiveStandings,readActiveMandates,readPeriodCloseReadiness,readConnectorEvidenceGaps,readProofHistory. - Reference: capability state
- Guide: building a Koerper —
pattern 9 explains when to prefer read models over
commit.recent.