Telego Webhook Handler Configuration: Complete Guide for Go Bots

Telego webhook handler configuration involves registering a POST handler on your HTTP server using WebhookFastHTTP, WebhookHTTPServer, or WebhookHTTPServeMux, then calling Bot.UpdatesViaWebhook to receive Telegram updates on a Go channel.

The mymmrac/telego library provides a modular architecture for handling Telegram bot webhooks in Go. Instead of forcing a specific HTTP framework, it exposes adapter functions that integrate with fasthttp, net/http, or http.ServeMux, while managing update decoding, channel buffering, and graceful shutdown internally.

Understanding the Telego Webhook Architecture

The webhook system separates transport concerns from update processing. The core components reside in webhook_handler.go (server adapters) and webhook.go (channel management and options).

WebhookHandler Type

The underlying handler signature is defined in webhook.go:

type WebhookHandler func(ctx context.Context, data []byte) error

This function receives the request context and raw JSON body. It must return an error if JSON unmarshaling fails. The UpdatesViaWebhook method wraps this handler to push decoded Update structs onto a buffered channel.

Server Integration Helpers

Three adapter functions in webhook_handler.go bind the WebhookHandler to your server:

  • WebhookFastHTTP – wraps *fasthttp.Server
  • WebhookHTTPServer – wraps *http.Server
  • WebhookHTTPServeMux – registers on *http.ServeMux

Each helper validates the request method (POST only), checks the optional secret token via the X-Telegram-Bot-Api-Secret-Token header, and returns appropriate HTTP status codes (404, 405, 401, or 200).

Configuring Webhook Handlers for Different Servers

FastHTTP Configuration

For high-performance applications using valyala/fasthttp, use WebhookFastHTTP. The function returns a closure that accepts your WebhookHandler.

package main

import (
	"context"
	"fmt"
	"os"

	"github.com/valyala/fasthttp"
	"github.com/mymmrac/telego"
)

func main() {
	ctx := context.Background()
	botToken := os.Getenv("TOKEN")

	bot, err := telego.NewBot(botToken, telego.WithDefaultDebugLogger())
	if err != nil {
		panic(err)
	}

	// Optional: configure webhook on Telegram servers
	_ = bot.SetWebhook(ctx, &telego.SetWebhookParams{
		URL:         "https://my.domain/bot",
		SecretToken: bot.SecretToken(),
	})

	// Initialize FastHTTP server
	fsrv := &fasthttp.Server{}

	// Configure webhook handler with 256-slot buffer
	updates, err := bot.UpdatesViaWebhook(
		ctx,
		telego.WebhookFastHTTP(fsrv, "/bot", bot.SecretToken()),
		telego.WithWebhookBuffer(256),
	)
	if err != nil {
		panic(err)
	}

	// Start server in background
	go func() { _ = fsrv.ListenAndServe(":8443") }()

	// Process updates
	for upd := range updates {
		fmt.Printf("Update %d: %+v\n", upd.UpdateID, upd)
	}
}

This example mirrors the official implementation in [examples/updates_webhook/main.go](https://github.com/mymmrac/telego/blob/main/examples/updates_webhook/main.go).

Standard Library http.Server

For applications using net/http, WebhookHTTPServer provides identical validation logic:

srv := &http.Server{Addr: ":8080"}

updates, err := bot.UpdatesViaWebhook(
    ctx,
    telego.WebhookHTTPServer(srv, "/bot", bot.SecretToken()),
    telego.WithWebhookSet(ctx, &telego.SetWebhookParams{
        URL:         "https://my.domain/bot",
        SecretToken: bot.SecretToken(),
    }),
)
if err != nil { panic(err) }

go func() { _ = srv.ListenAndServe() }()

for upd := range updates {
    // Handle update
}

Using http.ServeMux

When multiplexing multiple handlers, WebhookHTTPServeMux registers the POST route directly:

mux := http.NewServeMux()

updates, err := bot.UpdatesViaWebhook(
    ctx,
    telego.WebhookHTTPServeMux(mux, "POST /bot", bot.SecretToken()),
    telego.WithWebhookBuffer(128),
)
if err != nil { panic(err) }

go func() { _ = http.ListenAndServe(":8080", mux) }()

for upd := range updates {
    // Process update
}

Processing Updates with UpdatesViaWebhook

The Bot.UpdatesViaWebhook method in webhook.go orchestrates the entire flow:

  1. State validation – ensures no conflicting long-polling or webhook process is running (b.run(runningWebhook)).
  2. Option application – applies WebhookOption functions to configure the internal webhook struct.
  3. Channel creation – initializes a buffered chan Update with size determined by WithWebhookBuffer (default: 128).
  4. Handler registration – invokes the provided registerHandler closure, supplying a WebhookHandler that unmarshals JSON and sends updates to the channel.
  5. Lifecycle management – spawns a goroutine that closes the channel and clears state when the context is cancelled.

Channel Buffering Options

Control memory usage and backpressure with WithWebhookBuffer:

updates, err := bot.UpdatesViaWebhook(
    ctx,
    telego.WebhookFastHTTP(srv, "/bot"),
    telego.WithWebhookBuffer(64), // Small buffer for low-traffic bots
)

The default buffer size of 128 is defined as defaultWebhookUpdateChanBuffer in webhook.go.

Automatic Webhook Registration

Avoid manual SetWebhook calls by using WithWebhookSet:

updates, err := bot.UpdatesViaWebhook(
    ctx,
    telego.WebhookHTTPServer(srv, "/bot"),
    telego.WithWebhookSet(ctx, &telego.SetWebhookParams{
        URL:            "https://api.example.com/bot",
        SecretToken:    bot.SecretToken(),
        MaxConnections: 40,
    }),
)

This option invokes bot.SetWebhook before starting the server, ensuring Telegram knows where to deliver updates.

Summary

  • Telego webhook handler configuration relies on adapter functions (WebhookFastHTTP, WebhookHTTPServer, WebhookHTTPServeMux) to bridge your HTTP server with the library's update processing.
  • The WebhookHandler type receives raw JSON bytes and is responsible for unmarshaling and channel delivery; UpdatesViaWebhook orchestrates this into a buffered <-chan Update.
  • File locations: server adapters live in webhook_handler.go, core logic in webhook.go, and runnable examples in examples/updates_webhook/main.go.
  • Options like WithWebhookBuffer and WithWebhookSet tune performance and automate webhook registration with Telegram's API.

Frequently Asked Questions

How do I secure my Telego webhook endpoint?

Pass your secret token to the server adapter function (e.g., WebhookFastHTTP(server, "/bot", bot.SecretToken())). The handler validates the X-Telegram-Bot-Api-Secret-Token header against this value, returning HTTP 401 if the token mismatch indicates a forged request. You can retrieve the bot's auto-generated secret token via bot.SecretToken().

What is the difference between UpdatesViaWebhook and UpdatesViaLongPolling?

UpdatesViaWebhook configures the bot to receive updates via an HTTP POST endpoint that Telegram pushes to, while UpdatesViaLongPolling repeatedly calls the getUpdates method to fetch updates from Telegram's servers. The webhook approach is more efficient for high-traffic bots and provides lower latency, but requires a publicly accessible HTTPS server. UpdatesViaWebhook lives in webhook.go and uses a channel-based architecture, whereas long polling is implemented in long_polling.go.

Can I use a custom HTTP server not supported by the built-in helpers?

Yes. The UpdatesViaWebhook method accepts any function matching func(handler WebhookHandler) error as the registerHandler parameter. Implement your own registration logic that validates the request method, verifies the secret token header, reads the body, and calls handler(ctx, body). This allows integration with frameworks like Gin, Echo, or Fiber by wrapping their request contexts into the standard WebhookHandler signature.

How do I handle graceful shutdown when using webhooks?

The UpdatesViaWebhook method accepts a context.Context. When this context is cancelled (e.g., via signal.NotifyContext on SIGINT), the library automatically closes the update channel and clears the internal runningWebhook state. Ensure your HTTP server also implements graceful shutdown (e.g., http.Server.Shutdown) to complete processing of in-flight requests before the program exits. The channel returned by UpdatesViaWebhook will be closed, causing any for upd := range updates loops to exit cleanly.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →