Skip to content

Report templates

A report template is a presentation format — a Liquid document with no binding to any workspace, project, user, or period. A report freely combines any template with any scope and date range at render time. Templates are instance-scoped: every authenticated user can read them to compose a report, but creating, editing, disabling, and deleting them is gated.

Reading templates requires only read scope and any authenticated session. Managing them — POST, PATCH, PATCH …/state, and DELETE — requires an instance admin or a user with the template-author capability (user.canManageTemplates), not a workspace role.

Field Type Description
id string Unique identifier.
name string Display name (1–100 chars).
description string | null Optional description (≤ 1000 chars).
body string The Liquid template body (1–50000 chars).
enabled boolean Whether the template can back new/edited reports. Disabled templates are hidden from the report tabs.
isDefault boolean Whether this is the instance default — the template the compose form preselects. Exactly one template holds it.
nameTemplate string | null Liquid that generates a new report’s initial name (suggestedName in the preview).
noteTemplate string | null Liquid that generates a new report’s initial note (suggestedNote).
defaultDateRange string | null The date range a new report starts with (today, yesterday, this_week, last_week, this_month, last_month), or null to fall back to Today.
createdBy string | null The user who created it, or null for the seeded starter templates.
createdAt string | null ISO 8601 creation instant.
updatedAt string | null ISO 8601 last-update instant.

GET /api/v1/report-templates scope: read

Returns all templates. The starter catalog (Daily, Weekly, Monthly, from @spantail/templates) is seeded once at instance bootstrap — when the first user, the instance admin, signs up — in that request’s Accept-Language, so reports are always composable; Daily is the instance default. Listing does not seed.

curl "https://<your-instance>/api/v1/report-templates" \
  -H "Authorization: Bearer spantail_pat_yourtoken"

POST /api/v1/report-templates scope: write

Requires instance admin or the template-author capability. Created templates are enabled.

Request body

Field Type Required Description
name string yes Display name (1–100 chars).
body string yes Liquid template body (1–50000 chars).
description string no Optional description (≤ 1000 chars).
nameTemplate string no Liquid for a new report’s initial name.
noteTemplate string no Liquid for a new report’s initial note.
defaultDateRange string no Default date range for a new report (today, yesterday, this_week, last_week, this_month, last_month).
curl -X POST "https://<your-instance>/api/v1/report-templates" \
  -H "Authorization: Bearer spantail_pat_yourtoken" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Weekly summary",
    "description": "Totals and per-project breakdown for a week.",
    "body": "# {{ report.name }}\n\nTotal: {{ period.from }} – {{ period.to }}"
  }'

Returns 201 Created.

GET /api/v1/report-templates/:id scope: read

Returns a single template. Unknown id returns 404.

PATCH /api/v1/report-templates/:id scope: write

Requires instance admin or the template-author capability. All body fields are optional; send just what changes. Use Set template state to enable or disable instead.

Request body

Field Type Required Description
name string no Display name (1–100 chars).
description string | null no Description (≤ 1000 chars), or null to clear.
body string no Liquid template body (1–50000 chars).
nameTemplate string | null no Liquid for a new report’s initial name, or null to clear.
noteTemplate string | null no Liquid for a new report’s initial note, or null to clear.
defaultDateRange string | null no Default date range, or null to fall back to Today.
curl -X PATCH "https://<your-instance>/api/v1/report-templates/tpl_weekly" \
  -H "Authorization: Bearer spantail_pat_yourtoken" \
  -H "Content-Type: application/json" \
  -d '{ "description": "Weekly totals, per project and per person." }'

PATCH /api/v1/report-templates/:id/state scope: write

Requires instance admin or the template-author capability. Enables or disables a template, separately from body edits. A disabled (archived) template can no longer back a new or edited report, but existing reports stay viewable and shareable. The instance default cannot be disabled while it holds the flag — that returns 409 conflict; set another template as default first.

Request body

Field Type Required Description
enabled boolean yes true to enable, false to disable.
curl -X PATCH "https://<your-instance>/api/v1/report-templates/tpl_weekly/state" \
  -H "Authorization: Bearer spantail_pat_yourtoken" \
  -H "Content-Type: application/json" \
  -d '{ "enabled": false }'

PATCH /api/v1/report-templates/:id/default scope: write

Requires instance admin or the template-author capability. Makes this template the sole instance default — the one the compose form preselects — clearing the flag from whichever template held it. A disabled template cannot become the default (409 conflict). Returns the updated template.

curl -X PATCH "https://<your-instance>/api/v1/report-templates/tpl_weekly/default" \
  -H "Authorization: Bearer spantail_pat_yourtoken"

DELETE /api/v1/report-templates/:id scope: write

Requires instance admin or the template-author capability. Two guards return 409 conflict: a template still referenced by saved reports cannot be deleted (disable it instead), and the instance default cannot be deleted while it holds the flag (set another template as default first). Returns 204 No Content on success.