Skip to main content
The audit-trail record endpoints are mounted under /record/*, with the versioned audit-log read at /v1/record/audit-log. The base URL is https://api.visiqlabs.com. These endpoints manage the record surface behind the Audit Trail: every governance decision emits a record envelope, envelopes are grouped into records, and records carry events, artifacts, and attestations. For the cryptographic verification of a single envelope, see Decision Receipts.

Authentication

All endpoints require a Bearer credential: Authorization: Bearer <key>. Requests without a valid credential receive 401 Unauthorized. Two credential audiences exist:
  • Harness keys — the operational credential your SDK or harness runs with. On this surface a harness key covers exactly POST /record/envelopes (the envelope ingestion the record SDK calls); every other endpoint here is management-only and returns 403 {"error": "harness_key_not_permitted"} for a harness key.
  • Management keys: general automation credentials governed by explicit permission grants. They can call every endpoint on this page. Mint one under Settings → API Keys and grant it the permissions listed for each endpoint below; see Platform Automation. The dashboard calls the same endpoints with your session.
Each endpoint below names the exact permission it requires. Permission-gated management keys must carry that permission; scope-gated routes additionally check the coarse record:read / record:write scope, and full_access satisfies everything.

Rate limiting

Every API-key request passes a per-key sliding-window rate limit (default 600 requests per 60 seconds). Responses carry X-RateLimit-Limit and X-RateLimit-Remaining headers; exceeding the window returns 429 with a Retry-After header and body {"error": "rate_limited", "detail": "API key rate limit exceeded.", "retryAfter": <seconds>}.

List responses

Every list endpoint on this page returns the same envelope:
The record list envelope names the page size field limit (echoing the request parameter), where the action and retrieval list endpoints name it pageSize. The values are the same; only the key differs.
Pagination is controlled by page (default 1) and limit (default 50, max 200) query parameters.

Ingestion


POST /record/envelopes

Ingest a record envelope. The platform upserts the parent record by correlationId (creating it on first sight, appending to it thereafter), appends the event with the next sequence number and a SHA-256 content hash, and inserts any attached artifacts and attestations — atomically. Permission: record_records:create · Scope: record:write Request body:
Response (201):
Status codes: 201 Created, 400 Bad Request (invalid JSON or body), 401 Unauthorized, 403 Forbidden (harness-key on a management route, or tenantId does not match the authenticated vendor), 500 Internal Server Error

Records

Management endpoints — a harness key receives 403 harness_key_not_permitted here. Each read is vendor-scoped; a record that isn’t yours is 404.

GET /record/records

List records, newest first. Permission: record_records:view Query parameters: Response:
Status codes: 200 OK, 400 Bad Request (invalid query), 401 Unauthorized, 500 Internal Server Error

GET /record/records/:id

Get a single record by UUID. Permission: record_records:view Path parameter: :id — the record UUID (must be a valid UUID, else 400) Response: the record object (as in the list response). Status codes: 200 OK, 400 Bad Request (invalid record ID), 401 Unauthorized, 404 Not Found, 500 Internal Server Error

PATCH /record/records/:id/finalize

Finalize a record — seal it so no further events are expected. Idempotent: finalizing an already-finalized record returns it unchanged. Permission: record_records:finalize Path parameter: :id — the record UUID Response: the record object with status: "finalized" and a populated finalized_at. Status codes: 200 OK, 400 Bad Request (invalid record ID), 401 Unauthorized, 404 Not Found, 409 Conflict (the record is superseded and cannot be finalized), 500 Internal Server Error

GET /record/records/:id/events

List the events on a record, in sequence order. Permission: record_records:view Query parameters: page (default 1), limit (default 50, max 200) Response:
Status codes: 200 OK, 400 Bad Request, 401 Unauthorized, 404 Not Found (unknown or non-owned record), 500 Internal Server Error

GET /record/records/:id/artifacts

List the artifacts attached to a record. Permission: record_records:view Query parameters: page (default 1), limit (default 50, max 200) Response: the standard list envelope whose items carry id, artifact_type, mime_type, storage_ref, content_hash, metadata_json, and created_at. Status codes: 200 OK, 400 Bad Request, 401 Unauthorized, 404 Not Found, 500 Internal Server Error

GET /record/records/:id/attestations

List the attestations attached to a record. Permission: record_records:view Query parameters: page (default 1), limit (default 50, max 200) Response: the standard list envelope whose items carry id, attestation_type, issuer_type, issuer_id, statement_json, hash, signature, and created_at. Status codes: 200 OK, 400 Bad Request, 401 Unauthorized, 404 Not Found, 500 Internal Server Error

Verification


GET /record/envelopes/:id/verify

Run a live, independent verification of one envelope’s full attestation chain — integrity, Ed25519 leaf signature, Merkle inclusion, the AWS-KMS root signature (with a live KMS round-trip), and the RFC 3161 timestamp. The response carries a per-check result and evidence; Audit Trail documents the six checks. Permission: record_records:view · Scope: record:read Path parameter: :id — the envelope UUID (vendor-scoped; an envelope that isn’t yours is 404, indistinguishable from not-found to prevent enumeration) Status codes: 200 OK, 400 Bad Request (invalid record ID), 401 Unauthorized, 404 Not Found, 500 Internal Server Error

Checkpoints

The public transparency-log checkpoints — the signed, hash-chained Merkle roots. These are tenant-neutral: a checkpoint exposes only roots, signatures, counts, timestamp, and witness status, never any per-tenant data.

GET /record/checkpoints/:seq

Fetch one checkpoint by its 1-based batch sequence number. Permission: record_records:view · Scope: record:read Path parameter: :seq — the checkpoint’s batch_seq (integer ≥ 1) Query parameters: domainproduction (default) or sandbox, selecting the transparency chain Response: the tenant-free checkpoint view (roots, signatures, counts, timestamp-authority time, and the derived external-witness status). Status codes: 200 OK, 400 Bad Request (invalid sequence), 401 Unauthorized, 404 Not Found (unknown sequence), 500 Internal Server Error
The sibling GET /record/checkpoints lists checkpoints newest-first, seq-cursor paginated via before and limit (default 50, max 200), under the same permission and scope — walk it to audit the published roots and detect a split view or rewrite.

Audit Log


GET /v1/record/audit-log

Query the record event log for your organization — the events across all your records, filterable by source, correlation id, event type, and date. The join is vendor-scoped server-side, so it never leaks another tenant’s events. Permission: record_audit_log:view · Scope: record:read Query parameters: Response:
Status codes: 200 OK, 400 Bad Request (invalid query), 401 Unauthorized, 403 Forbidden (insufficient permission or scope), 500 Internal Server Error

Errors & conventions

Every endpoint on this page follows the platform-wide REST conventions — the validation-error body shape, the /v1/ vs unversioned split, and the API stability policy. See REST API conventions.