Why Telegram?

Email alerts get buried. Slack is overkill for a solo project or small team. PagerDuty has a pricing tier. Telegram is free, has a solid bot API, delivers messages instantly to your phone, and setting it up takes about 15 minutes.

This tutorial walks through creating a Telegram bot and building a reusable Ruby class to send notifications from your scripts and applications.


Step 1: Create a Bot via BotFather

Open Telegram and search for @BotFather. Start a conversation and run:

/newbot

BotFather will ask for a name (display name) and a username (must end in bot). After that, it gives you a token that looks like:

7412853690:AAHx3kFgPQ2vNmD8sLuYtR1WoZ4JcBqE5Vk

Save this token. You will need it in every API call.


Step 2: Get Your Chat ID

The bot needs to know where to send messages. Each chat (private or group) has a unique ID.

For a private chat:

  1. Open a conversation with your new bot and send it any message.
  2. Make an HTTP request to the getUpdates endpoint:
curl "https://api.telegram.org/bot<YOUR_TOKEN>/getUpdates"

The response is JSON. Look for message.chat.id:

{
  "result": [{
    "message": {
      "chat": {
        "id": 198765432,
        "type": "private"
      },
      "text": "hello"
    }
  }]
}

That number (198765432) is your chat ID.

For a group chat:

Add the bot to the group and send a message. The getUpdates response will include the group’s chat ID, which is a negative number like -1001234567890.


Step 3: Send a Test Message

Verify everything works before writing any Ruby:

curl -s -X POST "https://api.telegram.org/bot<YOUR_TOKEN>/sendMessage" \
  -d "chat_id=<YOUR_CHAT_ID>" \
  -d "text=Hello from the terminal" \
  -d "parse_mode=Markdown"

If you see the message arrive in Telegram, you are ready to move on.


Step 4: The TelegramNotifier Ruby Class

This class wraps the Telegram API with a clean interface:

require "net/http"
require "uri"
require "json"

class TelegramNotifier
  API_URL = "https://api.telegram.org/bot%s/sendMessage"

  def initialize(token: ENV["TELEGRAM_BOT_TOKEN"], chat_id: ENV["TELEGRAM_CHAT_ID"])
    @token   = token
    @chat_id = chat_id
  end

  def notify(message, level: :info)
    prefix = {
      info:    "INFO",
      success: "SUCCESS",
      warning: "WARNING",
      error:   "ERROR"
    }[level] || "INFO"

    send_message("[#{prefix}] #{message}")
  end

  private

  def send_message(text)
    uri = URI(format(API_URL, @token))

    response = Net::HTTP.post_form(uri, {
      "chat_id"    => @chat_id,
      "text"       => text,
      "parse_mode" => "Markdown"
    })

    unless response.is_a?(Net::HTTPSuccess)
      warn "TelegramNotifier: failed to send message (#{response.code})"
    end

    response
  rescue => e
    warn "TelegramNotifier: #{e.message}"
    nil
  end
end

Set the token and chat ID as environment variables:

export TELEGRAM_BOT_TOKEN="7412853690:AAHx3kFgPQ2vNmD8sLuYtR1WoZ4JcBqE5Vk"
export TELEGRAM_CHAT_ID="198765432"

Practical Examples

Backup notifications

notifier = TelegramNotifier.new

begin
  # Run backup logic
  `pg_dump myapp_production > /backups/db_#{Date.today}.sql`

  if $?.success?
    notifier.notify("Database backup completed: db_#{Date.today}.sql", level: :success)
  else
    notifier.notify("Database backup failed — check /backups/ directory", level: :error)
  end
rescue => e
  notifier.notify("Backup script crashed: #{e.message}", level: :error)
end

Deploy notifications

notifier = TelegramNotifier.new

notifier.notify("Deploy started — branch: #{ENV['BRANCH']} by #{ENV['USER']}", level: :info)

# ... deploy steps ...

notifier.notify("Deploy finished — #{ENV['BRANCH']} is live", level: :success)

Error alerts from a Rails app

In config/application.rb or an initializer:

# app/lib/telegram_notifier.rb — the class above

# In a rescue block or exception handler:
rescue => e
  TelegramNotifier.new.notify(
    "*Error in #{self.class}*\n`#{e.message}`",
    level: :error
  )
  raise
end

Or as middleware for unhandled exceptions:

# config/application.rb
config.exceptions_app = ->(env) do
  exception = env["action_dispatch.exception"]
  TelegramNotifier.new.notify("Unhandled exception: #{exception.message}", level: :error)
  [500, {}, ["Internal Server Error"]]
end

Monitoring cron job

A simple script that checks if a service is responding and sends an alert if not:

#!/usr/bin/env ruby
require_relative "telegram_notifier"
require "net/http"

SERVICES = {
  "API"       => "https://api.myapp.com/health",
  "Dashboard" => "https://app.myapp.com/health"
}

notifier = TelegramNotifier.new

SERVICES.each do |name, url|
  uri = URI(url)
  response = Net::HTTP.get_response(uri)

  unless response.is_a?(Net::HTTPSuccess)
    notifier.notify("#{name} is DOWN — HTTP #{response.code}", level: :error)
  end
rescue => e
  notifier.notify("#{name} is unreachable — #{e.message}", level: :error)
end

Add to crontab to run every 5 minutes:

*/5 * * * * /usr/bin/ruby /home/deploy/scripts/health_check.rb

Security Notes

  • Never hardcode the bot token in source code. Always use environment variables or a secrets manager.
  • If you add the bot to a group, anyone in that group can see the messages. Use private chats for sensitive system alerts.
  • Consider using parse_mode=MarkdownV2 if you need to send messages with special characters — MarkdownV2 has stricter escaping rules but better rendering.

Summary

StepWhat you do
Create botChat with @BotFather, run /newbot
Get chat_idSend a message to the bot, call getUpdates
TestUse curl to send a message
IntegrateUse the TelegramNotifier class from your scripts

Telegram bots are one of the lowest-friction notification solutions available. Once the class is in place, adding a notification to any script is a single line. For small projects and personal infrastructure, it is often all you need.


References