Blog

· 4 min read

Send announcements to Discord, Slack and Telegram with one API call

Broadcast release notes and announcements to a Discord channel, a Slack channel and a Telegram channel from your app, with one REST request and no developer apps to register.

Your community lives in three places: a Discord server, a Slack workspace and a Telegram channel. Every release, someone copies the same announcement into all three by hand. Usually it's late, sometimes it's missing from one of them, and the formatting is never quite right.

Automating it yourself means three different integrations:

  • Discord wants a JSON payload to a channel webhook, with images as embeds and a 2,000-character limit.
  • Slack wants a different payload shape to an incoming webhook URL.
  • Telegram wants a bot token, a chat ID, and a different method for text, photos, videos and albums.

This guide shows how to send the same announcement to all three with one request using Hapi. None of the three needs a developer app or a platform review, so you can be live in about ten minutes.

Step 1: Get a credential from each platform

Discord: open your server, go to Server Settings → Integrations → Webhooks → New Webhook, pick the channel (for example #announcements), and click Copy Webhook URL.

Slack: create an incoming webhook for your workspace and choose the channel it posts to (for example #launches). Copy the URL that starts with https://hooks.slack.com/services/.

Telegram: message @BotFather, send /newbot, and copy the bot token. Add the bot to your channel as an admin. Your chat ID is the channel's @username, or its numeric ID for private channels.

Step 2: Connect them in Hapi

Create a free Hapi account, open Accounts → Connect, and paste each credential. Hapi checks that each webhook URL is a real Discord or Slack webhook before saving it. Webhook URLs and bot tokens are encrypted at rest (AES-256-GCM) and never sent back to the browser, so nobody on your team can copy them out of the dashboard.

Then create an API key under API keys and put it in your environment:

bash
export HAPI_API_KEY="hapi_live_..."

Step 3: Send one announcement everywhere

bash
curl -X POST https://hapi.tools/v1/posts \
  -H "Authorization: Bearer $HAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: release-2-4-0" \
  -d '{
    "content": "v2.4 is out 🎉 Dark mode, CSV export and 3x faster search. Full notes: https://example.com/changelog",
    "platforms": ["discord", "slack", "telegram"],
    "mediaUrls": ["https://example.com/v2.4-banner.png"]
  }'

You get back a 201 with one result per channel, so you can see right away that the post landed in Discord, Slack and Telegram.

From your release pipeline (Node.js)

The most useful place for this call is the end of your deploy script, so announcements go out the moment a release ships:

js
await fetch("https://hapi.tools/v1/posts", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.HAPI_API_KEY}`,
    "Content-Type": "application/json",
    // Same key on a retried deploy = no duplicate announcement.
    "Idempotency-Key": `release-${process.env.RELEASE_VERSION}`,
  },
  body: JSON.stringify({
    content: `${process.env.RELEASE_VERSION} is live 🚀 ${process.env.RELEASE_NOTES_URL}`,
    platforms: ["discord", "slack", "telegram"],
  }),
});

The Idempotency-Key matters here. CI jobs get retried, and without it a flaky deploy can announce the same release three times.

Step 4: Tailor the message per channel

Your Slack workspace might be for customers while your Telegram channel is for the wider community. Use platformOptions to change the copy per channel in the same request:

json
{
  "content": "v2.4 is out 🎉 Dark mode, CSV export and 3x faster search.",
  "platforms": ["discord", "slack", "telegram"],
  "platformOptions": {
    "slack": { "content": "v2.4 is live for all workspaces. Dark mode, CSV export and faster search. Questions? Reply in this thread." },
    "telegram": { "content": "v2.4 is out 🎉 Dark mode, CSV export, 3x faster search. Changelog: https://example.com/changelog" }
  }
}

Hapi validates each version against that platform's limits before accepting the request. If your Discord copy runs past 2,000 characters, you find out now, not after the release.

Step 5: Schedule it for the right moment

Launching at 9am in your users' timezone, not whenever the deploy finished? Add a time:

json
{
  "content": "Launch day 🚀 v3.0 is here.",
  "platforms": ["discord", "slack", "telegram"],
  "scheduledAt": "2026-11-20T09:00:00-05:00",
  "timezone": "America/New_York"
}

None of these three platforms lets a webhook or bot schedule a message for later. Hapi holds the post and sends it on time, then fires a signed post.published or post.failed webhook to your app with the result for each channel.

Good to know

  • Images: Discord shows up to 10 images as embeds. Telegram sends a single photo or video, or an album of up to 10 when you attach several. With media attached, Telegram limits the caption to 1,024 characters, so keep image announcements short.
  • Telegram replies: add firstComment and Hapi posts it as a reply to your announcement. That's handy for a "discuss here" or "full changelog" follow-up.
  • Deleting: you can delete Discord and Telegram posts through DELETE /v1/posts/{id}. Slack incoming webhooks can't delete messages, so double-check Slack copy before it goes out.
  • More networks, same call: add "x", "linkedin" or "bluesky" to platforms to announce publicly at the same time.

What you skipped

  • Three payload formats and three sets of limits
  • Encrypting and storing webhook URLs and bot tokens safely
  • A scheduler, because none of these platforms schedules for you
  • Retries without duplicates, and per-channel failure reporting

Start your 15-day trial → The $5 trial covers 5 connected channels and 300 posts over 15 days: enough for Discord, Slack and Telegram from day one.