Skip to content

Guide: connector evidence

Status: fixture-rehearsed. Connector ingest accepts fixture witnesses only (request.fixture: true is required, otherwise refused with connector_fixture_only). Real connector integrations to bank / DATEV / shop / payment systems do not exist yet (see 022 gap report item 11).

This guide walks how to feed an external system’s witnessed fact into a Gestalt Geist as redacted, content-hashed evidence.

A connector is the bridge between an external system (a bank feed, a DATEV export, a Lexware integration, a shop system, a payment processor) and the Geist. Connectors do not write company truth. They produce connector witnesses — redacted, signed, content-addressed records of what the external system observed.

The pipeline:

external system
|
| raw payload
v
connector redacts, hashes, signs
|
| observed_input
v
transform deterministic shaping
|
| evidence_bundle
v
membrane crossing POST /v1/evidence/connectors/ingest
|
v
Geist evidence is now citable by atoms

Raw payloads are never exposed through the membrane. The membrane sees only the redacted observed input, the transform receipt, and the resulting evidence bundle.

Step 1 — ingest connector evidence (fixture)

Section titled “Step 1 — ingest connector evidence (fixture)”
import { GestaltClient } from "@gestalt/sdk";
const client = new GestaltClient({
baseUrl: "http://127.0.0.1:3011",
token: "fixture-session-token",
});
const ingested = await client.connectorEvidenceIngest({
tenant: "tenant_node:rheinwerk_calibration",
subject: "company_geist:rheinwerk_calibration",
kind: "invoice",
idempotency_key: "ingest-2026-04-001",
source_system: "fixture_connector",
source_label: "fixture",
source_hash: "sha256:fixture_invoice",
transform_hash: "sha256:fixture_transform",
raw_kind: "fixture_json",
claims: ["invoice_payload"],
amount_cents: 11900,
currency: "EUR",
fixture: true,
});
console.log(ingested.outcome); // "admitted"
console.log(ingested.body);
// {
// connectorWitness: "connector_witness:fixture_sdk",
// observedInput: "observed_input:fixture_sdk",
// transformReceipt: "transform_receipt:fixture_sdk",
// evidenceBundle: "evidence_bundle:fixture_sdk",
// rawConnectorPayloadExposed: false,
// evidenceCreatesAuthority: false
// }

evidenceCreatesAuthority: false is asserted explicitly. Evidence backs claims; it does not create authority. Authority comes from Pendulums and packages.

The kind field categorizes what the witnessed evidence is about:

invoice an invoice document was observed
payment a payment movement was observed
bookkeeping a bookkeeping fact was observed
advisor an advisor decision was observed
registry a registry record was observed
human_presence a human presence event was observed
identity_fallback an identity fallback signal was observed
closure_clearance clearance for period close was observed

These align with the operations that consume them: economy.invoice cites claims: ["invoice_payload"], economy.paymentObservation cites claims: ["payment_observation"], economy.periodClose cites evidence_bundle:closure_clearance, etc.

If fixture: true is not set, the membrane refuses. There is no production connector path today.

If you set stale: true, the membrane refuses. Stale evidence is not admitted.

If you set outside_tenant: true, the membrane refuses. Connector witnesses must come from the tenant’s own connectors.

Repeating the same idempotency_key for a different payload is refused. Repeats with identical payload are accepted (and deduped).

human_presence_creates_standing_refused / identity_fallback_creates_standing_refused

Section titled “human_presence_creates_standing_refused / identity_fallback_creates_standing_refused”

The membrane explicitly refuses any attempt to use connector evidence to create standing. Standing is its own first-class object.

The evidence bundle ref is now usable in an economy.* operation (or any operation that cites evidence):

const invoice = await client.economicInvoice({
tenant: "tenant_node:rheinwerk_calibration",
amount_cents: 11900,
currency: "EUR",
evidence: [ingested.body.evidenceBundle],
});
const status = await client.connectorEvidenceStatus();
console.log(status.body.rawConnectorPayloadExposed); // false
console.log(status.body.rawDbExposed); // false
console.log(status.body.connectorWitnesses); // count
console.log(status.body.observedInputs); // count
console.log(status.body.transformReceipts); // count
console.log(status.body.evidenceBundles); // count

Counts and refs only. Raw payload bytes are never returned.

You can build a connector as a process that:

  1. Subscribes to an external feed (bank webhook, DATEV polling, shop system events).
  2. Redacts the raw payload to remove personal data, secrets, and anything not necessary for the witnessed claim.
  3. Computes content hashes:
    • source_hash over the redacted source bytes,
    • transform_hash over the deterministic shaping function.
  4. Posts to /v1/evidence/connectors/ingest with fixture: true.
  5. Stores the returned evidence bundle ref alongside any downstream operation it triggers.

For the production path (when it lands):

  • fixture: true will not be required.
  • The connector will need to attest its own identity (a connector Pendulum).
  • The transform function will need to be content-addressed and reproducible.
  • The bridge between the external system’s authenticity (e.g. the bank’s signed CAMT.053 message) and the connector’s witness will need its own discipline.
  • Do not write company truth. Connector witnesses back claims; atoms make claims.
  • Do not create authority. Authority comes from Pendulums, packages, capabilities. Evidence is consumed.
  • Do not create standing. Even an identity-fallback witness cannot create standing.
  • Do not expose raw payloads. The membrane refuses to surface raw connector payloads.
  • Sending raw bank statements as the connector payload. Redact first.
  • Using idempotency_key: Date.now(). That makes idempotency meaningless. Use a stable key derived from the witnessed fact.
  • Treating evidence_bundle:fixture_sdk as a real bundle. It is the fixture canned response. Inspect the actual ref returned by your call.
  • Skipping the redaction pipeline. The raw-payload-not-exposed invariant is structural; do not weaken it client-side either.