Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.tallwatch.com/llms.txt

Use this file to discover all available pages before exploring further.

By default, the webhook channel POSTs the canonical payload. When that shape doesn’t fit your receiver, paste a Handlebars template into the channel form’s Payload template field. Tallwatch renders it against the canonical variables and POSTs the result. This page covers the variable surface, the helpers we register, and worked examples for common receivers.
Always test a template with the Send test alert button before binding the channel to real monitors. A malformed template fails at dispatch time and the alert never delivers; the test catches it before an incident does.

Variable reference

The template runs against the same JSON object documented on the Payload page. Use dot-notation to access nested fields.
VariableTypeExample value
{{event}}stringincident.opened
{{occurred_at}}string (ISO 8601)2026-06-02T14:23:01.829Z
{{org.id}}string (UUID)9b8c7d6e-...
{{org.name}}stringAcme Corp
{{org.slug}}stringacme
{{monitor.id}}string (UUID)1a2b3c4d-...
{{monitor.name}}stringAPI healthcheck
{{monitor.type}}stringhttp
{{monitor.url}}stringhttps://api.acme.com/health
{{monitor.tags}}string[]["prod", "api"]
{{incident.id}}stringabc12345
{{incident.status}}stringopen / acknowledged / resolved
{{incident.opened_at}}string (ISO 8601)2026-06-02T14:21:30.500Z
{{incident.acknowledged_at}}string | nullnull
{{incident.resolved_at}}string | nullnull on open events
{{incident.duration_sec}}number | null1037
{{incident.failing_regions}}string[]["fra1", "iad1", "sgp1"]

Built-in helpers

Standard Handlebars plus a small set of project-specific helpers:
HelperUseOutput
{{join failing_regions ", "}}Comma-join an arrayfra1, iad1, sgp1
{{json this}}Embed a value as JSON{"id":"abc..."}
{{upper monitor.type}}Uppercase a stringHTTP
{{#if incident.resolved_at}}…{{/if}}Conditional blockrenders only on resolved events
{{#each failing_regions}}…{{/each}}Loop over an arraytypical Handlebars iteration
{{@last}}, {{@first}}, {{@index}}Loop context inside {{#each}}standard Handlebars
Standard Handlebars escape rules apply: {{var}} HTML-escapes by default, {{{var}}} writes literally. JSON output ALWAYS wants the triple-stash form so quotes and braces aren’t escaped:
{
  "monitor": "{{{monitor.name}}}"
}
When templating JSON, every string field needs {{{...}}} (triple-stash), not {{...}} (double-stash). Double-stash escapes HTML entities and produces invalid JSON when the value contains a quote or ampersand. The double-stash form is for HTML output, which webhooks usually aren’t.

Worked examples

Slack-compatible body

If you want to POST to a Slack incoming webhook URL but get richer control than the native Slack channel offers, use a webhook channel with this template:
Slack template
{
  "text": "{{{monitor.name}}} is {{{incident.status}}}",
  "attachments": [
    {
      "color": "{{#if incident.resolved_at}}good{{else}}danger{{/if}}",
      "fields": [
        {
          "title": "Regions",
          "value": "{{join incident.failing_regions ", "}}",
          "short": true
        },
        {
          "title": "Duration",
          "value": "{{#if incident.duration_sec}}{{incident.duration_sec}}s{{else}}ongoing{{/if}}",
          "short": true
        }
      ]
    }
  ]
}

Datadog event API body

Push Tallwatch incidents into Datadog’s event stream for cross-correlation with your APM/RUM data:
Datadog template
{
  "title": "Tallwatch: {{{monitor.name}}} is {{{incident.status}}}",
  "text": "Failing regions: {{join incident.failing_regions ", "}}\nIncident: https://tallwatch.com/incidents/{{incident.id}}",
  "alert_type": "{{#if incident.resolved_at}}success{{else}}error{{/if}}",
  "tags": [
    "service:{{{monitor.name}}}",
    "tallwatch:{{{event}}}"
  ]
}

Minimal internal alert

If your internal ticketing system just needs a one-line subject and a URL back:
Minimal template
{
  "subject": "[Tallwatch] {{{monitor.name}}}: {{{event}}}",
  "url": "https://tallwatch.com/incidents/{{incident.id}}"
}

Status page incident publisher

Re-broadcast Tallwatch incidents to your existing status page tool (e.g. a Statuspage.io webhook receiver):
Statuspage template
{
  "incident": {
    "name": "{{{monitor.name}}} degraded",
    "status": "{{#if incident.resolved_at}}resolved{{else}}investigating{{/if}}",
    "body": "Tallwatch detected this incident in {{join incident.failing_regions ", "}}. We're investigating.",
    "impact_override": "minor"
  }
}

Errors and debugging

Your Handlebars template is malformed. Common causes: unclosed {{#if}} block, unbalanced quotes, unescaped braces in a JSON value. Open the channel form and re-test with Send test alert — the error message will show the line number.
Almost always a double-stash ({{x}}) where you needed triple-stash ({{{x}}}). When a value contains a special character (", &, <), the double-stash escapes it to an HTML entity and the resulting body is no longer valid JSON.Switch to triple-stash for all string-valued fields in your template.
Handlebars renders a missing value as an empty string by default, NOT undefined — so if you’re seeing the literal word undefined in your output, something on your receiver side is JSON-parsing the string "undefined" and printing it. Likely a layer between Tallwatch and the destination is corrupting the body.Open the dispatch history in Tallwatch and look at the rendered body to confirm what we actually sent.
Correct behaviour. On incident.resolved, the failing-regions array is empty because all regions have agreed the monitor is up. Wrap region-dependent template parts in {{#if incident.failing_regions.length}}:
{{#if incident.failing_regions.length}}
  Regions affected: {{join incident.failing_regions ", "}}
{{else}}
  All regions recovered.
{{/if}}
One channel = one template. To branch by event type inside the same template:
{
  "subject": "{{#if (eq event "incident.opened")}}[OPEN]{{else}}[RESOLVED]{{/if}} {{{monitor.name}}}"
}
Tallwatch registers an eq helper for this purpose.

When NOT to template

If your receiver accepts the canonical payload, leave the template blank. Reasons:
  • One less thing to maintain when the canonical payload gains a new field
  • Template errors are caught at dispatch time, the canonical path can’t go wrong
  • The dispatch history is easier to read when bodies are predictable
Templates are an escape hatch for receivers that require a specific shape. They are not a feature to use on every channel by default.