Report detail
Working with a single saved report — running it, exporting to CSV/XLSX/PDF, scheduling email delivery, and generating a public share link.
Report detail
The report detail view is everything you do with one saved report: run it and see the
result, export the rows, put it on an email schedule, and — if you want to share it outside
the app — mint a public link. It is backed by GET /v1/reports/{id} and the run / export /
schedule / share routes in api/routes/reports.py.
Analytics module + tenant scope
Every route on this page requires verify_api_key and require_module("analytics"), and
loads the report with get_report(report_id, tenant_id=…) — a report id belonging to
another tenant returns 404. The lone exception is GET /v1/reports/public/{token}, which is
authenticated by the share token instead of an API key.
Run it
POST /v1/reports/{id}/run executes the saved definition and returns the result set:
{
"columns": ["stage", "count"],
"rows": [ ["Negotiation", 12], ["Closed Won", 8] ],
"count": 2
}
Running a report stamps last_run_at and — when the caller is a known user — emits a
report.ready notification (in-app + push) carrying the report name and row count. A
notification failure never blocks the report response.
Export
POST /v1/reports/{id}/export?format=<fmt> runs the report and streams a file download.
Supported formats are fixed in core.exports.renderers.SUPPORTED_FORMATS: csv, xlsx,
and pdf. An unsupported format returns 422. The response sets a Content-Disposition
attachment header with a suggested filename and Cache-Control: no-store.
curl -X POST "/v1/reports/$ID/export?format=xlsx" \
-H "Authorization: Bearer $KEY" -OJ
Schedule email delivery
Reports can be delivered on a cadence to a recipient list.
POST /v1/reports/{id}/schedules— create a schedule withcadence(daily/weekly/monthly), arecipientslist, and a deliveryformat(pdfdefault, orhtml/csv/xlsx).GET /v1/reports/{id}/schedules— list schedules for this report.DELETE /v1/reports/schedules/{schedule_id}— remove one.GET /v1/reports/{id}/deliveries— the delivery audit trail (recent sends).POST /v1/reports/schedules/{schedule_id}/run-now— fire a schedule immediately, useful for a "test delivery".
A scheduler tick runs due schedules, executes the report, renders the chosen format, and
delivers to recipients through the existing email pipeline (core.dashboards.delivery),
recording each send.
Share via public link
A share link is unauthenticated — anyone with it can read the report
POST /v1/reports/{id}/share mints a single public token (revoking any prior token for the
report first) and returns a /r/<token> URL. GET /v1/reports/public/{token} reads the
report with no Authorization header — the token is the only credential. The token is
stored as a SHA-256 hash (report_share_tokens.token_hash), never in plaintext, and honors
an optional expires_at; an expired link returns 410. Revoke at any time with
DELETE /v1/reports/{id}/share. Only share reports whose data you are comfortable exposing to
anyone holding the link.
GET /v1/reports/{id}/share reports whether a link currently exists ({"shared": true, …})
without exposing the raw token — the plaintext token is only ever returned once, at creation.
Editing the definition
To change what the report measures, PATCH /v1/reports/{id} with a new definition
(or just a new name / description). The next run reflects the change immediately; saved
schedules and share links keep pointing at the same report and pick up the new definition on
their next run.