Zapnoty — Login via bots

API Documentation

REST API for notifications via Telegram and Max. Subscribers, OTP, broadcasts, forms, helpdesk.

Bot Auth

Authenticate your website users via Telegram/Max bots. User clicks a link, confirms in the bot, automatically subscribes to notifications, and you receive their data.

How it works

1. User clicks the bot link

2. Bot shows authorization request with "Login" / "Cancel" buttons

3. User clicks "Login" → automatic subscription to notifications + code generation

4. Bot sends "Go to website" button → callback_url?code=CODE

5. Your server calls POST /v1/auth/verify → receives data

Setup

In the project dashboard go to Settings → Auth and set the Callback URL and Origin URL.

Static links

Simple option — a permanent link. Get it via API or in the dashboard:

GET /v1/auth/link
 
// Response:
{
"telegram_link": "https://t.me/YourBot?start=auth_my-app",
"max_link": "https://max.ru/YourBot?start=auth_my-app",
"configured": true
}

The static authorization link (format auth_<slug>) works only if a callback URL is configured for the project (Settings → Auth). Without it the bot replies «Authorization for this project is not set up». The configured field in the response indicates whether the project is ready for authorization.

Subscription ≠ authorization

If you just need a notification subscription (without the user logging into your site) — use a separate mechanism: the proj_<slug> link from GET /v1/subscribe-link. It requires no callback configuration and always works. The auth_ prefix is authorization (login that returns user data), the proj_ prefix is a plain subscription. See the Subscribers section.

API sessions (with state)

To pass state (e.g., browser session ID), create a session via API:

POST /v1/auth/session
{
"state": "browser_session_abc", // ваш токен — вернётся обратно
"redirect_uri": "https://you.com/cb" // опц., должен быть в allowlist проекта
}
// Response — одна сессия, ссылки сразу на оба мессенджера:
{
"session_id": "aBcDeFgH12345678",
"telegram_link": "https://t.me/YourBot?start=auths_aBcDeFgH12345678",
"max_link": "https://max.ru/YourBot?start=auths_aBcDeFgH12345678",
"expires_in": 1800
}
  • state — 1–128 characters, printable ASCII without spaces or the < > & symbols. Put an opaque token there (not an email/phone) — it is returned in auth.completed and in /v1/auth/verify.
  • redirect_uri — optional. For the notification-only flow (receiving the result via the auth.completed webhook) no callback is needed at all. If set, it must exactly match a URL from the project allowlist.
  • A session lives 30 minutes (expires_in: 1800). Usually the user completes linking right away: open link → bot → confirm. The 30 minutes is a buffer in case they get distracted. If the link does expire — the bot replies with an "expired" message on /start; just create a new session. Stop status polling after expires_in.

Code verification

After confirmation, the user lands on callback_url?code=CODE. Verify the code:

POST /v1/auth/verify
{ "code": "aBcDeFgH..." } // code одноразовый, TTL 1800 c
// Response:
{
"channel": "telegram",
"first_name": "John",
"username": "johndoe", // без @, "" если нет
"avatar_url": null,
"subscriber_id": "550e8400-e29b-41d4-a716-446655440000",
"lang": "ru",
"tags": [],
"state": "browser_session_abc", // ваш токен, null если не передавали
"auth_time": "2026-05-21T12:00:00+00:00"
}

QR/Polling (cross-device)

For desktop auth via a mobile bot: create a session, display a QR code with the link, and poll the status. When the user confirms on their phone, you receive a code. Poll interval: 2-3 seconds. The code is one-time — after receiving status=completed, a repeat request returns expired.

GET /v1/auth/session/{session_id}/status
 
// Pending:
{ "status": "pending" }
 
// Completed:
{ "status": "completed", "code": "aBcDeFgH..." }

Receiving the result: three ways

After the user follows the link and confirms login in the bot, you can obtain the result in one of three ways:

  • Webhook auth.completed — always sent. The payload contains subscriber_id, state (your token) and subscriber data. The simplest path for a backend integration: no callback service needed.
  • Polling GET /v1/auth/session/{session_id}/status — when status: "completed" a code is returned, then POST /v1/auth/verify.
  • Redirect with code — if a callback URL is configured for the project.

Callback URL and redirect

Zapnoty does not redirect the browser automatically. If a callback URL is set for the project, after confirmation the bot shows the user a "go to site" button linking to:

{callback_url}?code=<code>&state=<urlencoded state>

  • code — always; state — if it was passed to /v1/auth/session.
  • The callback URL is taken from the redirect_uri of the /v1/auth/session request or from the project settings. Any URL used must be in the project allowlist (project settings → authorization) — exact match, open-redirect protection.
  • If no callback URL is configured — the flow is notification-only: the bot just shows a success message, and you receive the data via the auth.completed webhook.

Customizing authorization texts

The authorization message text and button label are configured via PUT /v1/sender (fields auth_text and auth_button_text, multilingual {ru, en}). auth_text must contain the {{url}} variable (≤500 chars), auth_button_text — ≤32 chars. Project management.

Related sections