← All posts
Tutorial

Connect a Telegram User Account to a Webhook: Code and QR Setup

To connect an existing Telegram user account to a webhook, first obtain your own Telegram api_id and api_hash, register the webhook before authorization, create a Telegram messaging account in UnifyPort, and complete either the code or QR flow. Code login also needs the account phone number and may request a two-factor password. QR login still needs the API credentials, but the account owner approves the login in an already signed-in Telegram app.

Key takeaways

  • A Telegram user-account connection uses api_id and api_hash, not a BotFather bot token.
  • Register the webhook first so authorization and inbound events have somewhere to arrive.
  • Choose auth_mode: "code" when the operator can enter a Telegram login code; choose auth_mode: "qrcode" when approval from an existing Telegram app is more convenient.
  • Treat api_hash, login codes, two-factor passwords, QR content, API keys, and signing_secret as secrets.
  • After authorization, accept only signed message.received deliveries and store the events you need when they arrive.

If you are still deciding which credential model applies, read Telegram API ID and API hash vs bot token before implementing this flow.

Telegram user account webhook setup: the complete sequence

The setup has four boundaries: Telegram application credentials, a receiver you control, the UnifyPort messaging account, and the interactive authorization step. Keeping those boundaries separate makes failures easier to diagnose.

1. Obtain your Telegram application credentials

Telegram’s official application setup guide says api_id and api_hash are required for user authorization. Create them through the API development tools at my.telegram.org, use credentials assigned to your own application, and keep the hash out of source control and logs.

This is different from the Bot API. Telegram describes its Bot API as an HTTP interface for bot identities. Use that official path when a bot identity and bot-specific behavior are exactly what you want. Continue here when your integration needs to connect an existing user account through an unofficial interface.

If you inherited a sample or published application ID, stop and verify its origin. The API_ID_PUBLISHED_FLOOD recovery checklist explains how to replace an unsuitable credential without exposing the new one.

2. Register the signed webhook before login

Create the receiver before starting authentication. UnifyPort does not provide a REST message-history read API or guaranteed replay, so your application should store required events on arrival.

curl -X POST https://api.unifyport.ai/v1/webhook-endpoints \
  -H "X-Api-Key: $UNIFYPORT_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{
    \"url\": \"$PUBLIC_WEBHOOK_URL\",
    \"status\": \"active\",
    \"subscribed_events\": [\"message.received\", \"account.auth.required\", \"account.auth.succeeded\", \"account.auth.failed\", \"account.status.updated\"],
    \"signing_secret\": \"$WEBHOOK_SIGNING_SECRET\"
  }"

The exact request contract is in Create webhook endpoint. When signing is enabled, verify X-Device-Signature as the hex HMAC-SHA256 of the X-Device-Timestamp, a period, and the raw request body. The webhook HMAC and replay-protection guide covers raw-body verification, stale timestamps, retries, and idempotency.

3A. Choose code authorization

For code login, create the account with provider_data.api_id, provider_data.api_hash, and provider_data.phone. Keep values in a secret manager or environment variables rather than embedding them in a repository.

curl -X POST https://api.unifyport.ai/v1/accounts \
  -H "X-Api-Key: $UNIFYPORT_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{
    \"name\": \"Telegram Support\",
    \"provider\": \"telegram\",
    \"region\": \"global\",
    \"status\": \"active\",
    \"auth_mode\": \"code\",
    \"capabilities\": [\"send_message\", \"receive_message\"],
    \"provider_data\": {
      \"api_id\": $TELEGRAM_API_ID,
      \"api_hash\": \"$TELEGRAM_API_HASH\",
      \"phone\": \"$TELEGRAM_PHONE\"
    }
  }"

Save the returned account id, then begin the login:

curl -X POST "https://api.unifyport.ai/v1/accounts/$ACCOUNT_ID/auth/start" \
  -H "X-Api-Key: $UNIFYPORT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'

Submit the code received through Telegram:

curl -X POST "https://api.unifyport.ai/v1/accounts/$ACCOUNT_ID/auth/code" \
  -H "X-Api-Key: $UNIFYPORT_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"code\": \"$TELEGRAM_LOGIN_CODE\"}"

Telegram’s official user authorization reference documents the additional two-factor step. If the UnifyPort auth state becomes awaiting_password, submit the password to /v1/accounts/{account_id}/auth/password; do not send it unless that state requests it.

3B. Choose QR authorization

For QR login, create the same Telegram account with auth_mode: "qrcode" and include provider_data.api_id plus provider_data.api_hash; the phone field is not required for this mode. Start the QR flow with:

curl -X POST "https://api.unifyport.ai/v1/accounts/$ACCOUNT_ID/auth/qr/start" \
  -H "X-Api-Key: $UNIFYPORT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'

Read the current state with GET /v1/accounts/{account_id}/auth or check it with POST /v1/accounts/{account_id}/auth/qr/check. Render the returned auth_payload.qr_code only to the account owner. Telegram’s official QR login specification says the QR must be scanned and accepted by an already logged-in Telegram app, and expired login tokens must be regenerated. Therefore, update the displayed QR when the auth response supplies a newer payload.

The Telegram authorization reference lists the code, QR, two-factor, and session-import branches in one place.

4. Confirm authorization and receive messages

Watch for account.auth.succeeded, then reconcile the account state with GET /v1/accounts/{account_id}. Successful authorization normally starts the runtime automatically; use the returned runtime_status rather than assuming the connection is ready.

A Telegram inbound message then arrives in the standard envelope:

{
  "id": "evt_b1a7c3e5f8",
  "type": "message.received",
  "provider": "telegram",
  "account_id": "acc_8c21d0",
  "occurred_at": "2026-06-08T12:37:00Z",
  "data": {
    "conversation": { "id": "5005", "type": "user" },
    "sender": { "id": "4004", "type": "user", "name": "Jordan Lee" },
    "message": {
      "id": "3003",
      "text": "Can you check my order?",
      "direction": "inbound",
      "sent_at": "2026-06-08T12:37:00Z"
    },
    "event": { "kind": "message_received" }
  }
}

Route only events where type is message.received and data.message.direction is inbound. Use the event ID for idempotent processing, acknowledge valid deliveries with a 2xx response, and persist the fields your workflow needs.

Limitations and trade-offs

A user-account connection is not a replacement for every Telegram bot use case. Choose the official Bot API when you want a dedicated bot identity, bot commands, and Telegram’s bot-oriented interface. Choose this UnifyPort flow when the required identity is an existing Telegram user account or when the same inbound handler must later accept WhatsApp, LINE, TikTok, Zalo, or X events.

UnifyPort is an unofficial interface, so upstream account behavior and availability can vary. Your use must still comply with Telegram’s API Terms of Service and your own security and privacy obligations. Do not expose credentials, authorization payloads, or session material to end users other than the account owner completing the login.

FAQ

Do I need a Telegram bot token for this setup?

No. A user-account connection uses an api_id and api_hash. A bot token belongs to the separate official Bot API model.

Does QR login remove the need for an API ID and API hash?

No. In the UnifyPort Telegram flow, QR authorization still requires provider_data.api_id and provider_data.api_hash; it changes how the account owner approves the login.

What happens when Telegram asks for two-factor authentication?

Wait until the auth state is awaiting_password, then submit the password to /v1/accounts/{account_id}/auth/password. Keep the password out of logs and discard it after the authorization request.

Should I register the webhook before or after connecting the account?

Before. Authorization state changes and inbound messages are delivered as events, and missed message payloads are not guaranteed to be replayed.

Which event should start my inbound workflow?

Use message.received and require data.message.direction to equal inbound. Verify the HMAC signature before parsing or acting on the event.

Next step

Open the Telegram authorization guide and choose code or QR login. Register and secure the webhook first, then create the messaging account and complete authorization.

Sources

Official sources checked on 2026-08-13: