Documentation menu
These are pre-release docs from the main branch.

API reference

21 operations in reports. Raw spec: openapi.json.

GET/api/v1/report-catalog

GET /api/report-catalog — the fixed field catalog for the R6 builder (ADR 0001): per-view projected columns + filterable inventory with value classes. Static data served from the same Rust constants the compiler validates against, so the UI can never offer an identifier the backend would reject.

Responses

StatusDescription
200

Security: bearer

GET/api/v1/report-definitions

GET /api/report-definitions — visible definitions, deterministically ordered `(name, id)`.

Responses

StatusDescription
200

Security: bearer

POST/api/v1/report-definitions

POST /api/report-definitions — create a stored definition through the instant-first write path (idempotency key honored; response carries `mutation` metadata).

Request body

CreateReportDefinitionRequest

Responses

StatusDescription
200
403missing reporting:create
409name conflict or idempotency key reused
422spec failed registry validation

Security: bearer

GET/api/v1/report-definitions/{id}

GET /api/report-definitions/{id} — one visible definition; anything not visible (deleted, other org, private of another user) is a bare 404.

Parameters

NameInTypeRequiredDescription
idpathstringYes

Responses

StatusDescription
200
404not visible in scope

Security: bearer

PUT/api/v1/report-definitions/{id}

PUT /api/report-definitions/{id} — full-replace update through the instant-first write path (version gate enforced; a miss inside a mutation is the typed `rls_sparse` reason, not `not_found`).

Parameters

NameInTypeRequiredDescription
idpathstringYes

Request body

UpdateReportDefinitionRequest

Responses

StatusDescription
200
403definition outside the caller's writable scope
404rls_sparse: target not visible
409version conflict or idempotency key reused
422spec failed registry validation

Security: bearer

DELETE/api/v1/report-definitions/{id}

DELETE /api/report-definitions/{id} — removal through the same gated path; the write trail keeps the deleted snapshot (undo substrate).

Parameters

NameInTypeRequiredDescription
idpathstringYes

Responses

StatusDescription
200
403definition outside the caller's writable scope
404rls_sparse: target not visible
409version conflict

Security: bearer

GET/api/v1/report-definitions/{id}/run

GET /api/report-definitions/{id}/run — compile-on-demand execution of a visible stored definition's spec (R6 builder runs). The spec re-validates through the registry, compiles via `ReportSpec::compile_windowed` (identifiers stay enum-matched catalog constants; values bind as `$N` parameters), and executes against the reporting pool inside an org-bound transaction. Non-admins are structurally self-scoped exactly like the prebuilt kinds.

Parameters

NameInTypeRequiredDescription
idpathstringYes
fromquery—NoInclusive window start (UTC day, YYYY-MM-DD). Default: 30 trailing days.
toquery—NoInclusive window end (UTC day). Max span with `from`: 366 days.
limitquery—NoPage size, clamped to [1, 500].
formatquery—No`"csv"` streams text/csv instead of the JSON envelope.

Responses

StatusDescription
200Report page (JSON envelope or CSV stream)
404not visible in scope
422spec failed registry validation or invalid window

Security: bearer

GET/api/v1/report-schedules

GET /api/report-schedules — cursor-paged listing (admin), ordered `(name, id)`, each row carrying its next-run preview.

Parameters

NameInTypeRequiredDescription
cursorquery—NoOpaque keyset cursor from a previous page's `next_cursor`.
limitquery—NoPage size, clamped to [1, 200].

Responses

StatusDescription
200

Security: bearer

POST/api/v1/report-schedules

POST /api/report-schedules — create a schedule through the instant-first write path; the next-run preview computes from now.

Request body

CreateReportScheduleRequest

Responses

StatusDescription
200
403admin-only surface
409name conflict or idempotency key reused
422validation failed (shape, recipients, definition)

Security: bearer

GET/api/v1/report-schedules/{id}

GET /api/report-schedules/{id} — one schedule; anything not in this org is a bare 404.

Parameters

NameInTypeRequiredDescription
idpathstringYes

Responses

StatusDescription
200
404not in scope

Security: bearer

PUT/api/v1/report-schedules/{id}

PUT /api/report-schedules/{id} — full-replace update; the next-run preview recomputes from now (cadence changes cannot strand a slot in the past; the worker's claim sweep catches up enabled schedules anyway, so this only affects the preview's freshness).

Parameters

NameInTypeRequiredDescription
idpathstringYes

Request body

UpdateReportScheduleRequest

Responses

StatusDescription
200
403admin-only surface
404rls_sparse: target not visible
409name conflict or version conflict
422validation failed

Security: bearer

DELETE/api/v1/report-schedules/{id}

DELETE /api/report-schedules/{id} — removal through the same gated path; ledger rows cascade and the write trail keeps the snapshot.

Parameters

NameInTypeRequiredDescription
idpathstringYes

Responses

StatusDescription
200
403admin-only surface
404rls_sparse: target not visible
409version conflict

Security: bearer

GET/api/v1/report-schedules/{id}/deliveries

GET /api/report-schedules/{id}/deliveries — the delivery ledger for one schedule (R4 history surface). Worker-written data: rows are append-only run records, never mutated, newest slot first. A missing schedule is a bare 404.

Parameters

NameInTypeRequiredDescription
idpathstringYes
limitquery—NoPage size, clamped to [1, 200].
offsetquery—NoRow offset for paging.

Responses

StatusDescription
200
404not in scope

Security: bearer

POST/api/v1/reports/run-spec

POST /api/reports/run-spec — execute an INLINE spec (R6 builder preview). Same compile/execute/RBAC seam as running a stored definition; the spec never touches storage and identifiers re-validate against the static catalog before compilation.

Request body

RunSpecRequest

Responses

StatusDescription
200
422spec failed registry validation or invalid window

Security: bearer

GET/api/v1/reports/{kind}

GET /api/reports/{kind} — prebuilt operational report over the read-model views. Kinds: time_by_user | time_by_client | time_by_ticket | sla_attainment | sla_breaches | ticket_throughput | ticket_aging | first_response.

Parameters

NameInTypeRequiredDescription
fromquery—NoInclusive window start (UTC day, YYYY-MM-DD). Default: 30 trailing days.
toquery—NoInclusive window end (UTC day). Max span with `from`: 366 days.
cursorquery—NoOpaque keyset cursor from a previous page's `next_cursor`.
limitqueryintegerNoPage size, clamped to [1, 500].
formatquery—No`"csv"` streams text/csv instead of the JSON envelope.
user_idquery—NoManager-only narrowing onto one staff member; non-managers are ALWAYS forced onto themselves regardless of this parameter.
policy_idquery—NoSLA kinds: restrict to one governing policy.
billablequery—NoTime rollups: filter billable/non-billable entries.
as_ofquery—Noticket_aging only: snapshot instant for ages (default: now).
kindpathstringYes

Responses

StatusDescription
200Report page (JSON envelope or CSV stream)

Security: bearer

GET/api/v1/scorecards

GET /api/scorecards?from&to — every active staff member's scorecard in one org-wide read (owner/admin only; R5 private-by-default means a plain tech never sees anyone else's card here, including via query tricks — the scope is derived from the principal, never the request).

Parameters

NameInTypeRequiredDescription
fromquery—NoInclusive window start (UTC day, YYYY-MM-DD). Default: 30 trailing days.
toquery—NoInclusive window end (UTC day). Max span with `from`: 366 days.

Responses

StatusDescription
200
403team scorecards are owner/admin only
422invalid window

Security: bearer

GET/api/v1/scorecards/clients

GET /api/scorecards/clients?from&to — per-client CSAT rollups over the window (owner/admin only). `available: false` until the org records its first survey, matching the per-tech section's honesty gate.

Parameters

NameInTypeRequiredDescription
fromquery—NoInclusive window start (UTC day, YYYY-MM-DD). Default: 30 trailing days.
toquery—NoInclusive window end (UTC day). Max span with `from`: 366 days.

Responses

StatusDescription
200
403missing reporting:view
422invalid window

Security: bearer

GET/api/v1/scorecards/me

GET /api/scorecards/me?from&to — the caller's own scorecard.

Parameters

NameInTypeRequiredDescription
fromquery—NoInclusive window start (UTC day, YYYY-MM-DD). Default: 30 trailing days.
toquery—NoInclusive window end (UTC day). Max span with `from`: 366 days.

Responses

StatusDescription
200
403missing reporting:view
422invalid window

Security: bearer

GET/api/v1/scorecards/me/settings

GET /api/scorecards/me/settings — the caller's scorecard settings (absent row reads as the private-by-defaults).

Responses

StatusDescription
200
403missing reporting:view

Security: bearer

PATCH/api/v1/scorecards/me/settings

PATCH /api/scorecards/me/settings — flip the R5 opt-in gamification toggle. Only ever touches the CALLER's row (no user_id in the body by design); emits `scorecard.settings_updated` in the same transaction.

Request body

UpdateScorecardSettingsRequest

Responses

StatusDescription
200
403missing reporting:view

Security: bearer

GET/api/v1/scorecards/{user_id}

GET /api/scorecards/{user_id}?from&to — one member's scorecard; a member may read their own, owner/admin may read anyone's.

Parameters

NameInTypeRequiredDescription
fromquery—NoInclusive window start (UTC day, YYYY-MM-DD). Default: 30 trailing days.
toquery—NoInclusive window end (UTC day). Max span with `from`: 366 days.
user_idpathstringYes

Responses

StatusDescription
200
403other members' scorecards are owner/admin only
404member not in scope (rls_sparse)
422invalid window

Security: bearer