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. Management keys are launching soon: they are visible in the dashboard under Settings → API Keys, but creating one is not yet enabled. Until then, drive the management endpoints from the dashboard, which authenticates 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.