Skip to content
DiscordTwitter

Template Messages Guide

This guide explains how to use template syntax to create dynamic, well-formatted notification messages in Telegram and Discord components.

Template messages allow you to create dynamic content by inserting data from your flow into notification messages. Instead of sending static text, you can include real-time data like prices, order details, or any other information flowing through your system.

Template Messages

Templates use Go’s template syntax with double curly braces {{ }}.

Use .fieldName to access data fields:

Symbol: {{ .symbol }}
Price: ${{ .price }}

Example Output:

Symbol: BTCUSDT
Price: $45678.90

If your data contains:

{
  "symbol": "ETHUSD",
  "price": 2345.67,
  "volume": 1234567
}

Template:

📊 {{ .symbol }} Update
💰 Price: ${{ .price }}
📈 Volume: {{ .volume }}

Output:

📊 ETHUSD Update
💰 Price: $2345.67
📈 Volume: 1234567

GrailHub provides built-in formatting functions to make your messages more readable.

Adds thousand separators to numbers.

Syntax: {{ formatNumber .fieldName }}

Examples:

Volume: {{ formatNumber .volume }}
InputOutput
12345671,234,567
1234.561,234.56
999999

Formats prices with appropriate decimal places based on value.

Syntax: {{ formatPrice .price }}

Formatting Rules:

  • Prices ≥ $1: 2 decimal places
  • Prices ≥ $0.01: 4 decimal places
  • Prices < $0.01: 8 decimal places

Examples:

Price: ${{ formatPrice .price }}
InputOutput
45678.945678.90
0.054320.0543
0.000012340.00001234

Formats Unix timestamps (milliseconds) to readable time (HH:MM:SS).

Syntax: {{ formatTime .timestamp }}

Examples:

Time: {{ formatTime .timestamp }}
Input (ms)Output
170419680000014:00:00
170418360000010:20:00

Formats Unix timestamps (milliseconds) to readable date and time.

Syntax: {{ formatDate .timestamp }}

Format: YYYY-MM-DD HH:MM:SS

Examples:

Executed at: {{ formatDate .timestamp }}
Input (ms)Output
17041968000002024-01-02 14:00:00
17041836000002024-01-02 10:20:00

Converts numbers to string format without scientific notation (e+).

Syntax: {{ formatString .fieldName }}

Examples:

Order ID: {{ formatString .order_id }}
Transaction ID: {{ formatString .transaction_id }}
InputOutput
1234567812345678
1.2345678e+0712345678
98765432109876543210

Converts text to UPPERCASE.

Syntax: {{ upper .text }}

Examples:

Status: {{ upper .status }}
Code: {{ upper .code }}
InputOutput
"active"ACTIVE
"pending"PENDING

Converts text to lowercase.

Syntax: {{ lower .text }}

Examples:

Username: {{ lower .username }}
Email: {{ lower .email }}
InputOutput
"ADMIN"admin
"User@Example.COM"user@example.com

Converts text to Title Case (first letter of each word capitalized).

Syntax: {{ title .text }}

Examples:

Name: {{ title .name }}
Status: {{ title .status }}
InputOutput
"john doe"John Doe
"order completed"Order Completed

Removes leading and trailing whitespace.

Syntax: {{ trim .text }}

Examples:

Message: {{ trim .message }}

Replaces all occurrences of a substring with another.

Syntax: {{ replace .text "old" "new" }}

Examples:

{{ replace .message "error" "warning" }}
{{ replace .path "/" "-" }}

Input: "Payment error occurred"
Output: "Payment warning occurred"

Checks if a string contains a substring.

Syntax: {{ if contains .text "substring" }}

Examples:

{{ if contains .status "success" }}
  ✅ Operation successful
{{ end }}

{{ if contains .email "@gmail.com" }}
  Gmail user detected
{{ end }}

Checks if a string starts with a prefix.

Syntax: {{ if hasPrefix .text "prefix" }}

Examples:

{{ if hasPrefix .code "ERR" }}
  ⚠️ Error code detected
{{ end }}

{{ if hasPrefix .id "ORD" }}
  Order ID format
{{ end }}

Checks if a string ends with a suffix.

Syntax: {{ if hasSuffix .text "suffix" }}

Examples:

{{ if hasSuffix .filename ".pdf" }}
  📄 PDF document
{{ end }}

{{ if hasSuffix .email ".com" }}
  Commercial email
{{ end }}

Extracts a portion of a string from start to end index.

Syntax: {{ substring .text start end }}

Examples:

Short code: {{ substring .code 0 5 }}
Preview: {{ substring .description 0 50 }}...

Input: "ABCDEFGHIJ" with substring .text 0 5
Output: "ABCDE"

Adds two numbers.

Syntax: {{ add .value1 .value2 }}

Examples:

Total: {{ add .subtotal .tax }}
Sum: {{ add 100 50 }}

Result: 150

Subtracts the second number from the first.

Syntax: {{ sub .value1 .value2 }}

Examples:

Remaining: {{ sub .total .used }}
Difference: {{ sub 100 30 }}

Result: 70

Multiplies two numbers.

Syntax: {{ mul .value1 .value2 }}

Examples:

Total: ${{ formatPrice (mul .price .quantity) }}
Area: {{ mul .width .height }}

Example: {{ mul 25 4 }} = 100

Divides the first number by the second.

Syntax: {{ div .value1 .value2 }}

Examples:

Average: {{ div .total .count }}
Per unit: ${{ formatPrice (div .total .quantity) }}

Example: {{ div 100 4 }} = 25

Returns the remainder of division.

Syntax: {{ mod .value1 .value2 }}

Examples:

{{ if eq (mod .count 2) 0 }}Even{{ else }}Odd{{ end }}
Remainder: {{ mod 17 5 }}

Example: {{ mod 17 5 }} = 2

Rounds a number to the nearest integer.

Syntax: {{ round .value }}

Examples:

Rounded: {{ round .average }}
Count: {{ formatNumber (round .estimate) }}
InputOutput
45.746
45.245
45.546

Rounds down to the nearest integer.

Syntax: {{ floor .value }}

Examples:

Minimum: {{ floor .value }}
InputOutput
45.945
45.145

Rounds up to the nearest integer.

Syntax: {{ ceil .value }}

Examples:

Maximum: {{ ceil .value }}
Pages needed: {{ ceil (div .items 10) }}
InputOutput
45.146
45.946

Returns the absolute value (removes negative sign).

Syntax: {{ abs .value }}

Examples:

Difference: {{ abs .change }}
Distance: {{ abs (sub .value1 .value2) }}
InputOutput
-5050
5050

Returns the smaller of two numbers.

Syntax: {{ min .value1 .value2 }}

Examples:

Minimum: {{ min .limit .available }}
Lower bound: {{ min .price .budget }}

Example: {{ min 100 75 }} = 75

Returns the larger of two numbers.

Syntax: {{ max .value1 .value2 }}

Examples:

Maximum: {{ max .required .available }}
Upper bound: {{ max .price .minimum }}

Example: {{ max 100 75 }} = 100

Provides a default value if the field is empty or zero.

Syntax: {{ default "defaultValue" .field }}

Examples:

Status: {{ default "Unknown" .status }}
Name: {{ default "Guest" .username }}
Count: {{ default 0 .count }}

Use case: Prevents empty fields from showing blank spaces.

Returns the length of a string or collection.

Syntax: {{ len .text }}

Examples:

Characters: {{ len .message }}
{{ if gt (len .password) 8 }}Strong password{{ end }}

Example: {{ len "Hello" }} = 5

When working with trading orders, use formatting functions for better readability.

📦 *New Order Update*

• *Order ID:* {{ .order_id }}
• *Symbol:* *{{ .symbol }}*
• *Side:* {{ .side }}
• *Type:* {{ .type }}

📊 *Order Details*
• *Quantity:* {{ formatNumber .quantity }}
• *Price:* ${{ formatPrice .price }}

📌 *Status:* *{{ .status }}*
⏱ *Time:* {{ formatDate .timestamp }}

Sample Output:

📦 *New Order Update*

• *Order ID:* 12345678
• *Symbol:* *BTCUSDT*
• *Side:* BUY
• *Type:* LIMIT

📊 *Order Details*
• *Quantity:* 1,500
• *Price:* $45,678.50

📌 *Status:* *FILLED*
⏱ *Time:* 2024-01-02 14:30:45

Use if statements to show content conditionally.

{{ if .condition }}
  This shows when condition is true
{{ end }}
{{ if gt .price 100 }}
  Price is high: ${{ .price }}
{{ else }}
  Price is low: ${{ .price }}
{{ end }}
OperatorDescriptionExample
eqEqual{{ if eq .status "FILLED" }}
neNot equal{{ if ne .status "CANCELED" }}
ltLess than{{ if lt .price 100 }}
leLess than or equal{{ if le .price 100 }}
gtGreater than{{ if gt .price 100 }}
geGreater than or equal{{ if ge .price 100 }}
🚨 *Price Alert*

{{ .symbol }} is now ${{ formatPrice .price }}

{{ if gt .price 50000 }}
  ⚠️ Price is above $50,000!
{{ else if gt .price 40000 }}
  📊 Price is between $40,000 and $50,000
{{ else }}
  ℹ️ Price is below $40,000
{{ end }}
📈 *{{ .symbol }} Update*

💰 Price: ${{ formatPrice .price }}
📊 Volume: {{ formatNumber .volume }}
🕐 {{ formatTime .timestamp }}
📊 *{{ .ticker }} Candle*

🟢 Open: ${{ formatPrice .open }}
🔴 Close: ${{ formatPrice .close }}
⬆️ High: ${{ formatPrice .high }}
⬇️ Low: ${{ formatPrice .low }}
📦 Volume: {{ formatNumber .volume }}
📖 *Order Book: {{ .symbol }}*

🟢 Best Bid: ${{ formatPrice .bids.0.price }}
🔴 Best Ask: ${{ formatPrice .asks.0.price }}
📊 Spread: ${{ formatPrice .spread }}
{{ if eq .side "BUY" }}
🟢 *BUY ORDER*
{{ else }}
🔴 *SELL ORDER*
{{ end }}

Symbol: {{ .symbol }}
Quantity: {{ formatNumber .quantity }}
Price: ${{ formatPrice .price }}
Total: ${{ formatPrice .total }}
{{ if eq .status "FILLED" }}
  ✅ Order Filled Successfully
{{ else if eq .status "PARTIALLY_FILLED" }}
  ⏳ Order Partially Filled
{{ else if eq .status "CANCELED" }}
  ❌ Order Canceled
{{ else if eq .status "REJECTED" }}
  🚫 Order Rejected
{{ else }}
  📝 Order {{ .status }}
{{ end }}

Order #{{ .order_id }}
{{ formatDate .timestamp }}
📊 *Trading Summary*

Symbol: {{ .symbol }}
Entry: ${{ formatPrice .entry_price }}
Current: ${{ formatPrice .current_price }}
Quantity: {{ formatNumber .quantity }}

{{ if gt .current_price .entry_price }}
  📈 Profit: ${{ formatPrice .profit }}
{{ else }}
  📉 Loss: ${{ formatPrice .loss }}
{{ end }}

Updated: {{ formatDate .timestamp }}

❌ Don’t:

Price: {{ .price }}
Volume: {{ .volume }}
Time: {{ .timestamp }}

✅ Do:

Price: ${{ formatPrice .price }}
Volume: {{ formatNumber .volume }}
Time: {{ formatDate .timestamp }}
📊 Market Update
💰 Price: ${{ formatPrice .price }}
📈 Change: {{ .change }}%
🕐 {{ formatTime .timestamp }}
Symbol: {{ .symbol }}
Side: {{ .side }}
Status: {{ .status }}

Use line breaks and spacing:

📦 *Order Confirmation*

Order ID: {{ .order_id }}
Symbol: {{ .symbol }}

Details:
• Quantity: {{ formatNumber .quantity }}
• Price: ${{ formatPrice .price }}
• Total: ${{ formatPrice .total }}

Status: {{ .status }}
Time: {{ formatDate .timestamp }}

Telegram supports different formatting modes:

No special formatting. Use for simple messages.

*Bold Text*
_Italic Text_
`Code Text`
[Link](https://example.com)
<b>Bold Text</b>
<i>Italic Text</i>
<code>Code Text</code>
<a href="https://example.com">Link</a>

Example with Markdown:

*📊 {{ .symbol }} Alert*

Price: *${{ formatPrice .price }}*
Volume: `{{ formatNumber .volume }}`

_Updated {{ formatTime .timestamp }}_
🚨 *Price Alert*

{{ .symbol }} has {{ if gt .change 0 }}risen{{ else }}fallen{{ end }} by {{ .change }}%

Current Price: ${{ formatPrice .price }}
24h Volume: {{ formatNumber .volume }}

{{ formatDate .timestamp }}
📦 *Order {{ .status }}*

#{{ .order_id }}
{{ .symbol }} - {{ .side }} {{ .type }}

Quantity: {{ formatNumber .quantity }}
{{ if ne .price 0 }}Price: ${{ formatPrice .price }}{{ end }}

{{ formatDate .timestamp }}
✅ *Trade Executed*

{{ .symbol }}
{{ .side }} {{ formatNumber .quantity }} @ ${{ formatPrice .price }}

Total: ${{ formatPrice .total }}
Fee: ${{ formatPrice .fee }}

{{ formatDate .timestamp }}

Problem: {{ .fieldname }} shows nothing

Solution: Check field name spelling and case sensitivity. Use the exact field name from your data.

Problem: Numbers show too many decimals

Solution: Use formatPrice for prices or formatNumber for quantities.

Problem: {{ .timestamp }} shows 1704196800000

Solution: Use formatDate or formatTime to convert timestamps.

Problem: if statement doesn’t work as expected

Solution: Check operator syntax. Use gt, lt, eq instead of >, <, ==.

  1. Start Simple: Begin with basic field access
  2. Add Formatting: Apply formatting functions one at a time
  3. Test Conditions: Verify conditional logic with different data
  4. Check Output: Send test messages to verify formatting

For more advanced template features, see the Go template documentation.