Skip to main content
When any Microsoft.AspNetCore.* package is referenced in your project, the PolyBot source generator emits PolyBotWebhookHostedService, AddPolyBotWebhook, and MapPolyBotWebhook. These wire up a production-ready webhook endpoint in a minimal-API or MVC application: Telegram sends HTTPS POST requests, PolyBot verifies the secret token, deserializes the update, and routes it through the generated BotRouter.
The webhook integration is generated only when a Microsoft.AspNetCore.* package is referenced. It is never emitted in library projects or console-only executables that lack ASP.NET Core.

Registration

Two calls configure the webhook integration:

AddPolyBotWebhook

The signature is:
The configure delegate receives the PolyBotOptions that will be used by the hosted service and the endpoint handler. Use it to set the webhook URL, secret token, and connection limits:
If PolyBotOptions is already registered as a singleton before AddPolyBotWebhook is called, the hosted service will use that instance and apply the configure delegate on top of it.

MapPolyBotWebhook

The signature is:
Maps the POST route after AddPolyBotWebhook. The path defaults to "/bot" and can be anything your reverse proxy exposes:

Webhook options

All webhook-specific settings live in PolyBotOptions:

PolyBotWebhookHostedService lifecycle

The generated PolyBotWebhookHostedService handles the Telegram webhook lifecycle automatically:
1

StartAsync — SetWebhook

On host startup, calls SetWebhook with WebhookUrl, WebhookSecretToken, WebhookMaxConnections, AllowedUpdates, and DropPendingUpdates. Throws InvalidOperationException if WebhookUrl is null or empty.
2

StopAsync — DeleteWebhook

On graceful shutdown, if DeleteWebhookOnStop is true (the default), calls DeleteWebhook. This is safe to disable if you want Telegram to keep sending updates to the URL after the process stops (e.g. during a rolling deployment).

Concurrent update processing

By default the webhook hosted service processes updates one at a time (WebhookMaxConcurrentUpdates = 1). Set this option higher to process multiple updates in parallel while keeping the concurrency bounded:
Concurrency only affects how many updates are routed through BotRouter at the same time. Each update still gets its own DI scope, but shared services (including IStateStorage and any custom state) must be thread-safe when WebhookMaxConcurrentUpdates is greater than 1.

Request handling

The generated HandlePolyBotWebhookAsync request delegate runs for every POST to the mapped path:
1

Secret token verification

If WebhookSecretToken is set, the X-Telegram-Bot-Api-Secret-Token header is checked:
  • Header absent → 400 Bad Request
  • Header value doesn’t match → 401 Unauthorized
  • Header matches → continues
2

Deserialization

The request body stream is deserialized using Telegram.Bot’s source-generated JsonBotSerializerContext. Malformed JSON or a missing/zero update ID → 400 Bad Request.
3

Routing

IUpdateHandler.HandleUpdateAsync is called with ITelegramBotClient and the deserialized Update. Both are resolved from HttpContext.RequestServices.
4

Response

Returns 200 OK after the handler completes. Telegram expects any 2xx response within the timeout; PolyBot always returns 200.
Services are resolved from HttpContext.RequestServices — the per-request DI scope. Scoped and transient services registered with the root container behave as expected. If you need per-request state, register services as scoped.

Complete Program.cs example

A minimal ASP.NET Core application wired to receive Telegram webhook updates:

Testing the webhook endpoint

Use PolyTests as ITelegramBotClient and call the endpoint method directly to test secret verification, deserialization, and routing without running a real HTTP server:
See PolyTests for full SentRequests assertions, and Test Harness for the simpler UpdateMocker-based approach that works without ASP.NET Core.