Skip to main content
Share links let a report run or decision trace be viewed at a /share/{token} URL without a login — the token itself is the credential, like a password. Management endpoints are tenant-scoped and RBAC-gated; the public read endpoint is auth-free and validates the token itself.

POST /api/v1/shares

Issue a new share token. Editor or admin.

Request body

FieldTypeRequiredDescription
kindenumYes"report_run" or "decision_trace".
resourceIdstring (1-256)YesId of the report run or decision trace to share.
expiresAtstring (ISO-8601)YesWhen the link expires. Must be in the future and at most 90 days out.
labelstring (max 256)NoHuman label for the link list. Defaults to "".
kind does not accept "dashboard". Dashboards are config-driven (there is no Dashboard entity to resolve), so a dashboard token would always 404. The value is intentionally excluded from the create schema.

Response 201

The token is returned only once, at creation time. Store it — list responses omit it.
{
  "id": "shl_...",
  "kind": "report_run",
  "resourceId": "rr_...",
  "token": "9f2c...<64 hex chars>",
  "label": "Q3 board deck",
  "expiresAt": "2026-08-01T00:00:00.000Z",
  "createdAt": "2026-07-03T12:00:00.000Z",
  "publicUrl": "/share/9f2c..."
}

Errors

CodeReason
400Invalid payload, expiresAt not a valid timestamp, in the past, or more than 90 days out.
403Caller is not editor/admin.

GET /api/v1/shares

List this tenant’s share links. Viewer, editor, or admin. The token is never returned here — only metadata and usage counters.

Response 200

{
  "data": [
    {
      "id": "shl_...",
      "kind": "report_run",
      "resourceId": "rr_...",
      "label": "Q3 board deck",
      "expiresAt": "2026-08-01T00:00:00.000Z",
      "createdBy": "user_...",
      "revoked": false,
      "viewCount": 12,
      "lastViewedAt": "2026-07-03T18:30:00.000Z",
      "createdAt": "2026-07-03T12:00:00.000Z",
      "updatedAt": "2026-07-03T18:30:00.000Z"
    }
  ]
}

DELETE /api/v1/shares/:id

Revoke a share link. Editor or admin. Revocation is soft — the row stays with revoked: true so the audit trail is preserved, and the public read endpoint immediately refuses the token.

Response 200

{ "ok": true, "revoked": true }

GET /api/v1/public/shares/:token

Auth-free read of a previously issued share. No tenant header, no API key — the token in the path is the credential. Per-IP rate limited (60 requests / 60 s, fail-open).

Response 200

{
  "kind": "report_run",
  "label": "Q3 board deck",
  "expiresAt": "2026-08-01T00:00:00.000Z",
  "payload": { "...": "the report-run or decision-trace record" }
}
For report_run the payload excludes raw artifact bytes (metadata, section data, and narrative only). Each successful read increments the link’s viewCount.
Every failure mode returns 404 — token not found, revoked, expired, or the underlying resource deleted — so a caller can never enumerate which tokens exist.