TrigRun
Guides

Notifications

Get alerted when jobs succeed, fail, or complete via webhook, email, Slack, Discord, or Telegram.

TrigRun can notify you when job executions succeed, fail, or complete — and when monitors go down or recover. Notifications are configured in two steps: create a channel (where to send), then attach a rule to a job or monitor (when to send).

All sensitive credentials (webhook URLs, bot tokens) are encrypted at rest and never exposed in API responses.

Channel types

TypeDescriptionCredentials stored
webhookPOST JSON to any URL with optional HMAC signingURL in config, signing secret encrypted
emailHTML email via ResendEmail address in config
slackRich messages with blocks to a Slack channelWebhook URL encrypted
discordEmbeds to a Discord channelWebhook URL encrypted
telegramHTML messages to a Telegram chat or groupBot token encrypted, chat ID in config

Slack setup

  1. Go to your Slack workspace settings: Apps → Manage → Custom Integrations → Incoming Webhooks (or create a new Slack app with an incoming webhook).
  2. Choose the channel you want alerts posted to.
  3. Copy the webhook URL (starts with https://hooks.slack.com/services/...).
  4. Create the channel in TrigRun — the webhook URL is stored encrypted and never shown again:
curl -X POST https://api.trigrun.com/v1/notification-channels \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "slack-alerts",
    "type": "slack",
    "config": {
      "webhook_url": "https://hooks.slack.com/services/T00/B00/xxx",
      "mention_text": "@channel",
      "include_output": false
    }
  }'

Config options:

FieldRequiredDescription
webhook_urlYesSlack incoming webhook URL
mention_textNoText prepended to messages, e.g. @channel or @here
include_outputNoInclude response body preview in messages (default: false)

Messages are sent with both a plaintext fallback and rich blocks showing the event, status, and timestamp.

Discord setup

  1. In your Discord server, go to Server Settings → Integrations → Webhooks.
  2. Click New Webhook, choose a channel, and copy the webhook URL.
  3. Create the channel in TrigRun:
curl -X POST https://api.trigrun.com/v1/notification-channels \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "discord-alerts",
    "type": "discord",
    "config": {
      "webhook_url": "https://discord.com/api/webhooks/123/abc",
      "thread_id": "456",
      "mention_role_ids": ["789012345678"],
      "include_output": false
    }
  }'

Config options:

FieldRequiredDescription
webhook_urlYesDiscord webhook URL
thread_idNoPost to a specific thread in a forum channel
mention_role_idsNoArray of role IDs to mention (e.g. ["123456"])
include_outputNoInclude response body preview in embeds (default: false)

Messages use Discord embeds with color-coded status (green for success/recovery, red for failure/down).

Telegram setup

  1. Open Telegram and message @BotFather.
  2. Send /newbot, follow the prompts, and copy the bot token (format: 123456:ABC-DEF...).
  3. Send a message to your bot (or add it to a group/channel) so it has permission to send messages.
  4. Get your chat ID:
    • For personal chats: message @userinfobot to get your numeric ID.
    • For groups: add @RawDataBot to the group, it will show the chat ID (negative number like -1001234567890).
  5. Create the channel in TrigRun:
curl -X POST https://api.trigrun.com/v1/notification-channels \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "tg-alerts",
    "type": "telegram",
    "config": {
      "bot_token": "123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11",
      "chat_id": "-1001234567890",
      "disable_web_page_preview": true,
      "include_output": false
    }
  }'

Config options:

FieldRequiredDescription
bot_tokenYesBot token from BotFather (stored encrypted)
chat_idYesNumeric chat ID as string (negative for groups)
message_thread_idNoThread ID for forum topic groups
disable_web_page_previewNoDisable link previews in messages (default: true)
include_outputNoInclude response body preview (default: false)

Messages are sent as HTML with bold titles and formatted status lines.

Webhook setup

POST JSON payloads to any HTTP endpoint. Optionally sign payloads with HMAC-SHA256.

curl -X POST https://api.trigrun.com/v1/notification-channels \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "ops-webhook",
    "type": "webhook",
    "config": {
      "url": "https://api.example.com/hooks/cron",
      "signing_secret": "whsec_your_signing_secret"
    }
  }'

Config options:

FieldRequiredDescription
urlYesEndpoint URL (must be public, not private/loopback)
signing_secretNoHMAC-SHA256 signing key (stored encrypted). Signature sent in X-Webhook-Signature: sha256=<hex> header.

Webhook payload format (execution events):

{
  "event": "execution.failed",
  "job": { "id": "clx...", "name": "Nightly sync" },
  "execution": {
    "id": "clx...",
    "status": "failed",
    "status_code": 500,
    "body_preview": "Internal Server Error",
    "error_class": "HTTP_5XX"
  },
  "output": null,
  "timestamp": "2026-03-16T10:00:00.000Z"
}

Webhook payload format (monitor events):

{
  "event": "monitor.down",
  "monitor": {
    "id": "clx...",
    "name": "API Health",
    "expected_interval_sec": 60,
    "last_ping_at": null
  },
  "timestamp": "2026-03-16T10:00:00.000Z"
}

Verifying signatures:

const crypto = require("crypto");
const signature = crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
const expected = req.headers["x-webhook-signature"]; // "sha256=<hex>"
if (`sha256=${signature}` !== expected) {
  return res.status(401).send("Invalid signature");
}

Email setup

curl -X POST https://api.trigrun.com/v1/notification-channels \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "team-email",
    "type": "email",
    "config": {
      "email": "[email protected]"
    }
  }'

Emails are sent as styled HTML with status-colored headers and a summary table.

Testing a channel

After creating a channel, verify it works by sending a test notification:

curl -X POST https://api.trigrun.com/v1/notification-channels/CHANNEL_ID/test \
  -H "Authorization: Bearer $TOKEN"

The test sends a synthetic success payload through the full delivery pipeline (secret resolution, rendering, provider send) without creating a delivery record. Response:

{ "ok": true, "channel_id": "clx...", "provider": "telegram" }

Or on failure:

{
  "ok": false,
  "error": { "code": "notification_test_failed", "message": "Telegram returned 403: bot was blocked by the user" },
  "http_status": 403,
  "permanent": true
}

You can also test from the dashboard — each channel row has a Test button.

Notification events

EventFires when
on_successAn execution completes with a success status
on_failureAn execution exhausts all retry attempts and fails
on_completionAn execution finishes, regardless of outcome
on_downA monitor misses its expected ping window
on_recoveryA monitor receives a ping after being down

Attaching rules to jobs

A rule connects a channel to a job for a specific event:

curl -X POST https://api.trigrun.com/v1/jobs/JOB_ID/notification-rules \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "channel_id": "CHANNEL_ID",
    "event": "on_failure"
  }'

You can attach multiple rules to the same job — for example, send failures to Slack and all completions to a webhook.

Attaching rules to monitors

curl -X POST https://api.trigrun.com/v1/monitors/MONITOR_ID/notification-rules \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "channel_id": "CHANNEL_ID",
    "event": "on_down"
  }'

Listing and removing rules

# List rules for a job
curl https://api.trigrun.com/v1/jobs/JOB_ID/notification-rules \
  -H "Authorization: Bearer $TOKEN"

# Remove a rule
curl -X DELETE https://api.trigrun.com/v1/jobs/JOB_ID/notification-rules/RULE_ID \
  -H "Authorization: Bearer $TOKEN"

Delivery tracking

Every notification sent is tracked as a delivery with retry status.

# List all deliveries (optionally filter by status)
curl "https://api.trigrun.com/v1/notification-deliveries?status=failed" \
  -H "Authorization: Bearer $TOKEN"

# List deliveries for a specific execution
curl "https://api.trigrun.com/v1/executions/EXECUTION_ID/notifications" \
  -H "Authorization: Bearer $TOKEN"

# Retry a failed delivery
curl -X POST https://api.trigrun.com/v1/notification-deliveries/DELIVERY_ID/retry \
  -H "Authorization: Bearer $TOKEN"

Delivery statuses

StatusMeaning
pendingQueued, waiting to be sent
processingCurrently being sent
sentSuccessfully delivered
failedAll delivery attempts exhausted or permanent provider error

Retry behavior

  • Transient failures (5xx, timeouts, network errors) are retried with exponential backoff up to 5 attempts.
  • Provider rate limits (429) are respected — the retry delay uses the Retry-After header when present.
  • Permanent failures (400, 403, 404 depending on provider) are marked failed immediately without retrying.
  • Missing or deleted secrets are treated as permanent failures.

Limits

  • Maximum 25 notification channels per workspace.
  • Secrets referenced by channels cannot be deleted (returns 409). Delete the channel first.

CLI reference

# Channels
trigrun channels list
trigrun channels create --name ops --type webhook --url https://example.com/hook
trigrun channels create --name alerts --type email --email [email protected]
trigrun channels create --name tg --type telegram --bot-token 123:ABC --chat-id -100123
trigrun channels test CHANNEL_ID
trigrun channels delete CHANNEL_ID

# Rules
trigrun rules list JOB_ID
trigrun rules add JOB_ID --channel CHANNEL_ID --event on_failure
trigrun rules remove JOB_ID RULE_ID

# Deliveries
trigrun deliveries list
trigrun deliveries list --status failed
trigrun deliveries retry DELIVERY_ID

On this page