Discord - Send Notification

Octopus.Script exported 2026-07-20 by Meanski belongs to ‘Discord’ category.

Posts a message and/or rich embed to a Discord channel via a webhook. No Discord application or bot is required — create a webhook in the channel’s settings (Integrations → Webhooks) and paste its URL into this step.

The embed can automatically colour itself green or red based on the deployment outcome (set Color to auto and use this step with a “run always” condition), include Project/Release/Environment fields, and link back to the deployment in Octopus.

Mentions (@everyone, roles, users) in message content are suppressed by default to prevent accidental pings from interpolated release notes.

Sets the output variable MessageId for use in later steps.

Requires curl and either jq or python3 on the worker.

Parameters

When steps based on the template are included in a project’s deployment process, the parameters below can be set.

Webhook URL

DiscordNotify.WebhookUrl =

The Discord webhook URL (Channel Settings → Integrations → Webhooks). Consider binding this to a sensitive project variable (e.g. #{Discord.WebhookUrl}) so it can be scoped per environment and rotated in one place.

Message Content

DiscordNotify.Content =

Plain message text (supports Discord markdown). Optional when Include Embed is enabled. Maximum 2000 characters — longer values are truncated.

Username Override

DiscordNotify.Username =

Overrides the webhook’s configured display name. Leave blank to use the name configured on the webhook.

Avatar URL Override

DiscordNotify.AvatarUrl =

Overrides the webhook’s configured avatar image. Leave blank to use the avatar configured on the webhook.

Include Embed

DiscordNotify.IncludeEmbed = True

If enabled, sends a rich embed with the title, description, colour, timestamp, a link to the deployment, and optional deployment detail fields.

Embed Title

DiscordNotify.EmbedTitle = #{Octopus.Project.Name} release #{Octopus.Release.Number} deployed to #{Octopus.Environment.Name}

Title of the embed. Maximum 256 characters — longer values are truncated.

Embed Description

DiscordNotify.EmbedDescription =

Body text of the embed (supports Discord markdown). Maximum 4096 characters — longer values are truncated.

Color

DiscordNotify.Color = auto

Colour of the embed’s side bar. auto picks green or red based on whether the deployment has an error — useful with a “run always” step condition. A raw decimal colour value is also accepted.

Include Deployment Fields

DiscordNotify.IncludeDeploymentFields = True

If enabled, adds Project, Release, and Environment fields to the embed (fields without a value, e.g. Release during a runbook run, are omitted).

Suppress Mentions

DiscordNotify.SuppressMentions = True

If enabled, @everyone, role, and user mentions in the message content will not ping anyone. Disable only if you intentionally want the notification to ping.

Thread ID

DiscordNotify.ThreadId =

Optional ID of a thread (or forum post) in the webhook’s channel to post into. Leave blank to post to the channel itself.

Script body

Steps based on this template will execute the following Bash script.

#!/bin/bash

# Discord - Send Notification
# Posts a message and/or rich embed to a Discord channel via a webhook.
# API reference: https://discord.com/developers/docs/resources/webhook#execute-webhook

# Read step parameters
WebhookUrl=$(get_octopusvariable "DiscordNotify.WebhookUrl")
Content=$(get_octopusvariable "DiscordNotify.Content")
Username=$(get_octopusvariable "DiscordNotify.Username")
AvatarUrl=$(get_octopusvariable "DiscordNotify.AvatarUrl")
IncludeEmbed=$(get_octopusvariable "DiscordNotify.IncludeEmbed")
EmbedTitle=$(get_octopusvariable "DiscordNotify.EmbedTitle")
EmbedDescription=$(get_octopusvariable "DiscordNotify.EmbedDescription")
EmbedColor=$(get_octopusvariable "DiscordNotify.Color")
IncludeFields=$(get_octopusvariable "DiscordNotify.IncludeDeploymentFields")
SuppressMentions=$(get_octopusvariable "DiscordNotify.SuppressMentions")
ThreadId=$(get_octopusvariable "DiscordNotify.ThreadId")

# System variables used for the auto colour, detail fields, and deployment link
SysProjectName=$(get_octopusvariable "Octopus.Project.Name")
SysReleaseNumber=$(get_octopusvariable "Octopus.Release.Number")
SysEnvironmentName=$(get_octopusvariable "Octopus.Environment.Name")
SysDeploymentError=$(get_octopusvariable "Octopus.Deployment.Error")
SysServerUri=$(get_octopusvariable "Octopus.Web.ServerUri")
SysDeploymentLink=$(get_octopusvariable "Octopus.Web.DeploymentLink")

# Validate required tooling

if ! command -v curl >/dev/null 2>&1; then
  echo "ERROR: curl is required on the worker to run this step." >&2
  exit 1
fi

if command -v jq >/dev/null 2>&1; then
  JSON_TOOL="jq"
elif command -v python3 >/dev/null 2>&1; then
  JSON_TOOL="python3"
else
  echo "ERROR: jq or python3 is required on the worker to build and parse JSON." >&2
  exit 1
fi

# Prints the JSON-encoded (quoted) form of $1
json_escape() {
  if [[ "$JSON_TOOL" == "jq" ]]; then
    jq -cn --arg v "$1" '$v'
  else
    python3 -c 'import json,sys; print(json.dumps(sys.argv[1]))' "$1"
  fi
}

# Reads JSON on stdin and prints the value at dotted path $1 (empty if missing or null)
json_get() {
  if [[ "$JSON_TOOL" == "jq" ]]; then
    jq -r ".$1 // empty" 2>/dev/null
  else
    python3 -c '
import json, sys
try:
    data = json.load(sys.stdin)
except Exception:
    sys.exit(0)
cur = data
for part in sys.argv[1].split("."):
    if isinstance(cur, dict) and part in cur:
        cur = cur[part]
    else:
        sys.exit(0)
if cur is None:
    sys.exit(0)
print(cur if not isinstance(cur, (dict, list)) else json.dumps(cur))
' "$1"
  fi
}

# Truncates $1 to at most $2 characters, appending an ellipsis when cut
truncate_to() {
  local s="$1" max="$2"
  if (( ${#s} > max )); then
    echo "${s:0:$((max - 1))}…"
  else
    echo "$s"
  fi
}

# Validate required parameters

if [[ -z "$WebhookUrl" ]]; then
  echo "ERROR: WebhookUrl is required." >&2
  exit 1
fi

if [[ ! "$WebhookUrl" =~ ^https://(ptb\.|canary\.)?(discord|discordapp)\.com/api/webhooks/ ]]; then
  echo "ERROR: WebhookUrl does not look like a Discord webhook URL (expected https://discord.com/api/webhooks/...)." >&2
  exit 1
fi

if [[ -z "$Content" && "$IncludeEmbed" != "True" ]]; then
  echo "ERROR: Nothing to send. Provide Content, or enable Include Embed." >&2
  exit 1
fi

# Build the payload

PARTS=()

if [[ -n "$Content" ]]; then
  Content=$(truncate_to "$Content" 2000)
  PARTS+=("\"content\":$(json_escape "$Content")")
fi

[[ -n "$Username" ]] && PARTS+=("\"username\":$(json_escape "$Username")")
[[ -n "$AvatarUrl" ]] && PARTS+=("\"avatar_url\":$(json_escape "$AvatarUrl")")

if [[ "$SuppressMentions" == "True" ]]; then
  PARTS+=("\"allowed_mentions\":{\"parse\":[]}")
fi

if [[ "$IncludeEmbed" == "True" ]]; then
  EPARTS=()

  if [[ -n "$EmbedTitle" ]]; then
    EmbedTitle=$(truncate_to "$EmbedTitle" 256)
    EPARTS+=("\"title\":$(json_escape "$EmbedTitle")")
  fi

  if [[ -n "$EmbedDescription" ]]; then
    EmbedDescription=$(truncate_to "$EmbedDescription" 4096)
    EPARTS+=("\"description\":$(json_escape "$EmbedDescription")")
  fi

  # Link the embed title back to the deployment when running in a deployment context
  if [[ -n "$SysServerUri" && -n "$SysDeploymentLink" ]]; then
    EPARTS+=("\"url\":$(json_escape "${SysServerUri}${SysDeploymentLink}")")
  fi

  # Resolve the embed colour (Discord expects a decimal integer)
  case "$(echo "$EmbedColor" | tr '[:upper:]' '[:lower:]')" in
    auto)
    # Green unless the deployment has an error
    if [[ -n "$SysDeploymentError" ]]; then COLOR=15548997; else COLOR=5763719; fi
      ;;
    success) COLOR=5763719 ;;
    failure) COLOR=15548997 ;;
    warning) COLOR=16705372 ;;
    info|"") COLOR=5793266 ;;
    *)
      if [[ "$EmbedColor" =~ ^[0-9]+$ ]]; then
        COLOR="$EmbedColor"
      else
        echo "WARNING: Unrecognised Color '$EmbedColor'; using info blue." >&2
        COLOR=5793266
      fi
      ;;
  esac
  EPARTS+=("\"color\":$COLOR")

  EPARTS+=("\"timestamp\":\"$(date -u '+%Y-%m-%dT%H:%M:%SZ')\"")

  if [[ "$IncludeFields" == "True" ]]; then
    FIELDS=()
    [[ -n "$SysProjectName" ]] && FIELDS+=("{\"name\":\"Project\",\"value\":$(json_escape "$SysProjectName"),\"inline\":true}")
    [[ -n "$SysReleaseNumber" ]] && FIELDS+=("{\"name\":\"Release\",\"value\":$(json_escape "$SysReleaseNumber"),\"inline\":true}")
    [[ -n "$SysEnvironmentName" ]] && FIELDS+=("{\"name\":\"Environment\",\"value\":$(json_escape "$SysEnvironmentName"),\"inline\":true}")
    if (( ${#FIELDS[@]} > 0 )); then
      EPARTS+=("\"fields\":[$(IFS=,; echo "${FIELDS[*]}")]")
    fi
  fi

  PARTS+=("\"embeds\":[{$(IFS=,; echo "${EPARTS[*]}")}]")
fi

PAYLOAD="{$(IFS=,; echo "${PARTS[*]}")}"

# Build the URL. wait=true makes Discord return the created message so the
# message id can be captured as an output variable.

POST_URL="${WebhookUrl}?wait=true"
if [[ -n "$ThreadId" ]]; then
  POST_URL="${POST_URL}&thread_id=${ThreadId}"
fi

# Send, retrying on rate limiting (HTTP 429)

echo "Sending Discord notification..."
[[ -n "$Content" ]] && echo "  Content : $(truncate_to "$Content" 60)"
[[ "$IncludeEmbed" == "True" && -n "$EmbedTitle" ]] && echo "  Embed   : $EmbedTitle"
[[ -n "$ThreadId" ]] && echo "  Thread  : $ThreadId"
echo ""

MAX_ATTEMPTS=3
ATTEMPT=1

while true; do
  RAW=$(curl --silent --show-error --max-time 60 --write-out $'\n%{http_code}' \
    --request POST "$POST_URL" \
    --header "Content-Type: application/json" \
    --data "$PAYLOAD")

  CURL_EXIT=$?

  if [[ $CURL_EXIT -ne 0 ]]; then
    echo "ERROR: curl request failed (exit code $CURL_EXIT)." >&2
    exit 1
  fi

  HTTP_STATUS=$(echo "$RAW" | tail -n 1)
  RESPONSE=$(echo "$RAW" | sed '$d')

  if [[ "$HTTP_STATUS" == "429" ]]; then
    if (( ATTEMPT >= MAX_ATTEMPTS )); then
      echo "ERROR: Discord rate limited the webhook and retries were exhausted." >&2
      exit 1
    fi
    RETRY_AFTER=$(echo "$RESPONSE" | json_get "retry_after")
    # retry_after can be fractional seconds; round up in plain bash
    WHOLE="${RETRY_AFTER%%.*}"
    if [[ "$WHOLE" =~ ^[0-9]+$ ]]; then
      WAIT_SECONDS=$((WHOLE + 1))
    else
      WAIT_SECONDS=2
    fi
    echo "Rate limited (429); retrying in ${WAIT_SECONDS}s (attempt $((ATTEMPT + 1))/${MAX_ATTEMPTS})..."
    sleep "$WAIT_SECONDS"
    ATTEMPT=$((ATTEMPT + 1))
    continue
  fi

  break
done

if [[ "$HTTP_STATUS" -ge 400 ]]; then
  ERROR_MSG=$(echo "$RESPONSE" | json_get "message")
  ERROR_CODE=$(echo "$RESPONSE" | json_get "code")
  echo "ERROR: Discord API returned an error (HTTP $HTTP_STATUS)." >&2
  [[ -n "$ERROR_CODE" ]] && echo "  Code   : $ERROR_CODE" >&2
  [[ -n "$ERROR_MSG" ]] && echo "  Message: $ERROR_MSG" >&2
  exit 1
fi

MESSAGE_ID=$(echo "$RESPONSE" | json_get "id")

echo "Notification sent successfully."
[[ -n "$MESSAGE_ID" ]] && echo "  Message ID: $MESSAGE_ID"

set_octopusvariable "MessageId" "$MESSAGE_ID"

Provided under the Apache License version 2.0.

Report an issue

To use this template in Octopus Deploy, copy the JSON below and paste it into the Library → Step templates → Import dialog.

{
  "Id": "5adb6692-04b1-4475-800b-fbf0652696ed",
  "Name": "Discord - Send Notification",
  "Description": "Posts a message and/or rich embed to a [Discord](https://discord.com) channel via a [webhook](https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks). No Discord application or bot is required — create a webhook in the channel's settings (Integrations → Webhooks) and paste its URL into this step.\n\nThe embed can automatically colour itself green or red based on the deployment outcome (set Color to `auto` and use this step with a \"run always\" condition), include Project/Release/Environment fields, and link back to the deployment in Octopus.\n\nMentions (`@everyone`, roles, users) in message content are suppressed by default to prevent accidental pings from interpolated release notes.\n\nSets the output variable `MessageId` for use in later steps.\n\nRequires `curl` and either `jq` or `python3` on the worker.",
  "Version": 1,
  "ExportedAt": "2026-07-20T11:46:55.000Z",
  "ActionType": "Octopus.Script",
  "Author": "Meanski",
  "Packages": [],
  "Parameters": [
    {
      "Id": "6f5e5a78-6498-4102-ba10-357f5c1bd3fe",
      "Name": "DiscordNotify.WebhookUrl",
      "Label": "Webhook URL",
      "HelpText": "The Discord webhook URL (Channel Settings → Integrations → Webhooks). Consider binding this to a sensitive project variable (e.g. `#{Discord.WebhookUrl}`) so it can be scoped per environment and rotated in one place.",
      "DefaultValue": "",
      "DisplaySettings": {
        "Octopus.ControlType": "Sensitive"
      }
    },
    {
      "Id": "198f797b-fd12-4a25-b203-c6d3bf49b428",
      "Name": "DiscordNotify.Content",
      "Label": "Message Content",
      "HelpText": "Plain message text (supports Discord markdown). Optional when Include Embed is enabled. Maximum 2000 characters — longer values are truncated.",
      "DefaultValue": "",
      "DisplaySettings": {
        "Octopus.ControlType": "MultiLineText"
      }
    },
    {
      "Id": "6469aad0-ac4e-4a5d-a115-b1940bc6642a",
      "Name": "DiscordNotify.Username",
      "Label": "Username Override",
      "HelpText": "Overrides the webhook's configured display name. Leave blank to use the name configured on the webhook.",
      "DefaultValue": "",
      "DisplaySettings": {
        "Octopus.ControlType": "SingleLineText"
      }
    },
    {
      "Id": "b3609271-4cd3-4f63-96e7-a6726dd65828",
      "Name": "DiscordNotify.AvatarUrl",
      "Label": "Avatar URL Override",
      "HelpText": "Overrides the webhook's configured avatar image. Leave blank to use the avatar configured on the webhook.",
      "DefaultValue": "",
      "DisplaySettings": {
        "Octopus.ControlType": "SingleLineText"
      }
    },
    {
      "Id": "bc4073e3-43de-470f-9d21-20f25b9ede5c",
      "Name": "DiscordNotify.IncludeEmbed",
      "Label": "Include Embed",
      "HelpText": "If enabled, sends a rich embed with the title, description, colour, timestamp, a link to the deployment, and optional deployment detail fields.",
      "DefaultValue": "True",
      "DisplaySettings": {
        "Octopus.ControlType": "Checkbox"
      }
    },
    {
      "Id": "4b3767ac-56f1-4f93-8245-12bf07d09ed0",
      "Name": "DiscordNotify.EmbedTitle",
      "Label": "Embed Title",
      "HelpText": "Title of the embed. Maximum 256 characters — longer values are truncated.",
      "DefaultValue": "#{Octopus.Project.Name} release #{Octopus.Release.Number} deployed to #{Octopus.Environment.Name}",
      "DisplaySettings": {
        "Octopus.ControlType": "SingleLineText"
      }
    },
    {
      "Id": "61aa08a7-c638-49ce-b800-9ceb67ce8bac",
      "Name": "DiscordNotify.EmbedDescription",
      "Label": "Embed Description",
      "HelpText": "Body text of the embed (supports Discord markdown). Maximum 4096 characters — longer values are truncated.",
      "DefaultValue": "",
      "DisplaySettings": {
        "Octopus.ControlType": "MultiLineText"
      }
    },
    {
      "Id": "644b2cad-e521-4a1b-a1ab-287278f4d84e",
      "Name": "DiscordNotify.Color",
      "Label": "Color",
      "HelpText": "Colour of the embed's side bar. `auto` picks green or red based on whether the deployment has an error — useful with a \"run always\" step condition. A raw decimal colour value is also accepted.",
      "DefaultValue": "auto",
      "DisplaySettings": {
        "Octopus.ControlType": "Select",
        "Octopus.SelectOptions": "auto|Auto (green on success, red on failure)\nsuccess|Green\nfailure|Red\nwarning|Yellow\ninfo|Blue"
      }
    },
    {
      "Id": "0bc69655-4c3d-43a9-af89-c084d1fed3e5",
      "Name": "DiscordNotify.IncludeDeploymentFields",
      "Label": "Include Deployment Fields",
      "HelpText": "If enabled, adds Project, Release, and Environment fields to the embed (fields without a value, e.g. Release during a runbook run, are omitted).",
      "DefaultValue": "True",
      "DisplaySettings": {
        "Octopus.ControlType": "Checkbox"
      }
    },
    {
      "Id": "da6f5ef7-5c60-44c3-98fb-f727f6e11bdd",
      "Name": "DiscordNotify.SuppressMentions",
      "Label": "Suppress Mentions",
      "HelpText": "If enabled, `@everyone`, role, and user mentions in the message content will not ping anyone. Disable only if you intentionally want the notification to ping.",
      "DefaultValue": "True",
      "DisplaySettings": {
        "Octopus.ControlType": "Checkbox"
      }
    },
    {
      "Id": "06f05ca7-2f1c-4aa9-86ae-4eba79084040",
      "Name": "DiscordNotify.ThreadId",
      "Label": "Thread ID",
      "HelpText": "Optional ID of a thread (or forum post) in the webhook's channel to post into. Leave blank to post to the channel itself.",
      "DefaultValue": "",
      "DisplaySettings": {
        "Octopus.ControlType": "SingleLineText"
      }
    }
  ],
  "Properties": {
    "Octopus.Action.Script.ScriptSource": "Inline",
    "Octopus.Action.Script.Syntax": "Bash",
    "Octopus.Action.Script.ScriptBody": "#!/bin/bash\n\n# Discord - Send Notification\n# Posts a message and/or rich embed to a Discord channel via a webhook.\n# API reference: https://discord.com/developers/docs/resources/webhook#execute-webhook\n\n# Read step parameters\nWebhookUrl=$(get_octopusvariable \"DiscordNotify.WebhookUrl\")\nContent=$(get_octopusvariable \"DiscordNotify.Content\")\nUsername=$(get_octopusvariable \"DiscordNotify.Username\")\nAvatarUrl=$(get_octopusvariable \"DiscordNotify.AvatarUrl\")\nIncludeEmbed=$(get_octopusvariable \"DiscordNotify.IncludeEmbed\")\nEmbedTitle=$(get_octopusvariable \"DiscordNotify.EmbedTitle\")\nEmbedDescription=$(get_octopusvariable \"DiscordNotify.EmbedDescription\")\nEmbedColor=$(get_octopusvariable \"DiscordNotify.Color\")\nIncludeFields=$(get_octopusvariable \"DiscordNotify.IncludeDeploymentFields\")\nSuppressMentions=$(get_octopusvariable \"DiscordNotify.SuppressMentions\")\nThreadId=$(get_octopusvariable \"DiscordNotify.ThreadId\")\n\n# System variables used for the auto colour, detail fields, and deployment link\nSysProjectName=$(get_octopusvariable \"Octopus.Project.Name\")\nSysReleaseNumber=$(get_octopusvariable \"Octopus.Release.Number\")\nSysEnvironmentName=$(get_octopusvariable \"Octopus.Environment.Name\")\nSysDeploymentError=$(get_octopusvariable \"Octopus.Deployment.Error\")\nSysServerUri=$(get_octopusvariable \"Octopus.Web.ServerUri\")\nSysDeploymentLink=$(get_octopusvariable \"Octopus.Web.DeploymentLink\")\n\n# Validate required tooling\n\nif ! command -v curl >/dev/null 2>&1; then\n  echo \"ERROR: curl is required on the worker to run this step.\" >&2\n  exit 1\nfi\n\nif command -v jq >/dev/null 2>&1; then\n  JSON_TOOL=\"jq\"\nelif command -v python3 >/dev/null 2>&1; then\n  JSON_TOOL=\"python3\"\nelse\n  echo \"ERROR: jq or python3 is required on the worker to build and parse JSON.\" >&2\n  exit 1\nfi\n\n# Prints the JSON-encoded (quoted) form of $1\njson_escape() {\n  if [[ \"$JSON_TOOL\" == \"jq\" ]]; then\n    jq -cn --arg v \"$1\" '$v'\n  else\n    python3 -c 'import json,sys; print(json.dumps(sys.argv[1]))' \"$1\"\n  fi\n}\n\n# Reads JSON on stdin and prints the value at dotted path $1 (empty if missing or null)\njson_get() {\n  if [[ \"$JSON_TOOL\" == \"jq\" ]]; then\n    jq -r \".$1 // empty\" 2>/dev/null\n  else\n    python3 -c '\nimport json, sys\ntry:\n    data = json.load(sys.stdin)\nexcept Exception:\n    sys.exit(0)\ncur = data\nfor part in sys.argv[1].split(\".\"):\n    if isinstance(cur, dict) and part in cur:\n        cur = cur[part]\n    else:\n        sys.exit(0)\nif cur is None:\n    sys.exit(0)\nprint(cur if not isinstance(cur, (dict, list)) else json.dumps(cur))\n' \"$1\"\n  fi\n}\n\n# Truncates $1 to at most $2 characters, appending an ellipsis when cut\ntruncate_to() {\n  local s=\"$1\" max=\"$2\"\n  if (( ${#s} > max )); then\n    echo \"${s:0:$((max - 1))}…\"\n  else\n    echo \"$s\"\n  fi\n}\n\n# Validate required parameters\n\nif [[ -z \"$WebhookUrl\" ]]; then\n  echo \"ERROR: WebhookUrl is required.\" >&2\n  exit 1\nfi\n\nif [[ ! \"$WebhookUrl\" =~ ^https://(ptb\\.|canary\\.)?(discord|discordapp)\\.com/api/webhooks/ ]]; then\n  echo \"ERROR: WebhookUrl does not look like a Discord webhook URL (expected https://discord.com/api/webhooks/...).\" >&2\n  exit 1\nfi\n\nif [[ -z \"$Content\" && \"$IncludeEmbed\" != \"True\" ]]; then\n  echo \"ERROR: Nothing to send. Provide Content, or enable Include Embed.\" >&2\n  exit 1\nfi\n\n# Build the payload\n\nPARTS=()\n\nif [[ -n \"$Content\" ]]; then\n  Content=$(truncate_to \"$Content\" 2000)\n  PARTS+=(\"\\\"content\\\":$(json_escape \"$Content\")\")\nfi\n\n[[ -n \"$Username\" ]] && PARTS+=(\"\\\"username\\\":$(json_escape \"$Username\")\")\n[[ -n \"$AvatarUrl\" ]] && PARTS+=(\"\\\"avatar_url\\\":$(json_escape \"$AvatarUrl\")\")\n\nif [[ \"$SuppressMentions\" == \"True\" ]]; then\n  PARTS+=(\"\\\"allowed_mentions\\\":{\\\"parse\\\":[]}\")\nfi\n\nif [[ \"$IncludeEmbed\" == \"True\" ]]; then\n  EPARTS=()\n\n  if [[ -n \"$EmbedTitle\" ]]; then\n    EmbedTitle=$(truncate_to \"$EmbedTitle\" 256)\n    EPARTS+=(\"\\\"title\\\":$(json_escape \"$EmbedTitle\")\")\n  fi\n\n  if [[ -n \"$EmbedDescription\" ]]; then\n    EmbedDescription=$(truncate_to \"$EmbedDescription\" 4096)\n    EPARTS+=(\"\\\"description\\\":$(json_escape \"$EmbedDescription\")\")\n  fi\n\n  # Link the embed title back to the deployment when running in a deployment context\n  if [[ -n \"$SysServerUri\" && -n \"$SysDeploymentLink\" ]]; then\n    EPARTS+=(\"\\\"url\\\":$(json_escape \"${SysServerUri}${SysDeploymentLink}\")\")\n  fi\n\n  # Resolve the embed colour (Discord expects a decimal integer)\n  case \"$(echo \"$EmbedColor\" | tr '[:upper:]' '[:lower:]')\" in\n    auto)\n    # Green unless the deployment has an error\n    if [[ -n \"$SysDeploymentError\" ]]; then COLOR=15548997; else COLOR=5763719; fi\n      ;;\n    success) COLOR=5763719 ;;\n    failure) COLOR=15548997 ;;\n    warning) COLOR=16705372 ;;\n    info|\"\") COLOR=5793266 ;;\n    *)\n      if [[ \"$EmbedColor\" =~ ^[0-9]+$ ]]; then\n        COLOR=\"$EmbedColor\"\n      else\n        echo \"WARNING: Unrecognised Color '$EmbedColor'; using info blue.\" >&2\n        COLOR=5793266\n      fi\n      ;;\n  esac\n  EPARTS+=(\"\\\"color\\\":$COLOR\")\n\n  EPARTS+=(\"\\\"timestamp\\\":\\\"$(date -u '+%Y-%m-%dT%H:%M:%SZ')\\\"\")\n\n  if [[ \"$IncludeFields\" == \"True\" ]]; then\n    FIELDS=()\n    [[ -n \"$SysProjectName\" ]] && FIELDS+=(\"{\\\"name\\\":\\\"Project\\\",\\\"value\\\":$(json_escape \"$SysProjectName\"),\\\"inline\\\":true}\")\n    [[ -n \"$SysReleaseNumber\" ]] && FIELDS+=(\"{\\\"name\\\":\\\"Release\\\",\\\"value\\\":$(json_escape \"$SysReleaseNumber\"),\\\"inline\\\":true}\")\n    [[ -n \"$SysEnvironmentName\" ]] && FIELDS+=(\"{\\\"name\\\":\\\"Environment\\\",\\\"value\\\":$(json_escape \"$SysEnvironmentName\"),\\\"inline\\\":true}\")\n    if (( ${#FIELDS[@]} > 0 )); then\n      EPARTS+=(\"\\\"fields\\\":[$(IFS=,; echo \"${FIELDS[*]}\")]\")\n    fi\n  fi\n\n  PARTS+=(\"\\\"embeds\\\":[{$(IFS=,; echo \"${EPARTS[*]}\")}]\")\nfi\n\nPAYLOAD=\"{$(IFS=,; echo \"${PARTS[*]}\")}\"\n\n# Build the URL. wait=true makes Discord return the created message so the\n# message id can be captured as an output variable.\n\nPOST_URL=\"${WebhookUrl}?wait=true\"\nif [[ -n \"$ThreadId\" ]]; then\n  POST_URL=\"${POST_URL}&thread_id=${ThreadId}\"\nfi\n\n# Send, retrying on rate limiting (HTTP 429)\n\necho \"Sending Discord notification...\"\n[[ -n \"$Content\" ]] && echo \"  Content : $(truncate_to \"$Content\" 60)\"\n[[ \"$IncludeEmbed\" == \"True\" && -n \"$EmbedTitle\" ]] && echo \"  Embed   : $EmbedTitle\"\n[[ -n \"$ThreadId\" ]] && echo \"  Thread  : $ThreadId\"\necho \"\"\n\nMAX_ATTEMPTS=3\nATTEMPT=1\n\nwhile true; do\n  RAW=$(curl --silent --show-error --max-time 60 --write-out $'\\n%{http_code}' \\\n    --request POST \"$POST_URL\" \\\n    --header \"Content-Type: application/json\" \\\n    --data \"$PAYLOAD\")\n\n  CURL_EXIT=$?\n\n  if [[ $CURL_EXIT -ne 0 ]]; then\n    echo \"ERROR: curl request failed (exit code $CURL_EXIT).\" >&2\n    exit 1\n  fi\n\n  HTTP_STATUS=$(echo \"$RAW\" | tail -n 1)\n  RESPONSE=$(echo \"$RAW\" | sed '$d')\n\n  if [[ \"$HTTP_STATUS\" == \"429\" ]]; then\n    if (( ATTEMPT >= MAX_ATTEMPTS )); then\n      echo \"ERROR: Discord rate limited the webhook and retries were exhausted.\" >&2\n      exit 1\n    fi\n    RETRY_AFTER=$(echo \"$RESPONSE\" | json_get \"retry_after\")\n    # retry_after can be fractional seconds; round up in plain bash\n    WHOLE=\"${RETRY_AFTER%%.*}\"\n    if [[ \"$WHOLE\" =~ ^[0-9]+$ ]]; then\n      WAIT_SECONDS=$((WHOLE + 1))\n    else\n      WAIT_SECONDS=2\n    fi\n    echo \"Rate limited (429); retrying in ${WAIT_SECONDS}s (attempt $((ATTEMPT + 1))/${MAX_ATTEMPTS})...\"\n    sleep \"$WAIT_SECONDS\"\n    ATTEMPT=$((ATTEMPT + 1))\n    continue\n  fi\n\n  break\ndone\n\nif [[ \"$HTTP_STATUS\" -ge 400 ]]; then\n  ERROR_MSG=$(echo \"$RESPONSE\" | json_get \"message\")\n  ERROR_CODE=$(echo \"$RESPONSE\" | json_get \"code\")\n  echo \"ERROR: Discord API returned an error (HTTP $HTTP_STATUS).\" >&2\n  [[ -n \"$ERROR_CODE\" ]] && echo \"  Code   : $ERROR_CODE\" >&2\n  [[ -n \"$ERROR_MSG\" ]] && echo \"  Message: $ERROR_MSG\" >&2\n  exit 1\nfi\n\nMESSAGE_ID=$(echo \"$RESPONSE\" | json_get \"id\")\n\necho \"Notification sent successfully.\"\n[[ -n \"$MESSAGE_ID\" ]] && echo \"  Message ID: $MESSAGE_ID\"\n\nset_octopusvariable \"MessageId\" \"$MESSAGE_ID\""
  },
  "Category": "Discord",
  "HistoryUrl": "https://github.com/OctopusDeploy/Library/commits/master/step-templates/discord-send-notification.json",
  "Website": "/step-templates/5adb6692-04b1-4475-800b-fbf0652696ed",
  "Logo": "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",
  "$Meta": {
    "Type": "ActionTemplate"
  }
}

History

Page updated on Monday, July 20, 2026