Report recipes

Short, copy-ready report templates for the events your workspace fires — an inspection PDF on a submission, a welcome email on an invite, a team note when a form goes live, and more.

Updated 2026-06-11

A report is driven by a webhook subscription, so any event your workspace fires can render a document or send a notification email. Point a subscription at a report template, pick the event, and every matching event renders and delivers within about a minute. This page is a set of starting points — one recipe per event family. For how to build and style a template, see report templates; for every merge field and modifier, see merge syntax; for the full event list and how to subscribe, see webhooks.

Each event arrives wrapped in an envelope — event, id, timestamp, and organization_id at the top level, with the event-specific fields under data. The paths below read from that data object. The report editor's sample-data panel shows the exact shape for the event you pick.

Record submitted — an inspection PDF

When this fires: a crew member submits a record from the mobile app or the dashboard, and you want a finished PDF in an inbox. This is the flagship recipe; report templates walks the full version end to end, including repeating tables and photos.

  • Trigger event: record.created
  • Output: PDF, delivered to an email destination as an attachment
<h1>{$data.field_values.report_title}</h1>
<p>Submitted by {$data.submitted_by}
   on {$data.submitted_at|date:'LL'}</p>
<p>Site temperature: {$data.field_values.site_temperature}</p>

Your form's answers live under data.field_values, keyed by field identifier. data.submitted_by is the submitter's user id and data.submitted_at is the submission time.

New user invited — a welcome email

When this fires: an invitation is issued, and you want to send the person a short note about the workspace and the roles they were granted. The event carries the invited email, the roles granted, who sent the invite, and a pending flag — true when the person does not have an account yet, false when an existing user was added.

  • Trigger event: user.invited
  • Output: HTML, delivered to an email destination in the message body (the rendered template is the email)
<p>You have been invited to the workspace.</p>
<p>Roles granted: {$data.roles|join:', '|default:'none yet'}</p>
<p>Invited on {$data.invited_at|date:'LL'}.</p>

data.email is the invited address, data.roles lists the roles granted at invite time (it can be empty, so default gives it a fallback), and data.invited_by is the person who sent the invite. data.user_id is filled in once the invitee creates an account.

Form published — notify a team

When this fires: a form admin publishes a new version of a form, and you want the field team to know the latest version is live.

  • Trigger event: form.published
  • Output: HTML, delivered to an email destination in the message body
<p>A new version of "{$data.form_identifier}" is live.</p>
<p>Version {$data.version}, published {$data.published_at|date:'LL'}.</p>
<p>What changed: {$data.changelog|default:'no notes'}</p>

data.form_identifier is the form's stable identifier, data.version is the new version number, and data.changelog is the publisher's notes — empty when they skipped them, so default covers that case.

User roles updated — an access-change notice

When this fires: a member's role set changes on save, and you want an audit-style note of what was added and removed. A single save fires one event no matter how many roles changed.

  • Trigger event: user.roles_updated
  • Output: HTML, delivered to an email destination in the message body
<p>Access changed for user {$data.user_id}.</p>
<p>Added: {$data.added|join:', '|default:'none'}</p>
<p>Removed: {$data.revoked|join:', '|default:'none'}</p>
<p>Changed by {$data.actor} on {$data.updated_at|date:'LL'}.</p>

data.added and data.revoked are lists of role names, so join turns each into a readable line. data.actor is the person who made the change.

Organization deactivated — an internal alert

When this fires: an organization is deactivated (soft-deleted), and you want an internal alert so the right people know access was turned off.

  • Trigger event: organization.deactivated
  • Output: HTML, delivered to an email destination in the message body
<p>Organization {$data.id} was deactivated.</p>
<p>Deactivated by {$data.deactivated_by}
   on {$data.deactivated_at|date:'LL'}.</p>

data.id is the organization id, data.deactivated_by is the person who turned it off, and data.deactivated_at is when.

Preview against the real shape

The report editor's sample-data panel can load a real example payload for each event, so you can preview your template against the exact fields it will receive before any live event fires. Pick the event your subscription uses, load its sample, and the live preview renders against that shape as you type.