1.234 Bot SDK Frameworks#


Explainer

Bot SDK Frameworks - EXPLAINER#

Research ID: 1.234 Category: Self-Operated Tools - Bot Development Status: Complete (S1-S4 + Explainer) Date: 2026-02-05


What This Research Covers#

Comprehensive analysis of bot SDK frameworks for building interactive chat bots across 5 major platforms:

  1. Matrix (matrix-nio) - Python SDK
  2. Discord (discord.py) - Python SDK
  3. Telegram (python-telegram-bot) - Python SDK
  4. Nostr (nostr-tools) - JavaScript SDK
  5. Slack (slack-bolt) - Python SDK

Quick Decision Guide#

Choose this platform if…

PlatformChoose if…Avoid if…
MatrixPrivacy/E2EE critical, self-hosting requiredNeed interactive UI (buttons/forms), quick MVP needed
DiscordBest UX/DX priority, gaming/community focusPrivacy required, payments needed, enterprise SSO
TelegramMobile-first, payments/commerce, fastest MVPRich formatting needed, threading critical
NostrCensorship resistance, Bitcoin/Lightning integrationInteractive UI needed, large user base required
SlackEnterprise internal tool, workplace integrationConsumer bot, high message volume, budget constrained

Key Findings#

Architecture Patterns#

PlatformConnectionCommand ModelState Management
MatrixLong-pollingManual parsing (! prefix)SQLite store (E2EE)
DiscordWebSocketCommandTree (decorators)Cache-based
TelegramPolling/WebhookHandler-basedBuilt-in persistence
NostrWebSocket (multi-relay)Manual parsingStateless (client-side)
SlackSocket/HTTPListener-basedExternal (Redis/DB)

Performance Comparison#

PlatformThroughput (msg/s)LatencyMemory FootprintRate Limits
Matrix5-8~200-500ms15-60 MB10 req/s (matrix.org)
Discord20-40~50-150ms30-50 MB (minimal)50 req/s global
Telegram10-20~100-300ms20-30 MB30 msg/s per chat
Nostr10-50Varies10-15 MBRelay-dependent
Slack1-3~50ms40-60 MB1 msg/s per channel

Feature Matrix#

FeatureMatrixDiscordTelegramNostrSlack
Slash commandsNo (! prefix)NativeNativeNoNative
Interactive buttonsWidgetsViewsInline KBNoBlock Kit
E2E encryption✅ Full❌ None⚠️ DMs only⚠️ Weak❌ None
Self-hosting✅ Yes❌ No❌ No✅ Yes❌ No
Payments❌ No❌ Banned✅ Native✅ Lightning❌ No
Threading✅ Native✅ Forums❌ Limited⚠️ Via tags✅ Native

Use Case → Platform Mapping#

Winner: Matrix (matrix-nio) Reason: Only platform with bot E2EE support

High-Volume Notifications#

Winners: Discord (discord.py) or Telegram (PTB) Reason: 20-40 msg/s vs 1-3 msg/s (Slack)

Enterprise Internal Tool#

Winner: Slack (slack-bolt) Reason: SSO, audit logs, compliance features

Payments/Commerce#

Winners: Telegram (fiat) or Nostr (Bitcoin) Reason: Native payment APIs

Censorship-Resistant#

Winner: Nostr (nostr-tools) Reason: No central authority, relay redundancy

Mobile-First#

Winner: Telegram (PTB) Reason: 900M+ mobile users, best mobile UX

Developer Tools (CI/CD)#

Winners: Slack (teams) or Discord (OSS) Reason: Code formatting, threading, developer adoption


Technical Complexity Ranking#

Easiest → Hardest:

  1. Telegram (python-telegram-bot) - 2-4 hours to MVP

    • Handler-based routing
    • Built-in state persistence
    • Simple inline keyboards
  2. Discord (discord.py) - 2-4 hours to MVP

    • CommandTree abstraction
    • Rich Views for UI
    • Auto rate limit handling
  3. Slack (slack-bolt) - 4-8 hours to MVP

    • Decorator-based routing
    • Block Kit learning curve
    • Socket Mode for dev, webhooks for prod
  4. Matrix (matrix-nio) - 4-8 hours to MVP

    • Manual command parsing
    • E2EE setup complexity
    • SQLite store management
  5. Nostr (nostr-tools) - 4-8 hours to MVP

    • No command framework (DIY everything)
    • Manual event construction
    • Relay management complexity

Cost Analysis#

PlatformUser CostBot CostScaling Cost
MatrixFree (self-host)Server costs ($5-50/mo)Linear with traffic
DiscordFreeFreeFree (no bot fees)
TelegramFreeFreeFree (no bot fees)
NostrFreeFreeFree (decentralized)
Slack$8.75/user/moFree (dev)Expensive at scale

Key insight: Slack is 100x more expensive than alternatives for user-facing bots.


Risk Assessment#

Platform Stability (2026-2031)#

PlatformShutdown RiskAPI BreakagePolicy Tightening
SlackVery LowLowMedium
DiscordVery LowMediumHigh (verification)
TelegramLowLowMedium
MatrixVery Low (protocol)MediumVery Low
NostrNone (protocol)High (NIPs evolving)None

Recommendation: Abstract platform logic early (adapter pattern) to mitigate API breakage risk.


Research Structure#

packages/research/1.234-bot-sdk-frameworks/
├── EXPLAINER.md (this file)
├── metadata.yaml
└── 01-discovery/
    ├── S1-rapid/
    │   └── recommendations-synthesis.md (Quick comparison + code examples)
    ├── S2-comprehensive/
    │   ├── approach.md
    │   ├── discord-py.md (Architecture, API, performance deep-dive)
    │   ├── matrix-nio.md
    │   ├── python-telegram-bot.md
    │   ├── nostr-tools.md
    │   └── slack-bolt.md
    ├── S3-need-driven/
    │   └── use-case-analysis.md (8 use cases + decision tree)
    └── S4-strategic/
        └── ecosystem-analysis.md (Market trends, 5-year outlook)

When to Read Each Phase#

S1 (Rapid): Start here

  • Need: Quick decision, code examples
  • Time: 10 minutes
  • Output: Platform recommendation + starter code

S2 (Comprehensive): Deep dive into specific platform

  • Need: Understand architecture, performance, trade-offs
  • Time: 30-60 minutes per platform
  • Output: Production deployment knowledge

S3 (Need-Driven): Map requirements to platforms

  • Need: “Which platform for my use case?”
  • Time: 20 minutes
  • Output: Use case → platform mapping

S4 (Strategic): Long-term planning

  • Need: Multi-year roadmap, market trends
  • Time: 45 minutes
  • Output: Risk assessment, future-proofing strategy

Common Gotchas#

Matrix#

  • E2EE requires persistent store - bot loses keys on restart without SqliteStore
  • No native slash commands - use ! prefix, confusing for users expecting /
  • Widgets are complex - interactive buttons require embedding web UI

Discord#

  • Privileged intents require approval - >75 guilds needs verification
  • Cache can be huge - 1000 guilds × 1000 members = 1 GB RAM
  • Command sync delay - global commands take ~1 hour to propagate

Telegram#

  • No native threading - replies via inline keyboards, not ideal for discussions
  • Callback data limited to 64 bytes - use short IDs, store data in bot_data
  • Group rate limits strict - 20 msg/minute for broadcasts

Nostr#

  • No command framework - implement all parsing/routing yourself
  • Relays go offline - connect to 10+ relays for redundancy
  • No interactive UI - protocol limitation, text + reactions only

Slack#

  • 3-second ack timeout - must call ack() immediately in handlers
  • Rate limits strict - 1 msg/s per channel
  • Expensive - $8.75/user/month minimum

Next Steps#

If implementing a bot:#

  1. Read S1 for quick platform selection
  2. Read S3 use case analysis for your specific requirements
  3. Read S2 comprehensive analysis for chosen platform
  4. Prototype with starter code from S1
  5. Production prep with deployment considerations from S2

If evaluating strategically:#

  1. Read S4 for market trends and long-term outlook
  2. Read S3 for decision framework
  3. Monitor platform changelogs for policy/API changes
  4. Abstract platform logic (adapter pattern) for multi-platform optionality

  • 1.173: Terminology Extraction - For extracting keywords from bot commands
  • 1.166: Text Classification - For intent detection in bot messages
  • 1.234.x (future): Platform-specific advanced patterns (Discord Views, Telegram Mini Apps, etc.)

Maintenance Notes#

Last updated: 2026-02-05 Reviewer: Ivan (Research Crew) Confidence: High (all 5 platforms analyzed in production contexts)

Update triggers:

  • Major SDK version releases (breaking changes)
  • Platform policy updates (new restrictions/features)
  • Market shifts (acquisitions, shutdowns)

Next review: 2026-Q3 (6 months)

S1: Rapid Discovery

S1 Rapid Discovery: Bot SDK Frameworks#

Date: 2025-12-22 Methodology: S1 - Rapid practical comparison Category: 1.234 (Bot SDK Frameworks) Scope: Bot development SDKs for major chat platforms


Executive Summary#

Comparison of bot SDKs for building interactive bots (commands, buttons, integrations):

PlatformRecommended SDKLanguageTime to MVPBest For
Matrixmatrix-nioPython4-8 hoursPrivacy, self-hosting
Discorddiscord.pyPython2-4 hoursInteractive UX
Telegrampython-telegram-botPython2-4 hoursMobile-first
Nostrnostr-toolsJavaScript4-8 hoursCensorship resistance
Slackslack-boltPython4-8 hoursEnterprise

Matrix Bot SDKs#

matrix-nio (Python)#

Overview: Async Python SDK for Matrix, supports E2EE.

Installation:

pip install matrix-nio[e2e]

Basic Bot Example:

import asyncio
from nio import AsyncClient, RoomMessageText

class Bot:
    def __init__(self, homeserver, user_id, password):
        self.client = AsyncClient(homeserver, user_id)
        self.password = password

    async def message_callback(self, room, event):
        if event.body.startswith("!hello"):
            await self.client.room_send(
                room.room_id,
                "m.room.message",
                {"msgtype": "m.text", "body": "Hello!"}
            )

    async def run(self):
        await self.client.login(self.password)
        self.client.add_event_callback(self.message_callback, RoomMessageText)
        await self.client.sync_forever(timeout=30000)

bot = Bot("https://matrix.org", "@bot:matrix.org", "password")
asyncio.run(bot.run())

Features:

FeatureSupport
Text commandsNative (! prefix convention)
Slash commandsNot protocol-native
Interactive buttonsVia widgets (complex)
ReactionsNative
E2E EncryptionFull support
File uploadsNative

Strengths:

  • Async-first design
  • E2EE support built-in
  • Well-documented
  • Self-hostable platform

Weaknesses:

  • No native slash commands (Matrix protocol limitation)
  • Interactive buttons require widget complexity
  • Learning curve for Matrix concepts

Time to MVP: 4-8 hours


matrix-bot-sdk (TypeScript)#

Overview: Official TypeScript SDK for Matrix bots.

import { MatrixClient, SimpleFsStorageProvider, AutojoinRoomsMixin } from "matrix-bot-sdk";

const client = new MatrixClient(
    "https://matrix.org",
    "access_token",
    new SimpleFsStorageProvider("bot.json")
);

AutojoinRoomsMixin.setupOnClient(client);

client.on("room.message", async (roomId, event) => {
    if (event.content.body?.startsWith("!hello")) {
        await client.sendText(roomId, "Hello!");
    }
});

client.start().then(() => console.log("Bot started"));

Time to MVP: 4-8 hours


Discord Bot SDKs#

discord.py (Python)#

Overview: Most popular Python Discord library, excellent slash command support.

Installation:

pip install discord.py

Slash Commands Example:

import discord
from discord import app_commands

class Bot(discord.Client):
    def __init__(self):
        super().__init__(intents=discord.Intents.default())
        self.tree = app_commands.CommandTree(self)

    async def setup_hook(self):
        await self.tree.sync()

client = Bot()

@client.tree.command(name="hello", description="Say hello")
async def hello(interaction: discord.Interaction):
    await interaction.response.send_message("Hello!")

@client.tree.command(name="greet", description="Greet someone")
@app_commands.describe(name="Who to greet")
async def greet(interaction: discord.Interaction, name: str):
    embed = discord.Embed(title=f"Hello {name}!", color=0x00ff00)
    await interaction.response.send_message(embed=embed)

client.run("BOT_TOKEN")

Interactive Buttons Example:

class ConfirmView(discord.ui.View):
    @discord.ui.button(label="Confirm", style=discord.ButtonStyle.success)
    async def confirm(self, interaction: discord.Interaction, button: discord.ui.Button):
        await interaction.response.edit_message(content="Confirmed!", view=None)

    @discord.ui.button(label="Cancel", style=discord.ButtonStyle.danger)
    async def cancel(self, interaction: discord.Interaction, button: discord.ui.Button):
        await interaction.response.edit_message(content="Cancelled", view=None)

Features:

FeatureSupport
Slash commandsExcellent (native)
Interactive buttonsExcellent (Views)
Dropdowns/SelectsNative
Modals/FormsNative
EmbedsRich formatting
File uploadsNative

Strengths:

  • Best slash command UX
  • Excellent interactive components
  • Large community
  • Well-documented

Weaknesses:

  • Requires bot verification for >100 servers
  • No self-hosting (centralized platform)

Time to MVP: 2-4 hours


Telegram Bot SDKs#

python-telegram-bot#

Overview: Feature-complete Python wrapper for Telegram Bot API.

Installation:

pip install python-telegram-bot

Example:

from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import Application, CommandHandler, CallbackQueryHandler, ContextTypes

async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
    keyboard = [[
        InlineKeyboardButton("Option 1", callback_data="1"),
        InlineKeyboardButton("Option 2", callback_data="2")
    ]]
    reply_markup = InlineKeyboardMarkup(keyboard)
    await update.message.reply_text("Choose:", reply_markup=reply_markup)

async def button_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    await query.answer(f"You selected {query.data}")

app = Application.builder().token("BOT_TOKEN").build()
app.add_handler(CommandHandler("start", start))
app.add_handler(CallbackQueryHandler(button_callback))
app.run_polling()

Features:

FeatureSupport
Slash commandsNative (/command)
Inline keyboardsExcellent
Reply keyboardsNative
Inline modeNative
File uploadsNative
Mini AppsWebApp support

Strengths:

  • Best mobile experience
  • Excellent inline keyboards
  • Simple API
  • Large user base (900M+)

Weaknesses:

  • Centralized platform
  • No self-hosting

Time to MVP: 2-4 hours


Nostr Bot SDKs#

nostr-tools (JavaScript)#

Overview: Core JavaScript library for Nostr protocol.

Installation:

npm install nostr-tools

Bot Example:

import { SimplePool, getPublicKey, finalizeEvent } from 'nostr-tools';

const sk = "private_key_hex";
const pk = getPublicKey(sk);
const pool = new SimplePool();

const relays = [
    'wss://relay.damus.io',
    'wss://relay.nostr.band'
];

// Subscribe to mentions
pool.subscribeMany(relays, [{
    kinds: [1],
    '#p': [pk],
    since: Math.floor(Date.now() / 1000)
}], {
    onevent(event) {
        if (event.content.includes('!hello')) {
            const reply = finalizeEvent({
                kind: 1,
                created_at: Math.floor(Date.now() / 1000),
                tags: [['e', event.id], ['p', event.pubkey]],
                content: "Hello!"
            }, sk);
            relays.forEach(r => pool.publish([r], reply));
        }
    }
});

Features:

FeatureSupport
Text commandsVia mentions
Slash commandsNot protocol-native
Interactive buttonsNot supported
ReactionsKind 7 events
Zaps (payments)NIP-57
E2E encryptionNot built-in

Strengths:

  • Censorship resistant
  • Lightning payments native
  • Simple protocol
  • No platform approval

Weaknesses:

  • No interactive components
  • Smaller user base
  • Key management complexity

Time to MVP: 4-8 hours


Slack Bot SDK#

slack-bolt (Python)#

Overview: Official Python SDK for Slack apps.

from slack_bolt import App
from slack_bolt.adapter.socket_mode import SocketModeHandler

app = App(token="xoxb-...")

@app.command("/hello")
def handle_hello(ack, command, client):
    ack()
    client.chat_postMessage(
        channel=command["channel_id"],
        text="Hello!"
    )

@app.action("button_click")
def handle_button(ack, body, client):
    ack()
    # Handle button click

handler = SocketModeHandler(app, "xapp-...")
handler.start()

Features:

FeatureSupport
Slash commandsExcellent
Interactive buttonsBlock Kit
ModalsNative
Rich formattingBlock Kit

Strengths:

  • Enterprise adoption
  • Excellent documentation
  • Rich UI components

Weaknesses:

  • Per-user cost ($8.75/mo Pro)
  • Admin API gated to Enterprise
  • Platform lock-in

Time to MVP: 4-8 hours


Feature Comparison Matrix#

FeatureMatrixDiscordTelegramNostrSlack
Slash commands! prefixNativeNativeNoNative
Interactive buttonsWidgetsViewsInline KBNoBlock Kit
DropdownsWidgetsNativeNativeNoNative
Modals/FormsNoNativeNoNoNative
Rich embedsHTMLEmbedsMarkdownNoBlocks
E2E encryptionYesNoNoNoNo
Self-hostingYesNoNoYesNo
PaymentsNoNoNoZapsNo
Python SDKYesYesYesNoYes

Decision Guide#

Choose Matrix when:

  • Privacy/E2EE is required
  • Self-hosting is important
  • Building for open/federated ecosystem

Choose Discord when:

  • Best UX is priority
  • Building for gaming/community
  • Need rich interactive components

Choose Telegram when:

  • Mobile-first experience needed
  • Large existing user base
  • Quick MVP required

Choose Nostr when:

  • Censorship resistance required
  • Lightning payments needed
  • Building for Bitcoin community

Choose Slack when:

  • Enterprise/workplace focus
  • Existing Slack workspace
  • Rich workflow automation needed

Sources#

S2: Comprehensive

S2 Comprehensive: Approach#

Date: 2026-02-05 Methodology: S2 - Comprehensive technical analysis Scope: Deep technical comparison of bot SDK frameworks

Research Question#

How do major bot SDK frameworks differ in architecture, API design, performance characteristics, and implementation patterns?

Libraries Under Analysis#

  1. Matrix - matrix-nio (Python)
  2. Discord - discord.py (Python)
  3. Telegram - python-telegram-bot (Python)
  4. Nostr - nostr-tools (JavaScript)
  5. Slack - slack-bolt (Python)

Analysis Dimensions#

Architecture Patterns#

  • Event-driven vs polling architectures
  • Sync vs async execution models
  • State management approaches
  • Connection handling (WebSocket, long polling, webhooks)

API Design#

  • Command registration patterns
  • Event callback systems
  • Message builder abstractions
  • Error handling strategies

Performance Characteristics#

  • Message throughput benchmarks
  • Memory footprint
  • Connection overhead
  • Rate limiting handling

Feature Completeness#

  • Interactive components (buttons, menus, forms)
  • Rich media support
  • E2E encryption
  • Multi-device sync
  • File handling

Method#

Each library analysis includes:

  1. Architecture overview - Core design patterns and runtime model
  2. API patterns - Code examples showing typical usage patterns
  3. Performance profile - Benchmarks and resource requirements
  4. Feature matrix - Capability comparison across implementations
  5. Integration patterns - How bots integrate with platform features

Sources#

  • Official SDK documentation
  • GitHub repositories and issue trackers
  • Platform API specifications
  • Performance benchmarks from community testing
  • Production bot implementations

discord.py - S2 Comprehensive Analysis#

Library: discord.py Language: Python Platform: Discord Version Analyzed: 2.3.2 Date: 2026-02-05


Architecture Overview#

Core Design Pattern#

discord.py implements an event-driven async architecture with rich command abstractions:

  • Client: Base connection manager (low-level)
  • Bot: Extended client with command framework
  • CommandTree: Slash command registration and dispatch
  • Cogs: Plugin system for organizing commands

Runtime Model#

Bot Lifecycle:
┌─────────────┐
│   Bot       │──→ login() ──→ Gateway handshake
└─────────────┘        ↓
       ↓          Receive READY event
    Gateway WS         ↓
       ↓          Dispatch events to handlers
    [Loop]            ↓
                  Command tree routes slash commands

Connection: Discord uses WebSocket gateway (not polling). Single persistent WS connection receives all events in real-time.

State Management#

Cache-based state (automatic):

  • Guilds (servers) and channels cached on READY
  • Members cached per guild (configurable via Intents)
  • Messages cached (last 100 per channel by default)

Cache implications:

  • Large bots (1000+ guilds): 500 MB - 2 GB memory for full member cache
  • Privileged intents required for full member cache (needs Discord approval)

State persistence: discord.py doesn’t persist state to disk. On restart, bot rejoins gateway and receives fresh state.


API Design#

Command Registration Pattern#

Slash commands (modern approach):

from discord import app_commands

@bot.tree.command(name="hello", description="Say hello")
async def hello(interaction: discord.Interaction):
    await interaction.response.send_message("Hello!")

# Command with parameters
@bot.tree.command()
@app_commands.describe(count="Number of times to greet")
async def greet(interaction: discord.Interaction, count: int):
    await interaction.response.send_message(f"Hello! " * count)

Key features:

  • Type-safe parameter extraction (Discord validates types client-side)
  • Auto-generated help text from descriptions
  • Global sync: Commands registered globally or per-guild

Command sync:

await bot.tree.sync()  # Global (takes ~1 hour to propagate)
await bot.tree.sync(guild=discord.Object(id=123))  # Guild-specific (instant)

Legacy text commands (prefix-based):

@bot.command()
async def ping(ctx):
    await ctx.send("Pong!")

Still supported but Discord deprecated prefix commands in UI (no autocomplete, no type validation).

Event Callback System#

Decorator-based events:

@bot.event
async def on_message(message):
    if message.author.bot:
        return
    # Process message

@bot.event
async def on_reaction_add(reaction, user):
    # Handle reaction

Event hierarchy: Discord emits ~70 event types (message, member, guild, voice, etc.). You implement handlers for events you care about.

Callback signature: Events have specific signatures (on_message gets Message object, on_reaction_add gets Reaction + User).

Message Builder Abstraction#

Embed builder:

embed = discord.Embed(
    title="Title",
    description="Description",
    color=0x00ff00
)
embed.add_field(name="Field 1", value="Value 1")
embed.set_thumbnail(url="https://...")

await interaction.response.send_message(embed=embed)

Rich builder pattern: Fluent API for constructing complex embeds. Contrast with matrix-nio’s raw dict construction.

Interactive components:

class MyView(discord.ui.View):
    @discord.ui.button(label="Click me", style=discord.ButtonStyle.primary)
    async def button_callback(self, interaction, button):
        await interaction.response.send_message("Clicked!")

    @discord.ui.select(options=[
        discord.SelectOption(label="Option 1", value="1"),
        discord.SelectOption(label="Option 2", value="2")
    ])
    async def select_callback(self, interaction, select):
        await interaction.response.send_message(f"Selected: {select.values[0]}")

await interaction.response.send_message("Choose:", view=MyView())

Component lifecycle: Views can have timeout (auto-disable after X seconds), persistent views (survive bot restarts).

Error Handling Strategy#

Exception-based errors:

try:
    await interaction.response.send_message("Message")
except discord.Forbidden:
    # Bot lacks permissions
except discord.HTTPException as e:
    # API error
    logger.error(f"HTTP {e.status}: {e.text}")

Command error handler:

@bot.tree.error
async def on_app_command_error(interaction, error):
    if isinstance(error, app_commands.CommandNotFound):
        await interaction.response.send_message("Unknown command")

Automatic retry: discord.py retries failed requests (5xx errors) with exponential backoff.


Performance Characteristics#

Message Throughput#

WebSocket advantages:

  • Low latency: ~50-150ms from event to bot (vs 200-500ms for polling)
  • No polling overhead: Single WS connection handles all events

Rate limits (per bot token):

  • 50 requests/second globally
  • 5 requests/second per channel
  • Special limits for bulk operations (bulk delete, ban/kick)

Practical throughput: 20-40 messages/second sustainable (respecting per-channel limits).

Memory Footprint#

Minimal config (no intents): ~30-50 MB Full member cache (large bot): 500 MB - 2 GB

Memory scaling:

  • ~500 KB per guild (metadata + channels)
  • ~1 KB per cached member
  • ~10 KB per cached message (100 messages/channel default)

Large bot example: 1000 guilds × 1000 members/guild = ~1 GB member cache

Connection Overhead#

Startup cost:

  1. Gateway handshake: ~500ms
  2. READY event: 1-5s (sends all guild data)
  3. Guild streaming: Large bots get guilds in chunks

Keepalive: Discord sends heartbeat every 41.25s. Bot must respond or gateway closes connection.

Rate Limiting Handling#

Per-route buckets: Discord uses complex rate limit bucketing (different limits for different endpoints).

discord.py automatically handles rate limits:

  • Pre-emptive rate limiting (tracks bucket state, doesn’t send if limit reached)
  • Queues requests exceeding limits
  • Waits for bucket reset before sending

Global rate limit: If bot hits global 50 req/s limit, all requests queue until window resets.

Transparent to bot code - you don’t implement retry logic.


Feature Completeness#

Interactive Components#

FeatureSupportNotes
ButtonsNative (Views)Up to 5 buttons per row, 5 rows per message
Select menusNativeSingle/multi-select, up to 25 options
ModalsNativePop-up forms with text inputs
AutocompleteNativeDynamic options for slash command params

View persistence:

class PersistentView(discord.ui.View):
    def __init__(self):
        super().__init__(timeout=None)  # Never times out

    @discord.ui.button(label="Persistent", custom_id="persistent_button")
    async def callback(self, interaction, button):
        await interaction.response.send_message("Still works after restart!")

# Register on bot startup
bot.add_view(PersistentView())

Custom IDs enable views to survive bot restarts (Discord stores component state, bot re-registers handlers).

Rich Media Support#

  • Embeds: Rich cards with title, description, fields, images, thumbnails
  • Images/Videos: Direct upload or URL reference
  • File attachments: Up to 25 MB (100 MB for Nitro users)
  • Stickers: Native sticker support

File upload:

file = discord.File("image.png")
await interaction.response.send_message("Image:", file=file)

E2E Encryption#

Not supported. Discord doesn’t offer E2EE for any messages (bot or user).

Privacy implication: Discord can read all messages. Not suitable for privacy-critical use cases.

Multi-Device Sync#

Not applicable to bots (bots run on single instance, not user accounts).

User accounts sync across devices, but bot tokens don’t represent user accounts.

File Handling#

Upload:

await channel.send(file=discord.File("file.pdf", filename="document.pdf"))

Single-step upload (vs matrix-nio’s two-step upload → send).

CDN caching: Uploaded files hosted on Discord’s CDN (permanent URLs unless deleted).


Integration Patterns#

Bot Registration#

  1. Create bot application at Discord Developer Portal
  2. Generate bot token
  3. Configure OAuth2 scopes (bot, applications.commands)
  4. Generate invite URL, add bot to guilds

Privileged intents (requires approval for >100 guilds):

  • GUILD_MEMBERS (member join/leave events)
  • GUILD_PRESENCES (online status)
  • MESSAGE_CONTENT (read message content)

Why approval needed? Privacy concerns (large bots can scrape member data).

Webhook Support#

Discord webhooks (alternative to bots):

# Bots can create webhooks
webhook = await channel.create_webhook(name="Bot Webhook")

# Post via webhook (appears as separate user)
await webhook.send("Message from webhook")

Webhook limitations:

  • Can’t receive events (send-only)
  • Can’t use slash commands
  • Can’t access full API (limited to sending messages)

Use case: External services posting to Discord (CI/CD notifications, monitoring alerts).

Admin API Access#

Bot permissions (configurable per guild):

  • Manage channels, roles, messages
  • Ban/kick members
  • Administrator (full access)

Permission integers: Discord uses bitfield permissions (combine with bitwise OR).

Requires guild owner approval when inviting bot.

Sharding#

Large bot requirement (2500+ guilds):

# Discord requires sharding at scale
bot = commands.AutoShardedBot(command_prefix="!", intents=intents)

How sharding works:

  • Discord assigns guilds to shards (shard 0 gets guilds 0-999, shard 1 gets 1000-1999, etc.)
  • Each shard = separate gateway connection
  • Bot code runs in single process, library manages shards

Manual sharding (advanced):

# Run separate processes for each shard
bot = commands.Bot(..., shard_id=0, shard_count=4)  # Process 1
bot = commands.Bot(..., shard_id=1, shard_count=4)  # Process 2

When to shard: >2500 guilds (Discord enforces), or >150k members cached.


Comparison Insights#

Strengths relative to other platforms:

  • Best interactive UX (Views, Modals, Autocomplete)
  • Native command framework (CommandTree vs manual parsing)
  • Automatic rate limit handling (vs manual implementation)
  • Rich embed system (best formatting of all platforms)

Weaknesses relative to other platforms:

  • No E2EE (Matrix has it)
  • No self-hosting (centralized platform)
  • Privileged intents (friction for large bots)
  • Bot verification (required for >75 guilds with privileged intents)

Architecture comparison:

  • vs matrix-nio: WebSocket (lower latency) vs long-polling
  • vs python-telegram-bot: Views (class-based components) vs inline keyboards (dict-based)
  • vs slack-bolt: Similar WebSocket approach, but Discord has richer component library

Production Deployment Considerations#

High Availability#

Single-instance architecture: discord.py maintains WS connection, can’t easily run multiple instances (gateway would spawn multiple connections).

HA approaches:

  • Blue-green deployment (new instance connects, old disconnects)
  • Run multiple bots with different tokens (manual work distribution)

Stateless design: Bot should store minimal state (rely on Discord’s cache, externalize user data to database).

Monitoring#

Key metrics:

  • Gateway latency (bot.latency)
  • Command invocation rate
  • Error rate by command
  • Shard status (if sharded)

Built-in stats:

@bot.event
async def on_ready():
    logger.info(f"Latency: {bot.latency * 1000}ms")
    logger.info(f"Guilds: {len(bot.guilds)}")

Integrate with Prometheus, Datadog, or CloudWatch for production monitoring.

Backup and Recovery#

No persistent state (besides bot token). On restart:

  • Reconnect to gateway
  • Receive READY event with fresh state
  • Re-register persistent views

External state (database): Bot should store:

  • Per-guild configuration
  • User data (permissions, preferences)
  • Analytics data

Recovery: Restart bot, reconnects to gateway automatically. No backup required for bot code.


Sources#


matrix-nio - S2 Comprehensive Analysis#

Library: matrix-nio Language: Python Platform: Matrix Version Analyzed: 0.24.0 Date: 2026-02-05


Architecture Overview#

Core Design Pattern#

matrix-nio implements an event-driven async architecture built on Python’s asyncio:

  • AsyncClient: Main client managing connection lifecycle
  • Event loop integration: Native async/await for all I/O operations
  • Store-based state: Persistent state management for E2EE
  • Event callbacks: Register handlers for Matrix event types

Runtime Model#

Client Lifecycle:
┌─────────────┐
│ AsyncClient │──→ login() ──→ Initial sync
└─────────────┘        ↓
       ↓          Set up callbacks
   sync_forever()       ↓
       ↓          Process events ──→ Invoke callbacks
    [Loop]             ↓
                  Send responses

Connection handling: Uses long-polling sync (Matrix’s /sync endpoint), not WebSocket. Each sync cycle fetches new events since last sync token.

State Management#

  • Ephemeral mode (default): No persistence, loses E2EE keys on restart
  • Store mode: SQLite-backed storage for:
    • E2EE device keys
    • Olm/Megolm sessions
    • Sync tokens
    • Room state cache

Key insight: Matrix’s encryption model requires persistent state. Without a store, encrypted rooms become unusable after restarts.


API Design#

Command Registration Pattern#

Matrix doesn’t have “slash commands” at protocol level. Bots conventionally use ! prefix:

async def message_callback(self, room, event):
    if not event.decrypted:
        return  # Skip encrypted events we can't read

    body = event.body
    if body.startswith("!hello"):
        await self.client.room_send(
            room.room_id,
            "m.room.message",
            {"msgtype": "m.text", "body": "Hello!"}
        )

No command routing DSL - you manually parse event.body. Compare to Discord’s @bot.command() decorator.

Event Callback System#

Event callbacks are type-based:

client.add_event_callback(
    callback_func,
    RoomMessageText  # Specific event type
)

# Multiple event types:
client.add_event_callback(callback_func, (RoomMessageText, RoomEncryptedImage))

Callback signature:

async def callback(room: MatrixRoom, event: Event) -> None

Strengths: Type-safe event filtering Weaknesses: Manual dispatch logic for commands

Message Builder Abstraction#

Low-level send interface:

await client.room_send(
    room_id="!abc:matrix.org",
    message_type="m.room.message",
    content={
        "msgtype": "m.text",
        "body": "Plain text fallback",
        "format": "org.matrix.custom.html",
        "formatted_body": "<b>HTML content</b>"
    }
)

No builder pattern. You construct dicts manually. Compare to:

  • Discord: discord.Embed(title="...", description="...")
  • Telegram: InlineKeyboardMarkup([[button1, button2]])

HTML formatting via formatted_body field provides rich text.

Error Handling Strategy#

matrix-nio uses response objects instead of exceptions:

response = await client.room_send(...)
if isinstance(response, RoomSendError):
    logger.error(f"Failed to send: {response.message}")
else:
    logger.info(f"Sent event: {response.event_id}")

Response types:

  • LoginResponse / LoginError
  • SyncResponse / SyncError
  • RoomSendResponse / RoomSendError

Why this pattern? Avoids exception handling overhead in hot paths (sync loop processes many events).


Performance Characteristics#

Message Throughput#

Long-polling overhead: Each sync cycle has ~200-500ms latency (HTTP round-trip + server processing).

Rate limits (matrix.org homeserver):

  • 10 requests/second per IP
  • Burst allowance: 20 requests

Practical throughput: ~5-8 messages/second for interactive bots on matrix.org. Self-hosted instances can configure higher limits.

Memory Footprint#

Minimal config (no store): ~15-20 MB resident memory With store + E2EE: ~40-60 MB (includes libolm crypto library)

Sync response caching: Matrix servers send full room state on initial sync. Subsequent syncs are incremental, but initial sync for large rooms (1000+ members) can be 5-10 MB.

Connection Overhead#

Startup cost:

  1. Login: ~200ms
  2. Initial sync: 500ms - 5s (depends on room count)
  3. E2EE setup (if enabled): +500ms

Keepalive: 30-second timeout on /sync endpoint. Client must sync at least every 30s to stay “online.”

Rate Limiting Handling#

matrix-nio respects HTTP 429 responses with Retry-After headers:

if isinstance(response, RateLimitError):
    await asyncio.sleep(response.retry_after_ms / 1000)
    # Retry request

No automatic retry - you implement exponential backoff manually.


Feature Completeness#

Interactive Components#

FeatureSupportNotes
ButtonsWidgets (MSC1236)Requires embedding web content via m.room.message with widget URL
Menus/DropdownsWidgetsSame as buttons - no native protocol support
FormsWidgetsComplex, requires hosting web UI
ReactionsNativem.reaction event type

Widget complexity: To show buttons, you:

  1. Host a web page with button UI
  2. Send m.widget event with URL
  3. Client renders iframe
  4. Bot receives widget events via separate API

Compared to Discord/Telegram: Significantly more complex. Most Matrix bots stick to text commands + reactions.

Rich Media Support#

  • Images: Native via m.room.message (msgtype: m.image)
  • Video/Audio: Native support
  • File uploads: Matrix homeserver stores media, generates mxc:// URLs
  • HTML formatting: Via formatted_body field (subset of HTML allowed)

File size limits: Configurable per homeserver (matrix.org: 50 MB default)

E2E Encryption#

Full protocol support:

  • Olm: 1:1 message encryption
  • Megolm: Group message encryption (efficient for rooms)
  • Device verification: Cross-signing support

Implementation notes:

# E2EE requires store + async setup
client = AsyncClient("https://matrix.org", "@bot:matrix.org", store_path="./store")
await client.login(password)
await client.sync()  # Download device keys
await client.rooms_joined()  # Load room members

Key challenge: Managing device keys for all room members. Encrypted rooms require tracking:

  • User device list (can have multiple devices)
  • Device key changes (when users add new devices)
  • Megolm session rotation

Performance impact: E2EE adds ~100-200ms per message (encryption + key distribution).

Multi-Device Sync#

Matrix protocol natively supports multi-device:

  • Each device gets unique device ID
  • Messages sync across devices automatically
  • Read receipts propagate to all user’s devices

Bot implications: If bot runs on multiple servers, each needs separate device ID + E2EE setup.

File Handling#

Upload flow:

response = await client.upload(
    data_provider=open("file.jpg", "rb"),
    content_type="image/jpeg",
    filename="file.jpg"
)
mxc_url = response.content_uri

# Send message referencing uploaded file
await client.room_send(
    room_id,
    "m.room.message",
    {
        "msgtype": "m.image",
        "url": mxc_url,
        "body": "file.jpg"
    }
)

Two-step process: Upload → send message. Allows reusing uploaded files across multiple messages.


Integration Patterns#

Bot Registration#

  1. Create Matrix account (manual or via registration endpoint)
  2. Obtain access token via password login
  3. (Optional) Configure as bot user (appservice for advanced use)

No OAuth flow for bots. Most bots use password authentication.

Webhook Support#

Matrix doesn’t have native webhooks. Options:

  1. Run bot server: Bot stays connected via long-polling
  2. Push gateway (advanced): Configure homeserver to push events to HTTP endpoint

Practical implication: Most Matrix bots are long-running processes, not webhook handlers.

Admin API Access#

Synapse admin API (requires server admin):

  • User management
  • Room moderation
  • Server statistics

Not available on shared homeservers (matrix.org). Requires self-hosting for admin features.

Federation Integration#

Matrix is federated - bots can interact with users on any homeserver:

# Bot on bot-server.com can message user on matrix.org
await client.room_send(
    "!room:matrix.org",
    "m.room.message",
    {"msgtype": "m.text", "body": "Cross-server message"}
)

Federation delay: Messages between servers can have 1-5s latency depending on network topology.


Comparison Insights#

Strengths relative to other platforms:

  • Only bot SDK with native E2EE (Discord/Slack/Telegram don’t support E2EE for bots)
  • Self-hostable (vs centralized Discord/Slack/Telegram)
  • Open federation (vs walled gardens)

Weaknesses relative to other platforms:

  • No native interactive components (Discord has Views, Telegram has InlineKeyboards)
  • Manual command parsing (Discord has command tree, Telegram has CommandHandler)
  • Complex E2EE setup (vs “just works” on other platforms)
  • Smaller ecosystem (fewer users/bots than Discord/Telegram)

Architecture comparison:

  • vs Discord.py: Both async, but Discord has better command abstraction
  • vs python-telegram-bot: Both event-driven, but PTB has richer component API
  • vs slack-bolt: Matrix uses long-polling, Slack uses WebSocket (lower latency)

Production Deployment Considerations#

High Availability#

Challenges:

  • Stateful E2EE (can’t easily run multiple bot instances)
  • Sync token management (each instance would have separate state)

Solutions:

  • Run single bot instance with auto-restart (systemd, Docker restart policy)
  • Use appservice for distributed bots (complex setup)

Monitoring#

Key metrics to track:

  • Sync loop latency (should be <1s)
  • Failed message sends (rate limit or network issues)
  • E2EE session failures (device key problems)

matrix-nio doesn’t have built-in metrics. Integrate with Prometheus/StatsD manually.

Backup and Recovery#

Critical state (must backup):

  • store/ directory (E2EE keys + sync tokens)
  • Bot access token

Recovery: Restore store + access token, bot resumes from last sync point.

Without backup: Bot can re-login, but loses E2EE sessions → can’t decrypt past encrypted messages.


Sources#


nostr-tools - S2 Comprehensive Analysis#

Library: nostr-tools Language: JavaScript/TypeScript Platform: Nostr Version Analyzed: 2.1.0 Date: 2026-02-05


Architecture Overview#

Core Design Pattern#

nostr-tools implements a low-level event-driven architecture without bot abstractions:

  • SimplePool: Connection pool for multiple relays
  • Event creation: Manual event construction + signing
  • Subscription model: Filter-based event subscriptions
  • No command framework: You implement all parsing/routing

Runtime Model#

Bot Lifecycle:
┌─────────────┐
│ SimplePool  │──→ Connect to relays
└─────────────┘        ↓
       ↓          Subscribe with filters
   WebSocket          ↓
   connections    Receive matching events
       ↓               ↓
    [Loop]        Process + respond

Connection: Each relay = separate WebSocket. Pool manages N relay connections.

No state management: Nostr is stateless. Events published to relays, relays forward to subscribers. No server-side persistence.

State Management#

Client-side only:

  • Bot stores private key locally
  • No server-side sessions
  • No message history (unless you query relays)

Event fetching:

// Get past events (recent 100)
const events = await pool.querySync(relays, {
    kinds: [1],
    authors: [publicKey],
    limit: 100
});

Relay differences: Each relay may have different events (no guaranteed consistency). Bots query multiple relays for redundancy.


API Design#

Command Registration Pattern#

Manual parsing (no command framework):

import { SimplePool, getPublicKey, finalizeEvent } from 'nostr-tools';

const sk = privateKeyHex;
const pk = getPublicKey(sk);
const pool = new SimplePool();
const relays = ['wss://relay.damus.io', 'wss://relay.nostr.band'];

pool.subscribeMany(relays, [{
    kinds: [1],  // Text notes
    '#p': [pk],  // Mentions of this bot
    since: Math.floor(Date.now() / 1000)
}], {
    onevent(event) {
        const content = event.content.toLowerCase();

        if (content.includes('!hello')) {
            handleHello(event);
        } else if (content.includes('!help')) {
            handleHelp(event);
        }
    }
});

No decorators, no command tree. You implement text parsing yourself.

Event Callback System#

Subscription filters:

// Filter by event kind
{kinds: [1]}  // Text notes
{kinds: [3]}  // Contact lists
{kinds: [7]}  // Reactions

// Filter by author
{authors: [pubkey1, pubkey2]}

// Filter by tags
{'#p': [pubkey]}  // Events mentioning pubkey
{'#e': [eventId]}  // Events replying to eventId

// Time range
{since: timestamp, until: timestamp}

// Limit results
{limit: 100}

Callback signature:

{
    onevent(event) {
        // Process event
    },
    oneose() {
        // End of stored events (relay sent all matching past events)
    }
}

No type safety: Events are plain objects. You manually check event.kind and event.tags.

Message Builder Abstraction#

Manual event construction:

import { finalizeEvent } from 'nostr-tools';

// Reply to event
const reply = finalizeEvent({
    kind: 1,
    created_at: Math.floor(Date.now() / 1000),
    tags: [
        ['e', originalEvent.id],  // Reply to event
        ['p', originalEvent.pubkey]  // Mention original author
    ],
    content: "Hello!"
}, privateKey);

// Publish to relays
await Promise.all(relays.map(relay => pool.publish([relay], reply)));

No builder pattern. You construct objects manually.

Event structure:

{
    id: "event_id_hex",      // SHA256 hash of event
    pubkey: "author_pubkey",  // Author's public key
    created_at: 1234567890,   // Unix timestamp
    kind: 1,                  // Event type
    tags: [["tag", "value"]], // Metadata tags
    content: "text",          // Event content
    sig: "signature_hex"      // Schnorr signature
}

Error Handling Strategy#

No automatic error handling:

try {
    const pubs = pool.publish(relays, event);

    // Wait for relay confirmations
    await Promise.all(pubs.map(p => p.on));

    console.log("Published successfully");
} catch (error) {
    console.error("Publish failed:", error);
}

Relay failures are silent: If 3/5 relays accept event, others fail silently.

No retry logic: You implement exponential backoff manually.


Performance Characteristics#

Message Throughput#

No rate limits (protocol level):

  • Nostr protocol doesn’t enforce rate limits
  • Individual relays may have limits (varies per relay)

Relay capacity: Most public relays handle 100-1000 events/second.

Practical throughput: 10-50 events/second to popular relays (limited by relay capacity, not protocol).

Memory Footprint#

Minimal: ~10-15 MB (Node.js runtime + nostr-tools)

No caching: nostr-tools doesn’t cache events. Bot uses memory only for active subscriptions.

Connection scaling: Each relay = 1 WebSocket = ~1-2 KB memory overhead.

Connection Overhead#

Startup cost:

  1. Connect to relays: ~200-500ms (depends on relay count + network)
  2. No authentication (keypair-based, no login flow)

Keepalive: WebSocket ping/pong (relay-specific, typically 30-60s).

Relay churn: Relays go offline frequently. Bots should reconnect automatically:

// Auto-reconnect on disconnect
relays.forEach(relay => {
    relay.on('disconnect', () => {
        setTimeout(() => pool.ensureRelay(relay), 5000);
    });
});

Rate Limiting Handling#

Relay-dependent:

  • Some relays: No limits
  • Others: 10 events/second per connection
  • Popular relays: 100 events/second aggregate

No standard rate limit protocol. Relays may disconnect clients violating limits.

Best practice: Publish to multiple relays (redundancy + load distribution).


Feature Completeness#

Interactive Components#

FeatureSupportNotes
ButtonsNot supportedProtocol limitation
MenusNot supportedProtocol limitation
FormsNot supportedProtocol limitation
ReactionsNative (Kind 7)Simple emoji reactions
Zaps (Lightning payments)Native (NIP-57)Monetization primitive

No rich UI: Nostr is text-focused. Clients render text + reactions + zaps.

Reaction example:

// React to event with 👍
const reaction = finalizeEvent({
    kind: 7,
    tags: [
        ['e', eventId],
        ['p', eventPubkey]
    ],
    content: "👍"
}, privateKey);

await pool.publish(relays, reaction);

Rich Media Support#

Basic media:

  • Text: Native (Kind 1 events)
  • Images/Videos: URL references in content (clients render)
  • No inline embeds: Clients show URLs, may auto-expand

Example:

content: "Check out this image: https://example.com/image.jpg"

Clients detect URLs and render previews.

File hosting: Not protocol-native. Use external hosting (IPFS, HTTP), reference in event.

E2E Encryption#

Not built-in:

  • Events are public by default
  • NIP-04 (deprecated): DM encryption using shared secret
  • NIP-44 (new): Improved DM encryption

Encrypted DM example (NIP-04):

import { nip04 } from 'nostr-tools';

// Encrypt message
const ciphertext = await nip04.encrypt(privateKey, recipientPubkey, "Secret message");

// Send as Kind 4 event
const dm = finalizeEvent({
    kind: 4,
    tags: [['p', recipientPubkey]],
    content: ciphertext
}, privateKey);

await pool.publish(relays, dm);

Limitations:

  • Only 1:1 DMs (no group encryption)
  • Metadata not encrypted (sender, recipient, timestamp visible)

vs Matrix: Nostr’s encryption is weaker (no group E2EE, metadata leaks).

Multi-Device Sync#

Not applicable:

  • Nostr keypairs = identity
  • Same keypair on multiple devices = automatic “sync” (all devices see same events)

No device management: No concept of “devices” (just keypairs).

File Handling#

No native file storage:

  1. Upload file to external host (IPFS, S3, Cloudflare R2)
  2. Reference URL in event content
  3. Clients fetch file from URL

Example:

// 1. Upload to IPFS (external service)
const ipfsHash = await uploadToIPFS(file);

// 2. Publish event with URL
const event = finalizeEvent({
    kind: 1,
    tags: [['imeta', `url https://ipfs.io/ipfs/${ipfsHash}`]],
    content: `File: https://ipfs.io/ipfs/${ipfsHash}`
}, privateKey);

File URLs in events: Permanent (event immutability).


Integration Patterns#

Bot Registration#

No registration:

  1. Generate keypair (private + public key)
  2. Start publishing events

No approval, no API token. Anyone can publish events.

Keypair generation:

import { generateSecretKey, getPublicKey } from 'nostr-tools';

const sk = generateSecretKey();
const pk = getPublicKey(sk);

console.log("Private key:", Buffer.from(sk).toString('hex'));
console.log("Public key:", pk);

Store private key securely (hex string, 32 bytes).

Webhook Support#

Not applicable:

  • No centralized server
  • Bots subscribe to relays via WebSocket
  • No HTTP callbacks

Admin API Access#

No admin API:

  • Relays don’t have “admin” concept
  • Events are public (anyone can read)
  • Bots can’t “moderate” (no delete/ban at protocol level)

Relay-level moderation: Relay operators can filter events (but that’s relay policy, not protocol feature).

Monetization (Zaps)#

Native Lightning payment integration (NIP-57):

// Request zap (payment) from user
const zapRequest = finalizeEvent({
    kind: 9734,
    tags: [
        ['relays', ...relays],
        ['amount', '1000'],  // Satoshis
        ['lnurl', lnurl]
    ],
    content: "Please zap!"
}, privateKey);

await pool.publish(relays, zapRequest);

Zap flow:

  1. Bot sends zap request (Kind 9734)
  2. User’s client shows Lightning invoice
  3. User pays
  4. Lightning service publishes zap receipt (Kind 9735)
  5. Bot sees zap receipt, knows payment completed

Use case: Monetize bot services (pay per query, subscriptions).


Comparison Insights#

Strengths relative to other platforms:

  • Censorship resistant (no centralized platform)
  • No approval/verification (instant bot creation)
  • Native payments (Lightning zaps)
  • Open protocol (anyone can build relay/client)
  • Pseudonymous (keypair-based identity)

Weaknesses relative to other platforms:

  • No interactive UI (no buttons, menus, forms)
  • Manual everything (no command framework, no builders)
  • Smaller user base (~100k active users vs 900M Telegram)
  • Weak encryption (metadata leaks, no group encryption)
  • Relay unreliability (relays go offline, no SLA)

Architecture comparison:

  • vs discord.py: No abstractions (vs rich command tree + Views)
  • vs python-telegram-bot: No handler system (vs CommandHandler, CallbackQueryHandler)
  • vs matrix-nio: Weaker encryption, but simpler protocol

Use case fit:

  • Bitcoin community bots (native Lightning integration)
  • Censorship-resistant apps (no platform can ban you)
  • Mass-market bots (small user base, poor UX)
  • Privacy-critical bots (weak encryption, metadata leaks)

Production Deployment Considerations#

High Availability#

Relay redundancy: Connect to 5-10 relays (if 2-3 go offline, bot still works).

Stateless: Bot crashes = reconnect to relays + resubscribe. No persistent state loss.

Multi-instance: Run multiple bot instances (same keypair), all receive events (relay broadcasts to all subscribers).

Monitoring#

Key metrics:

  • Relay connection count (should match configured relays)
  • Event processing latency
  • Relay disconnects per hour
  • Failed event publishes

No built-in monitoring: Implement custom metrics:

let connectedRelays = 0;
let publishFailures = 0;

pool.on('connect', () => connectedRelays++);
pool.on('disconnect', () => connectedRelays--);

async function publishWithMetrics(event) {
    try {
        await pool.publish(relays, event);
    } catch (error) {
        publishFailures++;
        throw error;
    }
}

Backup and Recovery#

Critical data:

  • Private key (hex string)
  • Relay list (hardcoded or config file)

Recovery:

  1. Restore private key
  2. Reconnect to relays
  3. Resubscribe to events
  4. Bot resumes (no missed events if offline >1 hour, relays don’t queue)

No message history: Nostr relays typically keep 7-30 days of events. Older events may be lost.


Sources#


python-telegram-bot - S2 Comprehensive Analysis#

Library: python-telegram-bot (PTB) Language: Python Platform: Telegram Version Analyzed: 20.7 Date: 2026-02-05


Architecture Overview#

Core Design Pattern#

PTB implements a handler-based async architecture with flexible routing:

  • Application: Main bot manager (successor to Updater in v13)
  • Handler system: Route updates to callbacks (CommandHandler, MessageHandler, CallbackQueryHandler)
  • JobQueue: Built-in task scheduler
  • Persistence: Optional state persistence layer

Runtime Model#

Bot Lifecycle:
┌─────────────────┐
│   Application   │──→ initialize() ──→ Setup handlers
└─────────────────┘        ↓
       ↓              start_polling() OR start_webhook()
   Get updates           ↓
       ↓              Dispatch to handlers
    [Loop]               ↓
                    Execute callbacks

Two modes:

  1. Polling: Bot fetches updates via getUpdates API (long-polling, 30s timeout)
  2. Webhook: Telegram POSTs updates to your HTTP endpoint

Polling is default (easier setup). Webhook for production (lower latency, scales better).

State Management#

Built-in persistence (optional):

from telegram.ext import PicklePersistence

persistence = PicklePersistence(filepath="bot_data.pkl")
app = Application.builder().token(TOKEN).persistence(persistence).build()

Persists:

  • bot_data: Global bot state
  • user_data: Per-user state
  • chat_data: Per-chat state
  • callback_data: Button callback state

Storage backends: PicklePersistence (file), DictPersistence (memory), or custom (Redis, PostgreSQL).


API Design#

Command Registration Pattern#

Handler-based routing:

async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
    await update.message.reply_text("Hello!")

app.add_handler(CommandHandler("start", start))
app.add_handler(CommandHandler(["help", "info"], help_command))  # Multiple commands

Command arguments:

async def greet(update: Update, context: ContextTypes.DEFAULT_TYPE):
    # /greet Alice Bob -> context.args = ["Alice", "Bob"]
    name = " ".join(context.args) or "World"
    await update.message.reply_text(f"Hello, {name}!")

app.add_handler(CommandHandler("greet", greet))

No type validation (unlike Discord’s slash commands). You manually parse context.args.

Event Callback System#

Handler hierarchy (evaluated in order):

# 1. Commands
app.add_handler(CommandHandler("start", start))

# 2. Callback queries (button clicks)
app.add_handler(CallbackQueryHandler(button_handler, pattern="^option_"))

# 3. Messages with filters
from telegram.ext import filters
app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, echo))

# 4. Catch-all
app.add_handler(MessageHandler(filters.ALL, fallback))

Filter system:

  • filters.TEXT: Text messages only
  • filters.PHOTO: Photos
  • filters.COMMAND: Any command
  • Custom filters: filters.User([123, 456]), filters.Regex(r"pattern")

Callback signature:

async def handler(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None

Context object provides:

  • context.bot: Bot API client
  • context.user_data: Per-user persistent state
  • context.args: Command arguments
  • context.job_queue: Task scheduler

Message Builder Abstraction#

InlineKeyboard builder:

from telegram import InlineKeyboardButton, InlineKeyboardMarkup

keyboard = [
    [InlineKeyboardButton("Option 1", callback_data="opt1")],
    [InlineKeyboardButton("Option 2", callback_data="opt2")]
]
reply_markup = InlineKeyboardMarkup(keyboard)

await update.message.reply_text("Choose:", reply_markup=reply_markup)

Button types:

  • callback_data: Bot handles click (CallbackQuery)
  • url: Opens URL
  • switch_inline_query: Switches to inline mode
  • web_app: Opens mini-app

ReplyKeyboard (alternative):

from telegram import ReplyKeyboardMarkup, KeyboardButton

keyboard = [
    [KeyboardButton("Button 1"), KeyboardButton("Button 2")],
    [KeyboardButton("Share contact", request_contact=True)]
]
reply_markup = ReplyKeyboardMarkup(keyboard, resize_keyboard=True)

await update.message.reply_text("Choose:", reply_markup=reply_markup)

Difference:

  • InlineKeyboard: Buttons under message (ephemeral)
  • ReplyKeyboard: Replaces keyboard at bottom (persistent until removed)

Error Handling Strategy#

Exception-based + error handler:

async def error_handler(update: Update, context: ContextTypes.DEFAULT_TYPE):
    logger.error(f"Update {update} caused error: {context.error}")
    # Optionally notify user
    if update and update.effective_message:
        await update.effective_message.reply_text("An error occurred.")

app.add_error_handler(error_handler)

Common exceptions:

  • telegram.error.TimedOut: Network timeout
  • telegram.error.BadRequest: Invalid API call (e.g., message not found)
  • telegram.error.Forbidden: Bot blocked by user
  • telegram.error.RetryAfter: Rate limit (includes retry_after seconds)

Automatic retry: PTB retries network errors (connection issues) but not API errors (e.g., BadRequest).


Performance Characteristics#

Message Throughput#

Long-polling latency: ~100-300ms (better than matrix-nio’s 200-500ms due to optimized Telegram servers).

Rate limits:

  • 30 messages/second per chat
  • 20 messages/second to different users
  • Group broadcasts: 20 messages/minute (slow for mass notifications)

Practical throughput: 10-20 messages/second for interactive bots.

Memory Footprint#

Minimal config: ~20-30 MB resident memory With persistence: +10-20 MB (depends on data size)

Update queue: PTB queues incoming updates (default: unbounded). High traffic can cause memory growth.

Memory management:

# Limit concurrent updates
app = Application.builder().token(TOKEN).concurrent_updates(100).build()

Connection Overhead#

Startup cost (polling mode):

  1. getMe call: ~100ms (fetch bot info)
  2. First getUpdates: ~100ms

Keepalive: Polling uses long-polling (30s timeout), automatically keeps connection alive.

Webhook mode startup:

  1. Set webhook URL: ~100ms
  2. Wait for Telegram to POST updates (no polling overhead)

Rate Limiting Handling#

Manual handling required:

from telegram.error import RetryAfter

try:
    await bot.send_message(chat_id, "Message")
except RetryAfter as e:
    logger.warning(f"Rate limited, retry after {e.retry_after}s")
    await asyncio.sleep(e.retry_after)
    await bot.send_message(chat_id, "Message")

No automatic retry for rate limits (unlike discord.py).

Best practice: Implement token bucket or leaky bucket algorithm for bulk messaging.


Feature Completeness#

Interactive Components#

FeatureSupportNotes
Inline keyboardsNativeUp to 8 buttons per row, unlimited rows
Reply keyboardsNativeCustom keyboard layout
Inline modeNativeBot responds to @bot query in any chat
Web AppsNativeEmbed web UI in bot (mini-apps)
FormsVia Web AppsNo native modal support

Callback data limitation: 64 bytes max per button. For larger data, store in context.bot_data and use short IDs as callback_data.

Inline mode example:

from telegram import InlineQueryResultArticle, InputTextMessageContent

async def inline_query(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.inline_query.query
    results = [
        InlineQueryResultArticle(
            id="1",
            title=f"Result for {query}",
            input_message_content=InputTextMessageContent(f"You searched: {query}")
        )
    ]
    await update.inline_query.answer(results)

app.add_handler(InlineQueryHandler(inline_query))

Rich Media Support#

  • Markdown/HTML: Via parse_mode parameter
  • Photos/Videos: Native upload or URL reference
  • Documents: Any file type, up to 50 MB (2 GB for premium users)
  • Stickers: Send existing stickers or upload custom sticker packs
  • Polls: Native poll creation

Media groups (albums):

await bot.send_media_group(chat_id, [
    InputMediaPhoto("photo1.jpg"),
    InputMediaPhoto("photo2.jpg")
])

E2E Encryption#

Secret Chats (user-to-user only):

  • Native E2EE for user DMs
  • Not available for bots (bots can’t create secret chats)

Regular chats: Server-side encryption (Telegram can read messages).

Privacy implication: Bots don’t have E2EE. Better than Discord (no E2EE at all), worse than Matrix (full E2EE support).

Multi-Device Sync#

User accounts: Native multi-device sync (cloud-based).

Bots: Not applicable (bots don’t run on multiple devices).

File Handling#

Upload:

# From disk
await update.message.reply_document(document=open("file.pdf", "rb"))

# From URL
await update.message.reply_photo(photo="https://example.com/image.jpg")

# With custom filename
from telegram import InputFile
await update.message.reply_document(
    document=InputFile(open("data.csv", "rb"), filename="report.csv")
)

File download:

file = await context.bot.get_file(update.message.document.file_id)
await file.download_to_drive("downloaded.pdf")

File IDs: Telegram assigns unique file_id to uploaded files. Reuse file_id to avoid re-uploading.


Integration Patterns#

Bot Registration#

  1. Message @BotFather on Telegram
  2. Create new bot (/newbot)
  3. Receive bot token
  4. (Optional) Configure commands (/setcommands)

No approval process (unlike Discord’s verification). Instant bot creation.

Webhook Support#

Setup webhook:

await application.bot.set_webhook(
    url="https://yourdomain.com/webhook",
    allowed_updates=Update.ALL_TYPES
)

# Run webhook server
application.run_webhook(listen="0.0.0.0", port=8443, webhook_url="https://yourdomain.com/webhook")

Requirements:

  • HTTPS required (Telegram won’t POST to HTTP)
  • Valid SSL certificate (self-signed not allowed)
  • Open port (443, 80, 88, or 8443)

Webhook advantages:

  • Lower latency (~50ms vs 100-300ms polling)
  • No polling overhead
  • Scales better (Telegram pushes to you)

Webhook challenges:

  • Requires public IP + domain
  • SSL certificate management
  • Firewall configuration

Admin API Access#

Bot API limitations:

  • Can’t access user phone numbers
  • Can’t initiate DMs (users must message bot first)
  • Can’t add bot to channels as admin (requires user intervention)

Admin permissions (when added to groups):

  • Delete messages
  • Ban/restrict users
  • Pin messages
  • Change group title/photo

Requires group owner to grant permissions.

Payment Integration#

Telegram Payments API:

await bot.send_invoice(
    chat_id=chat_id,
    title="Product",
    description="Description",
    payload="invoice_payload",
    provider_token="STRIPE_TOKEN",
    currency="USD",
    prices=[LabeledPrice("Product", 1000)]  # $10.00
)

Supported providers: Stripe, Yandex.Money, etc.

Native payment flow (users pay within Telegram, bot receives confirmation).


Comparison Insights#

Strengths relative to other platforms:

  • Mobile-first UX (900M+ users, primarily mobile)
  • Instant bot creation (no approval process)
  • Inline mode (bot works in any chat, not just dedicated conversations)
  • Payment integration (native commerce support)
  • File handling (up to 2 GB for premium users)

Weaknesses relative to other platforms:

  • No E2EE for bots (Matrix has it)
  • Manual rate limit handling (discord.py auto-handles)
  • Limited formatting (no rich embeds like Discord)
  • Callback data limit (64 bytes vs Discord’s 100)

Architecture comparison:

  • vs discord.py: Polling/webhook vs WebSocket, handler-based vs command tree
  • vs matrix-nio: Better UX (inline keyboards), worse privacy (no bot E2EE)
  • vs slack-bolt: Similar webhook support, but Telegram is consumer-focused (Slack is enterprise)

Production Deployment Considerations#

High Availability#

Webhook mode enables HA:

  • Run multiple bot instances behind load balancer
  • Telegram distributes updates via round-robin
  • Each instance handles subset of requests

Polling mode: Single instance only (can’t poll from multiple servers without duplicate updates).

State synchronization: Use external persistence (Redis, PostgreSQL) for shared state across instances.

Monitoring#

Key metrics:

  • Update processing latency
  • Handler error rate
  • Rate limit hits
  • Queue depth (incoming updates)

Built-in stats:

@app.post_init
async def post_init(application: Application):
    logger.info(f"Bot started: @{application.bot.username}")

# Track handler timing
import time

async def timed_handler(update, context):
    start = time.time()
    await original_handler(update, context)
    duration = time.time() - start
    logger.info(f"Handler took {duration:.2f}s")

Backup and Recovery#

Persistent state (if using persistence):

  • Backup bot_data.pkl (or Redis/PostgreSQL)
  • Store bot token securely

Recovery:

  • Restore persistence file
  • Restart bot with same token
  • Bot resumes from last update offset

Webhook recovery: If bot crashes, Telegram queues updates (up to 24 hours). On restart, bot receives queued updates.


Sources#


slack-bolt - S2 Comprehensive Analysis#

Library: slack-bolt (Python) Language: Python Platform: Slack Version Analyzed: 1.18.0 Date: 2026-02-05


Architecture Overview#

Core Design Pattern#

slack-bolt implements a listener-based async architecture with decorator routing:

  • App: Main application instance (manages listeners + middleware)
  • Listener system: Route events/commands to handlers
  • Middleware stack: Chain handlers for auth, logging, etc.
  • Socket Mode / HTTP: Two connection modes

Runtime Model#

Bot Lifecycle:
┌─────────────┐
│     App     │──→ Register listeners
└─────────────┘        ↓
       ↓          Start Socket Mode OR HTTP server
   Connection          ↓
       ↓          Receive events from Slack
    [Loop]            ↓
                  Dispatch to listeners

Two modes:

  1. Socket Mode: WebSocket connection (development, no public URL required)
  2. HTTP Mode: Slack POSTs events to your endpoint (production)

State Management#

No built-in persistence:

  • Bolt doesn’t provide state management
  • You store state in external systems (Redis, PostgreSQL, DynamoDB)

Conversation state (built-in):

@app.action("button_click")
def handle_button(ack, body, client, context):
    ack()
    # context.user_id available
    user_data = get_user_data(context.user_id)  # Your storage

No automatic persistence like python-telegram-bot. You implement storage.


API Design#

Command Registration Pattern#

Decorator-based routing:

from slack_bolt import App

app = App(token="xoxb-...", signing_secret="...")

# Slash command
@app.command("/hello")
def handle_hello(ack, command, respond):
    ack()  # Acknowledge within 3 seconds (required)
    respond(f"Hello, <@{command['user_id']}>!")

# Shortcut (global)
@app.shortcut("open_modal")
def handle_shortcut(ack, shortcut, client):
    ack()
    client.views_open(...)

# Message event
@app.message("hello")
def handle_hello_message(message, say):
    say(f"Hi <@{message['user']}>!")

Acknowledge pattern: All interactions must be acknowledged within 3 seconds (Slack timeout).

ack()  # Always first line in listener

Command arguments:

@app.command("/greet")
def handle_greet(ack, command, respond):
    ack()
    # /greet Alice -> command['text'] = "Alice"
    name = command['text'] or "World"
    respond(f"Hello, {name}!")

Event Callback System#

Event subscription:

# Listen to all messages
@app.event("message")
def handle_message(event, say):
    say(f"You said: {event['text']}")

# Filtered events
import re

@app.message(re.compile(r"(hi|hello)"))
def handle_greeting(message, say):
    say("Hello!")

Event types:

  • message: Chat messages
  • app_mention: Bot mentioned with @
  • reaction_added: Emoji reaction
  • member_joined_channel: User joins channel

Callback signature (flexible):

def handler(ack, body, logger):  # Bolt injects arguments
    # ack: Acknowledge function
    # body: Full event payload
    # logger: Pre-configured logger

Lazy listeners (async processing):

@app.event("message")
def handle_message_sync(ack, body):
    ack()  # Acknowledge immediately
    # Body queued for async processing

def process_message_async(body, say):
    # Heavy processing
    say("Processed!")

app.event("message", middleware=[handle_message_sync])(process_message_async)

Message Builder Abstraction#

Block Kit builder:

@app.command("/survey")
def survey(ack, client, command):
    ack()

    client.views_open(
        trigger_id=command["trigger_id"],
        view={
            "type": "modal",
            "title": {"type": "plain_text", "text": "Survey"},
            "blocks": [
                {
                    "type": "input",
                    "block_id": "name_block",
                    "label": {"type": "plain_text", "text": "Name"},
                    "element": {
                        "type": "plain_text_input",
                        "action_id": "name_input"
                    }
                },
                {
                    "type": "actions",
                    "elements": [
                        {
                            "type": "button",
                            "text": {"type": "plain_text", "text": "Submit"},
                            "action_id": "submit_survey",
                            "style": "primary"
                        }
                    ]
                }
            ]
        }
    )

Block Kit = Slack’s UI framework. Rich components (buttons, selects, date pickers, etc.).

Simpler syntax via slack_sdk.models:

from slack_sdk.models.blocks import *
from slack_sdk.models.views import View

view = View(
    type="modal",
    title=PlainTextObject(text="Survey"),
    blocks=[
        InputBlock(
            block_id="name",
            label=PlainTextObject(text="Name"),
            element=PlainTextInputElement(action_id="name_input")
        ),
        ActionsBlock(elements=[
            ButtonElement(text=PlainTextObject(text="Submit"), action_id="submit")
        ])
    ]
)

client.views_open(trigger_id=..., view=view)

Error Handling Strategy#

Exception-based + error listener:

@app.error
def handle_errors(error, body, logger):
    logger.error(f"Error: {error}")
    logger.debug(f"Body: {body}")
    # Optionally notify admins

# Specific handler errors
@app.command("/hello")
def handle_hello(ack, command, respond):
    ack()
    try:
        result = risky_operation()
        respond(f"Success: {result}")
    except Exception as e:
        respond(f"Error: {e}")

Slack API errors:

from slack_sdk.errors import SlackApiError

try:
    client.chat_postMessage(channel="C123", text="Message")
except SlackApiError as e:
    if e.response["error"] == "channel_not_found":
        logger.error("Invalid channel")
    elif e.response["error"] == "not_in_channel":
        logger.error("Bot not in channel")

Automatic retry: slack_sdk retries 429 (rate limit) and 5xx errors automatically.


Performance Characteristics#

Message Throughput#

Rate limits (per workspace):

  • 1 message/second per channel (Tier 1)
  • 1 request/second for most API methods (Tier 2)
  • 20 requests/minute for user-scoped methods (Tier 3)
  • 100+ requests/minute for high-volume apps (Tier 4, approved apps only)

Practical throughput: 1-3 messages/second for typical apps.

Burst allowance: Short bursts (5-10 messages) tolerated before rate limiting.

Memory Footprint#

Minimal config: ~40-60 MB (includes slack_sdk dependencies) Socket Mode: +10-20 MB (WebSocket connection overhead)

No caching: Bolt doesn’t cache workspace data. Each API call fetches fresh data.

Connection Overhead#

Socket Mode startup:

  1. Authenticate: ~200ms
  2. WebSocket handshake: ~100ms
  3. Ready to receive events: <500ms total

HTTP Mode startup:

  1. Start HTTP server: ~50ms
  2. Wait for Slack POSTs (no connection overhead)

Keepalive: Socket Mode sends WebSocket pings every 30s.

Rate Limiting Handling#

Automatic retry (slack_sdk):

from slack_sdk import WebClient
from slack_sdk.errors import SlackApiError

client = WebClient(token="xoxb-...")

try:
    response = client.chat_postMessage(channel="C123", text="Message")
except SlackApiError as e:
    if e.response.status_code == 429:
        # Automatically retried by SDK
        logger.warning(f"Rate limited, retry after {e.response.headers['Retry-After']}s")

No manual retry needed (unlike python-telegram-bot).


Feature Completeness#

Interactive Components#

FeatureSupportNotes
ButtonsNative (Block Kit)Rich styling (primary, danger)
Select menusNativeStatic, dynamic, user/channel select
Date pickerNativeCalendar UI
Time pickerNativeTime selection
ModalsNativePop-up forms with validation
WorkflowsNativeNo-code automation (Workflow Builder)

Button example:

@app.command("/action")
def show_buttons(ack, respond):
    ack()
    respond(
        blocks=[
            {
                "type": "actions",
                "elements": [
                    {
                        "type": "button",
                        "text": {"type": "plain_text", "text": "Approve"},
                        "action_id": "approve",
                        "style": "primary"
                    },
                    {
                        "type": "button",
                        "text": {"type": "plain_text", "text": "Deny"},
                        "action_id": "deny",
                        "style": "danger"
                    }
                ]
            }
        ]
    )

@app.action("approve")
def handle_approve(ack, body, respond):
    ack()
    respond(text="Approved!", replace_original=True)

Rich Media Support#

  • Attachments: Images, videos, files (up to 1 GB per file)
  • Rich text: Block Kit formatting (markdown subset)
  • Embeds: Unfurl links automatically (og:image, og:title)
  • Custom unfurls: Bot controls link previews

File upload:

client.files_upload(
    channels="C123",
    file="report.pdf",
    title="Monthly Report"
)

E2E Encryption#

Not supported: Slack doesn’t offer E2EE (even for user messages).

Enterprise Key Management (EKM): Enterprise Grid customers can bring their own encryption keys (but Slack still has access during processing).

Privacy implication: Slack (and admins) can read all messages.

Multi-Device Sync#

User accounts: Native multi-device sync (cloud-based).

Bots: Not applicable (single bot instance per app).

File Handling#

Upload:

client.files_upload_v2(
    channel="C123",
    file="./document.pdf",
    title="Document",
    initial_comment="Here's the file"
)

Download:

import requests

file_info = client.files_info(file="F123")
file_url = file_info["file"]["url_private"]

# Download with bot token
response = requests.get(file_url, headers={"Authorization": f"Bearer {bot_token}"})
with open("downloaded.pdf", "wb") as f:
    f.write(response.content)

File hosting: Slack hosts files on CDN (permanent URLs unless deleted by user/admin).


Integration Patterns#

Bot Registration#

  1. Create app at api.slack.com/apps
  2. Configure bot scopes (permissions)
  3. Install app to workspace
  4. Receive bot token (xoxb-...)

OAuth flow (for distribution):

from slack_bolt.oauth import OAuthSettings

oauth_settings = OAuthSettings(
    client_id="YOUR_CLIENT_ID",
    client_secret="YOUR_CLIENT_SECRET",
    scopes=["chat:write", "commands"],
)

app = App(oauth_settings=oauth_settings)

Bot distributes to multiple workspaces, each gets separate token.

Webhook Support#

Incoming webhooks (simple, send-only):

import requests

webhook_url = "https://hooks.slack.com/services/T123/B456/abc"
requests.post(webhook_url, json={"text": "Message from webhook"})

Limitations: Can’t receive events, can’t use full API.

App webhooks (full API):

  • Configure Request URL in app settings
  • Slack POSTs events to your endpoint
  • Use Bolt’s HTTP mode

Admin API Access#

Scoped permissions (OAuth scopes):

  • chat:write: Post messages
  • channels:read: List channels
  • users:read: List workspace members
  • admin: Workspace admin actions (Enterprise Grid only)

Requires workspace owner approval for admin scopes.

Enterprise Grid: Additional APIs for org-level management (multi-workspace).

Workflow Integration#

Workflow Steps (custom steps in Workflow Builder):

@app.step("approval_step")
def approval_step(ack, step, configure):
    ack()
    # User configures step in Workflow Builder

@app.action("approval_step_save")
def save_approval_step(ack, body, client):
    ack()
    # Save step configuration

Use case: No-code automation for end users (trigger workflows on events, bot provides custom logic).


Comparison Insights#

Strengths relative to other platforms:

  • Enterprise-grade (SSO, admin controls, audit logs)
  • Rich UI components (Block Kit rivals Discord’s complexity)
  • Workflow Builder (no-code automation)
  • Mature ecosystem (10M+ daily active users in paid workspaces)

Weaknesses relative to other platforms:

  • Expensive ($8.75/user/month Pro, $15/user/month Business+)
  • No E2EE (unlike Matrix)
  • Strict rate limits (1 msg/s/channel vs 30 msg/s Telegram)
  • Enterprise-focused (overkill for consumer bots)

Architecture comparison:

  • vs discord.py: Similar (WebSocket, rich components), but Slack is workplace-focused
  • vs python-telegram-bot: Better rich UI (Block Kit), worse rate limits
  • vs matrix-nio: Easier (no E2EE complexity), but no self-hosting

Use case fit:

  • Internal workplace bots (HR, DevOps, support)
  • Enterprise integrations (Salesforce, Jira, GitHub)
  • Consumer bots (expensive, not consumer-facing)
  • High-volume messaging (rate limits too strict)

Production Deployment Considerations#

High Availability#

Socket Mode: Single connection (no HA). If bot crashes, reconnect.

HTTP Mode: Scale horizontally (multiple instances behind load balancer). Slack distributes events via round-robin.

Stateless design: Store state externally (Redis, DynamoDB). Each instance handles subset of requests.

Monitoring#

Key metrics:

  • Event processing latency
  • API error rate
  • Rate limit hits
  • Socket Mode connection drops (if using)

Built-in logging:

import logging
logging.basicConfig(level=logging.DEBUG)

@app.middleware
def log_request(logger, body, next):
    logger.info(f"Received: {body['type']}")
    next()

Slack API analytics: Slack provides dashboard (API call counts, error rates) at api.slack.com.

Backup and Recovery#

Critical data:

  • Bot token (xoxb-...)
  • Signing secret (for request verification)
  • OAuth credentials (if distributing)

External state: Store in database (PostgreSQL, DynamoDB, Redis).

Recovery:

  1. Restore tokens + secrets
  2. Restart bot
  3. Reconnect (Socket Mode) or resume (HTTP Mode)
  4. No missed events (Slack retries failed webhook deliveries for 3 hours)

Event replay: Slack doesn’t queue events >3 hours. If bot offline longer, events lost.


Sources#

S3: Need-Driven

S3 Need-Driven: Bot SDK Use Case Analysis#

Date: 2026-02-05 Methodology: S3 - Need-driven selection framework Category: 1.234 (Bot SDK Frameworks)


Framework Purpose#

This analysis maps bot SDK selection to concrete use cases and requirements. Rather than abstract comparisons, we evaluate SDKs against real-world constraints and needs.


Use Case Matrix#

1. Privacy-Critical Communication Bot#

Requirements:

  • End-to-end encryption mandatory
  • Self-hosting capability
  • No third-party data access
  • Audit trail for compliance

SDK Evaluation:

PlatformFitRationale
Matrix (matrix-nio)Best fitOnly SDK with native E2EE. Self-hostable. Full message encryption including metadata.
Discord (discord.py)❌ No E2EECentralized, no encryption. Discord can read all messages.
Telegram (PTB)⚠️ PartialSecret Chats E2EE (user-to-user only), but bots can’t use secret chats.
Nostr (nostr-tools)⚠️ WeakDM encryption (NIP-04), but metadata leaks. No group encryption.
Slack (slack-bolt)❌ No E2EEEnterprise-focused, but no message encryption. Admins see all.

Recommendation: Matrix (matrix-nio) - Only option with full E2EE support for bot messages. Requires understanding E2EE key management complexity.

Implementation notes:

  • Use SqliteStore for persistent E2EE keys
  • Implement device verification flow
  • Plan for key backup/recovery
  • Test encrypted room membership changes

2. High-Volume Notification Bot#

Requirements:

  • Send 1000+ messages/hour
  • Low latency (<500ms)
  • Reliable delivery
  • Cost-effective at scale

SDK Evaluation:

PlatformThroughputLatencyCostVerdict
Discord (discord.py)20-40 msg/s~50-150msFree✅ Best
Telegram (PTB)10-20 msg/s~100-300msFree✅ Good
Matrix (matrix-nio)5-8 msg/s~200-500msFree (self-host)⚠️ Slow
Slack (slack-bolt)1-3 msg/s~50ms$8.75/user/mo❌ Expensive + slow
Nostr (nostr-tools)10-50 msg/sVariesFree⚠️ Unreliable relays

Recommendation: Discord (discord.py) or Telegram (PTB) depending on audience:

  • Discord: Best for gaming/community (younger demographic)
  • Telegram: Best for mobile-first (broader geographic reach, 900M+ users)

Implementation notes:

  • Discord: Respect 50 req/s global limit, use per-channel batching
  • Telegram: Implement token bucket for 30 msg/s rate limit
  • Both: Use webhook mode in production for lower latency

3. Enterprise Internal Tool#

Requirements:

  • SSO integration
  • Admin audit logs
  • Rich UI components (forms, approvals)
  • IT department approval process

SDK Evaluation:

PlatformEnterprise FeaturesUI RichnessApproval ProcessVerdict
Slack (slack-bolt)Excellent (SSO, SCIM, audit)Block Kit (excellent)Standard procurement✅ Best
Matrix (matrix-nio)Self-host (full control)Widgets (complex)Deploy your own⚠️ High effort
Discord (discord.py)Limited (no SSO)Views (excellent)Consumer platform❌ Not enterprise
Telegram (PTB)NoneInline keyboards (good)Consumer platform❌ Not enterprise
Nostr (nostr-tools)NoneText onlyNo approval needed❌ Not enterprise

Recommendation: Slack (slack-bolt) - Only platform designed for enterprise. Cost justified by compliance/security features.

Alternative: Matrix (matrix-nio) if:

  • Company already self-hosts Matrix
  • SSO not critical (or implement via proxy)
  • UI simplicity acceptable
  • Privacy requirements outweigh UX

Implementation notes:

  • Slack: Use OAuth for multi-workspace distribution
  • Request admin scopes early (approval takes time)
  • Integrate with SAML/SCIM for user provisioning
  • Use Workflow Builder for no-code end-user automation

4. Developer Tool Bot (CI/CD Integration)#

Requirements:

  • GitHub/GitLab integration
  • Code syntax highlighting
  • Thread-based conversations
  • Developer-friendly UX

SDK Evaluation:

PlatformCode DisplayThreadingDev AdoptionVerdict
Slack (slack-bolt)Excellent (code blocks)Native threadsHigh (workplace)✅ Best for teams
Discord (discord.py)Good (markdown)Forum channelsHigh (OSS community)✅ Best for OSS
Matrix (matrix-nio)HTML formattingNative threadsMedium (tech community)⚠️ Smaller reach
Telegram (PTB)MarkdownNo native threadsLow (consumer focus)❌ Poor fit
Nostr (nostr-tools)NoneVia ’e’ tagsVery low❌ Poor fit

Recommendation:

  • Slack (slack-bolt) for internal company tools
  • Discord (discord.py) for open-source project notifications

Implementation notes:

  • Slack: Use Block Kit code blocks with language highlighting
  • Discord: Use embeds with code blocks (```python)
  • Both: Implement threading for build logs (keep channels clean)
  • GitHub webhooks → bot processes → formatted messages

5. Payments/Commerce Bot#

Requirements:

  • Native payment integration
  • Transaction confirmation
  • Receipt delivery
  • PCI compliance considerations

SDK Evaluation:

PlatformPayment SupportTransaction FlowComplianceVerdict
Telegram (PTB)Native (Stripe, etc.)In-app checkoutSlack handles PCI✅ Best for consumers
Nostr (nostr-tools)Lightning Network (Zaps)Bitcoin-nativeN/A (crypto)✅ Best for Bitcoin
Slack (slack-bolt)None (external links)Leave appN/A⚠️ Manual integration
Discord (discord.py)None (banned ToS)N/AN/A❌ Prohibited
Matrix (matrix-nio)NoneN/AN/A❌ Not supported

Recommendation:

  • Telegram (PTB) for fiat currency (broad payment provider support)
  • Nostr (nostr-tools) for Bitcoin/Lightning (native Zaps protocol)

Implementation notes:

  • Telegram: Use send_invoice + handle pre_checkout_query
  • Payment providers: Stripe, Yandex.Money (varies by region)
  • Nostr: Implement NIP-57 (Zaps) with LNURL/Lightning Address
  • Consider fraud detection (user reputation, transaction limits)

6. Community Moderation Bot#

Requirements:

  • Ban/kick users
  • Delete messages
  • Auto-moderation (spam, profanity)
  • Audit log for mod actions

SDK Evaluation:

PlatformMod PowersAuto-mod APIsAudit TrailVerdict
Discord (discord.py)Excellent (ban, timeout, etc.)Native (AutoMod)Via webhooks✅ Best
Telegram (PTB)Good (ban, restrict)Manual implementationManual logging⚠️ Good
Slack (slack-bolt)Limited (admin only)ManualSlack audit logs⚠️ Enterprise only
Matrix (matrix-nio)Good (kick, ban)ManualManual logging⚠️ Good
Nostr (nostr-tools)None (protocol limitation)Relay-level onlyN/A❌ Not supported

Recommendation: Discord (discord.py) - Best moderation API, AutoMod integration, built-in audit logging via guild audit log.

Implementation notes:

  • Discord: Use guild.ban(), member.timeout() for temp bans
  • Check guild.audit_logs for mod action history
  • Implement warning system (3 strikes → ban)
  • Use AutoMod API for regex-based filtering (reduces bot load)

7. Decentralized/Censorship-Resistant Bot#

Requirements:

  • No single point of failure
  • Resistant to deplatforming
  • Pseudonymous operation
  • No approval process

SDK Evaluation:

PlatformDecentralizationCensorship ResistanceDeployment BarrierVerdict
Nostr (nostr-tools)Full (relay network)ExcellentNone (instant)✅ Best
Matrix (matrix-nio)FederatedGoodSelf-host setup⚠️ Good
Discord (discord.py)CentralizedNoneVerification required❌ Can be banned
Telegram (PTB)CentralizedNoneInstant❌ Can be banned
Slack (slack-bolt)CentralizedNoneOAuth approval❌ Can be banned

Recommendation:

  • Nostr (nostr-tools) for maximum censorship resistance
  • Matrix (matrix-nio) for federated approach with better UX

Implementation notes:

  • Nostr: Connect to 10+ relays (redundancy), rotate relay list
  • Generate keypair securely, no email/phone required
  • Use NIP-05 for identity verification (optional)
  • Matrix: Self-host homeserver, use .onion address for anonymity
  • Both: No KYC, no approval process

8. Mobile-First Bot#

Requirements:

  • Excellent mobile UX
  • Push notifications
  • Offline message queue
  • Low bandwidth usage

SDK Evaluation:

PlatformMobile UXPush NotificationsOffline SupportBandwidthVerdict
Telegram (PTB)ExcellentNativeMessage queueLow✅ Best
Discord (discord.py)GoodNativeSync on reconnectMedium⚠️ Good
Slack (slack-bolt)GoodNativeSync on reconnectMedium⚠️ Good
Matrix (matrix-nio)GoodVia push gatewaySync tokensHigh (E2EE)⚠️ Slower
Nostr (nostr-tools)LimitedNo standardNo guaranteeLow❌ Unreliable

Recommendation: Telegram (PTB) - Built for mobile-first, 900M+ users primarily on mobile, excellent offline message queueing.

Implementation notes:

  • Telegram: Messages queued on server if user offline
  • Use inline keyboards (better than reply keyboards on mobile)
  • Keep messages concise (mobile screen space)
  • Test on slow networks (3G simulation)

Decision Tree#

START: What type of bot are you building?

┌─ Privacy-critical? (Healthcare, legal, sensitive data)
│  └─ YES → Matrix (matrix-nio)
│  └─ NO → Continue
│
┌─ Enterprise internal tool?
│  └─ YES → Already use Slack? → YES → Slack (slack-bolt)
│  │                           → NO → Evaluate Matrix (self-host) vs Slack (buy)
│  └─ NO → Continue
│
┌─ Payments/commerce?
│  └─ YES → Bitcoin/Lightning? → YES → Nostr (nostr-tools)
│  │                          → NO → Telegram (python-telegram-bot)
│  └─ NO → Continue
│
┌─ Censorship resistance critical?
│  └─ YES → Maximum resistance → Nostr (nostr-tools)
│  │       Federated OK → Matrix (matrix-nio)
│  └─ NO → Continue
│
┌─ High message volume? (`>1000` msg/hour)
│  └─ YES → Gaming/community? → YES → Discord (discord.py)
│  │                         → NO → Telegram (python-telegram-bot)
│  └─ NO → Continue
│
┌─ Mobile-first audience?
│  └─ YES → Telegram (python-telegram-bot)
│  └─ NO → Continue
│
┌─ Developer tool? (CI/CD, GitHub integration)
│  └─ YES → Internal team? → YES → Slack (slack-bolt)
│  │                      → NO → Discord (discord.py) [OSS community]
│  └─ NO → Continue
│
└─ Default recommendation: Discord (discord.py) [best UX, largest features]

Anti-Patterns: When NOT to Use Each SDK#

Avoid Matrix if:#

  • Interactive UI critical (buttons, forms) - widgets too complex
  • Quick MVP needed (<4 hours) - E2EE setup takes time
  • Non-technical users - slash commands confusing (! prefix vs /)

Avoid Discord if:#

  • Privacy/E2EE required - no encryption
  • Mobile-first audience - good but not mobile-native
  • Payments needed - prohibited by ToS
  • Enterprise SSO required - consumer platform

Avoid Telegram if:#

  • Rich formatting needed - limited compared to Discord/Slack
  • Threading important - no native thread support
  • Self-hosting required - centralized platform

Avoid Nostr if:#

  • Interactive UI needed - protocol limitation (text only)
  • Large user base required - ~100k active users (niche)
  • Reliable delivery critical - relays can go offline
  • UX polish matters - rough edges, developer-focused

Avoid Slack if:#

  • Consumer-facing bot - expensive per-user pricing
  • High message volume - strict rate limits (1 msg/s/channel)
  • Budget-constrained - $8.75/user/month minimum
  • No enterprise budget - not cost-effective for small projects

Multi-Platform Strategy#

Some use cases benefit from supporting multiple platforms simultaneously:

When to go multi-platform:#

  1. Maximize reach: Different audiences prefer different platforms
  2. Risk mitigation: Platform ban/outage doesn’t kill bot
  3. Feature complementarity: Use Telegram for mobile, Discord for desktop

Implementation approach:#

Shared core logic:

# Core bot business logic (platform-agnostic)
class BotCore:
    def handle_hello(self, user_id: str) -> str:
        return f"Hello, `{user_id}`!"

# Platform-specific adapters
class DiscordAdapter:
    def __init__(self, core: BotCore):
        self.core = core

    @bot.command()
    async def hello(self, ctx):
        response = self.core.handle_hello(ctx.author.id)
        await ctx.send(response)

class TelegramAdapter:
    def __init__(self, core: BotCore):
        self.core = core

    async def hello(self, update, context):
        response = self.core.handle_hello(update.effective_user.id)
        await update.message.reply_text(response)

When NOT to go multi-platform:

  • Maintenance burden 2x (each platform has quirks)
  • Feature parity difficult (Discord Views ≠ Telegram InlineKeyboards)
  • User confusion (different command syntax per platform)

Recommendation: Start single-platform, add others when proven demand exists.


Sources#

  • Platform API documentation (Discord, Telegram, Matrix, Slack, Nostr)
  • Production bot case studies
  • Developer community surveys (r/discordapp, r/Telegram, Matrix community)
  • Enterprise procurement analysis (Slack vs alternatives)
S4: Strategic

S4 Strategic: Bot SDK Ecosystem Analysis#

Date: 2026-02-05 Methodology: S4 - Strategic long-term analysis Category: 1.234 (Bot SDK Frameworks)


Executive Summary#

Bot SDK ecosystem is fragmenting into three strategic directions:

  1. Enterprise consolidation (Slack) - workplace dominance, high margins
  2. Consumer scale (Discord, Telegram) - massive user bases, free platforms
  3. Decentralized protocols (Matrix, Nostr) - open standards, self-sovereignty

Long-term bet: Multi-protocol abstraction layers will emerge (like how web frameworks abstract HTTP). Early movers building protocol-agnostic bot cores will have advantage.


Ecosystem Landscape#

Market Segmentation (2026)#

SegmentLeadersGrowthMonetization
EnterpriseSlack, Microsoft TeamsStable (~10% YoY)Per-user SaaS ($8-15/mo)
Gaming/CommunitiesDiscordHigh (~30% YoY)Nitro subscriptions + server boosts
Consumer MobileTelegram, WhatsAppHigh (~25% YoY)Business API revenue
DecentralizedMatrix, NostrNascent (~100% YoY, small base)Self-hosted/donations

Key insight: Enterprise and consumer markets diverging. Discord/Telegram growing faster but monetization unclear. Matrix/Nostr tiny but ideologically driven.


1. The “Bot Verification” Trap#

Problem: Platforms increasingly gate bot features behind verification/approval:

  • Discord: >75 guilds requires verification + privileged intents approval
  • Slack: Enterprise Grid features require partnership
  • Telegram: No restrictions (yet), but may change
  • Matrix/Nostr: No approval (decentralized)

Implication: Early-stage bots should avoid platforms with scaling gates. Ship on Telegram/Matrix first, add Discord/Slack when proven.

Future prediction: Discord/Slack will tighten bot policies (spam prevention). Telegram may follow (currently most permissive).

2. AI Agent Platforms#

Emerging pattern: Platforms adding native AI agent support:

  • Discord: Bot accounts can request “AI agent” badge
  • Slack: Workflow AI steps (GPT integration)
  • Telegram: Bot API enhancements for conversational AI
  • Matrix: No official AI features (DIY)

Implication: Platform-native AI features will commoditize simple bots. Differentiation moves to:

  1. Domain expertise (vertical-specific bots)
  2. Complex workflows (multi-step automation)
  3. Privacy/security (where AI plugins can’t go)

Recommendation: Don’t build generic “answer questions” bots - platforms will bundle that. Build specialized tools.

3. Cross-Platform Messaging Bridges#

Trend: Users want unified messaging (Matrix bridges, Beeper, Element).

Reality: Bridges are fragile (rely on unofficial APIs, break on updates).

Strategic implication: Don’t rely on bridges for production. If multi-platform critical, implement native SDKs for each platform.

Exception: Matrix→Everything bridges (Matrix.org officially supports bridges). If building on Matrix, bridges are first-class.

4. The Payment Platform Shift#

Observation:

  • Telegram: Native payment API (Stripe, etc.)
  • Discord: Banned commerce (2024 ToS update)
  • Nostr: Native Lightning (Zaps protocol)
  • Slack/Matrix: No native payments

Strategic insight: Payment-enabled platforms (Telegram, Nostr) will attract commerce bots. Discord’s commerce ban creates opportunity gap.

Long-term: Payment rails = platform moat. Expect more platforms to add payments (or ban competitors).

5. E2EE vs. Moderation Trade-off#

Tension: Platforms face choice:

  • E2EE (Matrix, Nostr DMs) - privacy, but can’t moderate
  • Server-side access (Discord, Slack, Telegram) - moderation possible, but privacy concerns

Trend: Consumer platforms prioritizing moderation over E2EE (see Telegram’s policy shifts). Enterprise platforms adding “compliant encryption” (keys in escrow).

Implication for bot builders:

  • Privacy-critical bots: Matrix is only real option long-term
  • Moderation bots: Discord/Slack have best APIs (require server access)
  • Hybrid approach: Nostr (relay-level moderation, no protocol-level censorship)

Architectural Patterns#

Pattern 1: The “Thin Client” Bot#

Design: Bot as thin wrapper around external service.

User → Platform SDK → Bot (routing only) → External API → Response

Example: GitHub notifications bot

  • Receives webhooks from GitHub
  • Formats as platform-specific messages
  • No state, no business logic

Best platforms: Slack (webhooks), Discord (webhooks), Telegram (webhooks)

Avoid: Matrix (no native webhooks), Nostr (requires persistent connection)


Pattern 2: The “Conversational State Machine” Bot#

Design: Multi-step workflows with user state.

User input → State lookup → Business logic → State update → Response

Example: Survey bot (ask name → ask email → ask feedback → send confirmation)

Best platforms:

  • Telegram (built-in persistence via context.user_data)
  • Discord (can use persistent Views)

Avoid:

  • Matrix (no state management, DIY)
  • Nostr (stateless protocol, external DB required)

Pattern 3: The “Real-Time Sync” Bot#

Design: Bot mirrors external state in real-time.

External system → WebSocket/SSE → Bot → Platform → Users see updates

Example: CI/CD status bot (build starts → bot posts “Building…” → build completes → bot updates “✅ Done”)

Best platforms:

  • Discord (edit messages, rich embeds)
  • Slack (update messages, Block Kit)

Challenges:

  • Telegram (can’t edit other bot messages)
  • Matrix (no edit history, confusing UX)

Pattern 4: The “Collaborative Workspace” Bot#

Design: Bot facilitates multi-user workflows.

User A action → Bot state → Notify User B → User B action → Update shared view

Example: Approval workflow (employee requests, manager approves, bot tracks)

Best platforms:

  • Slack (threads, Block Kit, workflow builder)
  • Discord (forum channels, thread creation)

Poor fit:

  • Telegram (no native threading)
  • Nostr (no collaborative state)

Technology Stack Recommendations#

Polyglot Architecture#

Insight: No single SDK language dominates. Choose by team expertise:

LanguageBest SDKEcosystem Maturity
Pythondiscord.py, python-telegram-bot, matrix-nio, slack-boltExcellent (4/5 platforms)
JavaScript/TypeScriptdiscord.js, telegraf, matrix-bot-sdk, @slack/boltExcellent (4/5 platforms)
Godiscordgo, gotgbot, mautrix-goGood (3/5 platforms)
Rustserenity, teloxide, matrix-rust-sdkGrowing (3/5 platforms)

Recommendation: Python or TypeScript - widest SDK support, largest community.

Exception: Performance-critical bots (>10k messages/s) - use Go or Rust.


Deployment Patterns#

Pattern A: Single-Server Monolith#

When: MVP, <100 users, low traffic

Architecture:

Bot process (Python/Node) → Platform API
        ↓
    SQLite DB (state)

Platforms: All work well

Cost: $5-10/month (VPS)


Pattern B: Serverless Functions#

When: Sporadic traffic, pay-per-use preferred

Architecture:

Platform webhook → AWS Lambda/Cloudflare Workers → Platform API
                         ↓
                   DynamoDB/KV (state)

Best platforms:

  • Slack (webhooks, 3s timeout limit OK)
  • Telegram (webhooks, fast responses)

Avoid:

  • Discord (needs persistent WebSocket for optimal performance)
  • Matrix (long-polling, not webhook-friendly)
  • Nostr (requires persistent WebSocket)

Cost: $0-5/month (free tier sufficient for small bots)


Pattern C: Kubernetes Cluster#

When: High availability, >10k users, multi-platform

Architecture:

Load balancer → N bot pods → Platform APIs
                    ↓
          Shared state (Redis/PostgreSQL)

Best platforms:

  • Slack (HTTP mode, stateless)
  • Telegram (webhook mode, stateless)
  • Discord (requires sharding strategy)

Challenges:

  • Matrix (E2EE state per instance, hard to replicate)
  • Nostr (each instance connects to relays, duplicate events)

Cost: $50-500/month (depends on scale)


Long-Term Sustainability#

Revenue Models for Bot Developers#

Successful patterns:

  1. Freemium (Discord bots like MEE6, Dyno)

    • Free tier: Basic features
    • Premium: $5-10/month per server
    • Works on platforms with server-level billing
  2. B2B SaaS (Slack apps like Donut, Workast)

    • Charge per workspace: $50-500/month
    • Target enterprises with budget
  3. Transaction fees (Telegram payment bots)

    • Take % of payments processed
    • Requires payment-enabled platform
  4. Tips/Donations (Nostr bots)

    • Lightning Zaps (micropayments)
    • Works for niche communities

Avoid: Ad-supported bots (platforms prohibit, users hate).


Platform Risk Assessment#

Risk factors:

  1. API deprecation (breaking changes)
  2. Policy changes (bot features restricted)
  3. Platform shutdown (unlikely but not impossible)

Risk matrix (2026-2030):

PlatformShutdown RiskAPI Breakage RiskPolicy Tightening Risk
SlackVery LowLowMedium (anti-spam)
DiscordVery LowMedium (frequent updates)High (verification gates)
TelegramLowLow (stable API)Medium (may add restrictions)
MatrixVery Low (protocol)Medium (spec changes)Very Low (decentralized)
NostrNone (protocol)High (NIPs evolving)None (no central authority)

Mitigation strategy:

  • Abstract platform logic (dependency injection, adapters)
  • Monitor platform changelogs (subscribe to developer updates)
  • Test against beta APIs (catch breaking changes early)
  • Multi-platform redundancy (if one platform bans, others remain)

Emerging Opportunities#

1. AI-Augmented Moderation Bots#

Opportunity: Platforms struggle with moderation at scale. Bots combining:

  • LLM-based content analysis (detect toxicity, spam)
  • Platform mod APIs (ban, timeout, delete)
  • Human-in-the-loop for edge cases

Best platforms: Discord (best mod APIs), Telegram (good APIs)

Differentiation: Domain expertise (gaming toxicity vs political discourse)


2. Cross-Platform Identity Bots#

Problem: Users have fragmented identities across platforms.

Solution: Bot that links Discord/Telegram/Matrix accounts, provides unified profile.

Tech: OAuth (Discord, Slack), Bot API (Telegram), Matrix auth

Monetization: Premium features (verified cross-platform identity)


3. Web3 Integration Bots#

Opportunity: Crypto communities need bot tooling:

  • Wallet verification (prove NFT ownership)
  • DAO governance (vote via chat)
  • Token gating (access based on holdings)

Best platforms: Discord (largest crypto community), Nostr (Lightning native)

Caution: Regulatory uncertainty, scam risk (due diligence on partners)


4. Compliance/Audit Bots#

Opportunity: Regulated industries (healthcare, finance) need audit trails.

Features:

  • Message archiving (compliance)
  • Keyword alerting (detect violations)
  • Audit reports (for regulators)

Best platforms: Slack (enterprise focus), Matrix (E2EE + audit trails)

Monetization: B2B SaaS ($500-5000/month per org)


Strategic Recommendations#

For Startups Building Bot Products#

  1. Start with Telegram or Discord

    • Fastest time-to-market
    • No approval gates for early stage
    • Large user bases for validation
  2. Abstract platform logic early

    • Even if single-platform now, plan for multi-platform
    • Use adapter pattern (thin platform layer, thick core logic)
  3. Prioritize platforms by audience, not tech

    • Wrong: “Matrix has best tech” → build on Matrix
    • Right: “Our users are on Discord” → build on Discord
  4. Monitor platform policy changes

    • Subscribe to developer changelogs
    • Join platform developer communities
    • Test in beta programs (catch breaking changes early)

For Enterprises Building Internal Bots#

  1. Default to Slack (if already using)

    • Lowest friction (employees already have accounts)
    • Best compliance features
    • SSO integration
  2. Consider Matrix for sensitive data

    • Self-host for full control
    • E2EE for privacy
    • Trade-off: More IT overhead
  3. Avoid consumer platforms (Discord, Telegram)

    • No enterprise SSO
    • No audit trails
    • Employees mixing personal/work accounts

For Open-Source Projects#

  1. Discord for community

    • Best for real-time chat
    • Forum channels for organized discussion
    • Large OSS community presence
  2. Matrix for privacy-conscious projects

    • E2EE for security discussions
    • Self-hosted (no platform lock-in)
    • Bridges to other platforms (reach)
  3. Avoid Slack (unless sponsored)

    • Free tier too limited (90-day message history)
    • Expensive for large communities

5-Year Outlook (2026-2031)#

Predicted Consolidation#

Likely scenario:

  • Slack acquired or partners with Microsoft (Teams integration)
  • Discord explores federation (Matrix-compatible protocol)
  • Telegram continues independent (funded by founder)
  • Matrix reaches critical mass (10M+ monthly active users)
  • Nostr remains niche but stable (Bitcoin community)

Impact on bot developers:

  • Platform interoperability increases (Matrix bridges standardize)
  • Bot verification becomes universal (anti-spam measure)
  • AI features commoditize simple bots (need specialization)

Technology Shifts#

WebAssembly bots (speculative):

  • Platform-agnostic bot binaries
  • Deploy once, run on any platform
  • Reduces SDK fragmentation

Decentralized social protocols:

  • ActivityPub (Mastodon) gains traction
  • Bots need ActivityPub support
  • Matrix/Nostr positioned well (already decentralized)

Agentic AI platforms:

  • LLMs integrated at platform level
  • Custom bots for specialized tasks only
  • Privacy/security/domain expertise differentiators

Conclusion#

Key takeaways:

  1. No single “best” platform - optimize for use case
  2. Platform risk is real - abstract early, diversify when proven
  3. Enterprise vs consumer diverging - different monetization models
  4. AI will commoditize simple bots - specialize or integrate deeply
  5. Decentralized platforms growing - hedge for long-term

Final recommendation: Build for Discord or Telegram first (fastest validation), abstract platform logic, add other platforms when product-market fit proven. For privacy-critical use cases, start with Matrix despite higher complexity.


Sources#

  • Platform developer documentation
  • Bot ecosystem surveys (Discord/Telegram developer communities)
  • Enterprise procurement analysis
  • Gartner/Forrester workplace collaboration reports
  • Decentralized protocol adoption metrics (Matrix.org stats, Nostr relay counts)
  • Venture capital funding data (bot platform investments)
Published: 2026-03-06 Updated: 2026-03-06