PPactDocs
CRM

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:

json
{
  "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.

bash
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 with cadence (daily / weekly / monthly), a recipients list, and a delivery format (pdf default, or html / 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.

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.