Skip to main content

Audit Trail Rebuild — New Endpoints

Reference for the Phase 1+2+3 Audit Trail rebuild API surface (2026-05). All endpoints additive; existing /api/audit/* and /api/hash-chain/* endpoints remain unchanged.

Authenticated endpoints (admin/owner)

Chain integrity

MethodPathDescription
GET/api/v1/audit-integrity/snapshot?namespace=decision|operations|allPer-org chain integrity snapshot. Returns chainStatus + heartbeat history + OTS status + Tessera status. Accepts optional namespace filter (per ADR-AT-05 two-chain architecture).
GET/api/v1/audit-integrity/heartbeat/history?limit=NPer-org heartbeat verification history.

Notary attestation (Governance+/Enterprise/Custom)

MethodPathDescription
GET/api/v1/notary-attestationList notary attestations for the org.
GET/api/v1/notary-attestation/:idGet specific attestation metadata.
GET/api/v1/notary-attestation/:id/pdfDownload signed attestation PDF. Response carries Cache-Control: no-store + X-Content-Type-Options: nosniff.
POST/api/v1/notary-attestation/generateOn-demand attestation generation (admin/owner).

Erasure (GDPR Art. 17, ADR-AT-04)

GDPR Art. 17 erasure is a mandatory data-subject right; these endpoints are available on every plan tier (no requireFeature gate). All four endpoints require the admin or owner role — erasure-ledger metadata is not readable by every org member.

MethodPathDescription
POST/api/v1/erasure/acknowledge-and-executeTwo-step protocol: customer pre-flight acknowledgment + payload nullification + erasure-ledger append. Body: { traceIds, acknowledgment, reason? }. Batch capped at 5 000 trace IDs per call (ERASURE_BATCH_TOO_LARGE 400 if exceeded; configurable via ERASURE_BATCH_MAX). Each traceId must be a non-empty string ≤200 chars.
GET/api/v1/erasure/verifyFull erasure-ledger chain verification.
GET/api/v1/erasure/statusErasure ledger summary stats.
GET/api/v1/erasure/trace/:traceIdLookup erasure entry for a specific trace.

Customer-portable bundle export

MethodPathDescription
POST/api/v1/audit-bundle/generateGenerate signed .tar.gz bundle for offline regulator verification. Body: { periodStart, periodEnd }. Admin/owner only. The bundle is built in-memory; periods that contain more than 500 000 chain entries return BUNDLE_PERIOD_TOO_LARGE (HTTP 413) — split the period or queue the streaming generator (Phase 3.1). Cap configurable via AUDIT_BUNDLE_MAX_ROWS.
GET/api/v1/audit-bundle/:bundleHash/downloadDownload generated bundle. Cardinal Rule #1 enforced (cross-org access rejected with 403). Response carries Cache-Control: no-store + X-Content-Type-Options: nosniff — signed compliance artefacts must not persist in browser disk cache or HTTPS-inspecting proxies.

Insurance feed (Custom tier)

MethodPathDescription
GET/api/v1/insurance-feedList monthly insurance feed records.
GET/api/v1/insurance-feed/:idGet specific feed metadata.

Bias-stratified metrics

cohortField must be one of the allow-listed dimensional attributes safe to surface as a fairness-cohort label (Cardinal Rule #4 — prevents extracting arbitrary DecisionTrace payload fields into the cohort key):

  • agentId (default)
  • outputDecision.decisionType
  • outputDecision.action
  • metadata.region
  • metadata.locale
  • metadata.environment

Anything else returns INVALID_COHORT_FIELD (HTTP 400).

MethodPathDescription
GET/api/v1/bias-metrics?cohortField=agentId&from=...&to=...Per-cohort chain integrity metrics with fairness alerts (>5pp deviation).

Witness admin (Adjudon admin/owner only)

MethodPathDescription
POST/api/v1/witness-admin/registerRegister external EU-domiciled witness. Returns {witness, sharedSecret} — sharedSecret shown ONCE, transmit out-of-band.
GET/api/v1/witness-adminList registered witnesses.
DELETE/api/v1/witness-admin/:idDeactivate witness.

Public endpoints (Cardinal Rule #2 documented exceptions)

All public CT endpoints are rate-limited at 1 000 requests per IP per 15 minutes (apiLimiter). Public per RFC 6962 model — proof generation is computationally non-trivial, so the rate-limit prevents scraping + DoS without blocking legitimate auditors or monitors.

merkleRoot, fromSTHRoot, toSTHRoot MUST match /^[0-9a-f]{64}$/ (64-char lowercase hex). Length-only validation was tightened in 2026-05.

Witness STH (CT pattern)

These endpoints proxy to the Adjudon Tessera Personality service running at tessera.adjudon.com (Frankfurt eu-central-1, Ed25519-signed c2sp.org/tlog-checkpoint format). Public verifier key: /keys/tessera-public.txt. The underlying log can also be queried directly via the standard tlog-tiles paths at https://tessera.adjudon.com/{decision|operations}/checkpoint, /tile/<L>/<N>, /tile/entries/<N> for any compatible client tooling.

MethodPathDescription
GET/api/audit-witness/sth?namespace=decision|operations|allLatest Signed Tree Head for the chain namespace.
GET/api/audit-witness/inclusion-proof?namespace=...&merkleRoot=<hex>Merkle inclusion proof for a given root.
GET/api/audit-witness/consistency-proof?namespace=...&fromSTHRoot=<hex>&toSTHRoot=<hex>Consistency proof between two STHs.
GET/api/audit-witness/statusWitness service status.

Witness gossip (HMAC-authenticated)

MethodPathDescription
POST/api/audit-witness/gossip/observeExternal witness POSTs STH observation. Headers: X-Adjudon-Witness-Secret + hmacSignature over canonical JSON payload. Replay window: payload MUST include timestamp (ISO-8601 or epoch ms) within ±10 minutes of server time; outside the window returns 401 with sentinel "outside acceptable replay window". Configurable via WITNESS_GOSSIP_REPLAY_WINDOW_MS.
GET/api/audit-witness/gossip/consortiumPublic consortium status (active witnesses, mismatches).

Insurance partner-pull (HMAC-authenticated)

MethodPathDescription
POST/api/v1/insurance-feed/partner-pullInsurance underwriter pulls signed feed. Headers: X-Adjudon-Partner-Name + X-Adjudon-Partner-Secret + hmacSignature. Replay window: body payload.timestamp (ISO-8601 or epoch ms) MUST be within ±10 minutes of server time, else PARTNER_REPLAY_WINDOW (HTTP 401). Configurable via PARTNER_PULL_REPLAY_WINDOW_MS. The shared-secret comparison and HMAC verification both use crypto.timingSafeEqual (constant-time).

Response envelope

All endpoints follow the standard Adjudon envelope:

{ "success": true, "data": { /* ... */ } }
{ "success": false, "error": "human-readable", "code": "REGISTERED_CODE" }

Error codes from this rebuild are registered in backend/utils/errorCodes.js (57 new codes including the 2026-05 hardening pass: BUNDLE_PERIOD_TOO_LARGE, ERASURE_BATCH_TOO_LARGE, INVALID_TIMESTAMP, PARTNER_REPLAY_WINDOW). SDKs can react programmatically to specific codes (see Error Codes).

Operational notes

qSeal failure mode (Enterprise + Custom tier)

When AUDIT_TRAIL_QSEAL_ENABLED=true and the configured D-Trust qSeal endpoint is unreachable, the qSeal scheduler does not fall back to a mock seal. The eIDAS Art. 35 qSeal that establishes German §371a Abs. 3 statutory presumption is either real or absent — a mock seal that looks real on the dashboard but offers zero legal effect would silently downgrade the customer's compliance posture.

The chain itself does not break. Per ADR-AT-02, the qSeal is layer 4 (additive German legal-presumption), while Merkle anchor (layer 1) + OpenTimestamps (layer 2) + Tessera witness (layer 3) carry the integrity baseline. A single-day D-Trust outage records "qSeal pending" for that day and is retried by the scheduler on the next run; the chain-integrity dashboard surfaces the degraded state explicitly.

Smoke-heartbeat verification (chains > 1 000 entries)

chainHeartbeat.smokeVerifyOrg verifies the last SMOKE_TAIL_SIZE (default 1 000) chain entries every 5 minutes. The range-query path through hashChainService.verifyChain looks up the predecessor's chainHash via Mongo to seed the bootstrap — a missing predecessor correctly reports a chain break, not a false alarm. Customers with chains larger than SMOKE_TAIL_SIZE get the same correctness guarantee as a full nightly replay, with bounded latency per heartbeat.

Methodology

Full specification: github.com/adjudon/audit-trail-methodology (version adjudon-audit-trail-methodology/v1.0).

Open-source verifier: github.com/adjudon/audit-trail-verifier (Rust, Apache 2.0).

External witness reference monitor: github.com/adjudon/witness-reference-monitor (Go, Apache 2.0).