Webhook payloads
What CloudLine sends to your Discord webhook on each alert type — the embed shape, field names, severity colors, and timestamps.
When CloudLine fires an alert (your bot went offline, latency spiked, gateway zombied, etc.), it POSTs a Discord webhook message to your configured URL. This page documents the exact embed structure so you know what to expect — and what to build against if you're routing the webhook through a custom receiver before forwarding to Discord.
Alert types
| Type | Fires when... |
|---|---|
offline | Bot missed too many heartbeats. Opens an incident. |
recovery | Bot came back from offline. Closes the incident. |
degraded | Bot is heartbeating but slowly (opt-in). |
test | You clicked Send test on the Alerts tab. |
latency_high | Gateway ping above threshold for the sustained window. |
latency_recovery | Gateway ping back below threshold. |
zombie | Bot's gateway has been stale for the sustained window. |
zombie_recovery | Gateway recovered. |
shard_down | Sharded bot has fewer shards connected than expected. |
shard_recovery | All shards back. |
cpu_high / cpu_recovery | CPU sustained above / back below threshold. |
mem_high / mem_recovery | RAM sustained above / back below. |
lag_high / lag_recovery | Event-loop lag sustained above / back below. |
err_high / err_recovery | Errors-per-minute sustained above / back below. |
Every threshold-based alert has a paired _recovery event when the metric returns to normal.
Discord embed shape
CloudLine sends a single embeds entry, with username: "CloudLine" on the message. The shape:
{
"username": "CloudLine",
"embeds": [
{
"title": "<emoji> <Alert title> · CL-<short ref>",
"url": "<appUrl>/dashboard/bots/<botId>",
"description": "<one-line summary>",
"color": 4474437,
"fields": [
{ "name": "Bot", "value": "`MyBot`", "inline": true },
{ "name": "Status", "value": "CRITICAL", "inline": true },
{ "name": "Detected", "value": "`2026-06-03 14:23`\n2 min ago", "inline": true }
// … type-specific fields here
],
"footer": {
"text": "CloudLine Monitoring · BOT-<short ref>"
},
"timestamp": "2026-06-03T14:23:45.123Z"
}
]
}Notes:
- The
colorfield is the decimal form of the hex below (e.g.#ED4245→4474437). - The footer is a plain
textline — there is nofooter.icon_url. Business users with a custom footer get<your footer> · BOT-<ref>instead of the defaultCloudLine Monitoring · BOT-<ref>. - A Business custom logo is attached at the message level as
avatar_url, not inside the footer.
The embed colour follows the alert type / severity and is not customisable for real incidents. A Business customBrandColor only re-colours the test alert — live incident colours stay semantic (red / yellow / green) so an outage always looks like an outage:
| Severity (Status field) | Alert types | Color |
|---|---|---|
CRITICAL | offline, zombie | red #ED4245 |
WARNING | degraded, latency_high, shard_down, cpu_high, mem_high, lag_high, err_high | degraded is yellow #FEE75C; all other warnings are orange #FF8800 |
RECOVERY | recovery, *_recovery | green #57F287 |
TEST | test | blurple #5865F2 |
Title format
Each alert type has a specific title with a leading emoji. The short incident reference (CL-A1B2C3D) follows on the same line so you can quote it when paging up colleagues:
| Type | Title |
|---|---|
offline | 🔴 Bot Offline · CL-… |
recovery | 🟢 Bot Recovered · CL-… |
degraded | 🟡 Bot Degraded · CL-… |
test | 🔔 Test Alert · CL-… |
latency_high | ⚡ High Latency · CL-… |
latency_recovery | ✅ Latency Recovered · CL-… |
zombie | 🧟 Bot Zombie · CL-… |
zombie_recovery | ✅ Gateway Recovered · CL-… |
shard_down | 🧩 Shard Down · CL-… |
shard_recovery | ✅ Shards Recovered · CL-… |
cpu_high | 🔥 High CPU · CL-… |
mem_high | 🧠 High Memory · CL-… |
lag_high | ⏱ Event-loop Stalling · CL-… |
err_high | 🚨 Error Burst · CL-… |
The recovery variants for CPU / memory / lag / error all use the ✅ emoji with their "… Recovered / Subsided" title.
Fields by alert type
All alerts share three header fields: Bot, Status, Detected. Per-type fields:
offline, degraded
| Field | Value |
|---|---|
| Trigger | Multi-line code block with the cause (e.g. "no heartbeat since 2 min ago"). |
recovery
| Field | Value |
|---|---|
| Downtime | 1m 32s style string. |
| Latency | First heartbeat's gateway ping after recovery (when reported). |
latency_high
| Field | Value |
|---|---|
| Current | 350 ms |
| Threshold | 200 ms |
| Sustained | 1m 0s style string. |
cpu_high, mem_high, lag_high, err_high
Same shape as latency_high — Current / Threshold / Sustained, with the units appropriate to the metric (%, MB, ms, /min).
*_recovery (latency / cpu / mem / lag / err)
A single field echoing the current value (Latency, CPU, Memory, Event-loop lag, Error rate).
zombie
| Field | Value |
|---|---|
| Gateway stale | 1m 0s — how long the gateway has been unhealthy. |
shard_down, shard_recovery
| Field | Value |
|---|---|
| Shards | 3/5 connected |
test
| Field | Value |
|---|---|
| Note | "Test dispatch — no real incident. Templates render identically for live alerts." |
Severity labels
The Status field of the embed carries a fixed per-type severity label — it's the alert's category, not an outage-duration tier:
CRITICAL—offline,zombie. The bot is having a real problem.WARNING—degradedand all threshold alerts (latency_high,cpu_high,mem_high,lag_high,err_high,shard_down). Notable, often self-resolving.RECOVERY— every*_recoveryevent.TEST— the manual test dispatch.
Deep link to the bot
If the alert was dispatched from a context that knows the dashboard's app URL, the embed url (which makes the title clickable in Discord) is:
<appUrl>/dashboard/bots/<botId>Clicking it opens the bot detail in your CloudLine dashboard.
Timestamps
The timestamp field on the embed is an ISO-8601 UTC string. Discord renders this in the client's local timezone. The text in the Detected field is a copy of the same instant rendered in the bot owner's configured timezone (set in your account settings) so the embed reads correctly even when forwarded to a server in a different timezone.
What gets retried
The webhook delivery makes up to 3 attempts:
- Initial send.
- Retry after 1 s.
- Retry after 2 s.
Discord's 429 Retry-After header is honored — if Discord asks us to wait, we wait (and that wait doesn't consume a normal backoff step). 4xx errors other than 429 (e.g. 404 — webhook deleted) are not retried; they're recorded as a delivery failure in the Alerts tab with a "delivery failed" badge.
Each attempt has a 10-second timeout so a hung connection can't wedge the dispatcher.
Email shape
Alert emails (Pro+) use the same field set as Discord embeds, rendered as HTML. Subject format:
<emoji> CloudLine — <Alert title>: <bot name>For example: 🔴 CloudLine — Bot Offline: MyBot. The HTML body uses CloudLine's default theme; Business users with custom branding get their hex color on the header bar and their logo above the title.
Routing to a custom endpoint
A common pattern: send the Discord webhook to a custom receiver you control (Cloudflare Worker, your own backend), let it modify or forward the payload, then send to Discord.
In your CloudLine config, paste your receiver's URL instead of Discord's URL. Your receiver gets the exact JSON described above; do what you want with it, then POST onward to Discord.
Note: your receiver must accept application/json POST and return a 2xx within 10 seconds, or CloudLine treats the alert as a delivery failure. Keep your receiver fast and synchronous.