ZaminDocs

Webhook bilan joylashtirish

Production uchun: Zamin yangilanishlarni HTTPS orqali serveringizga yuboradi, Flask ilovasi ularni qabul qiladi. Maxfiy sarlavha tekshiriladi, javob darhol qaytariladi.

Talablar

  • Domen va ishonchli TLS sertifikat (masalan, Let's Encrypt). O'z-o'zidan imzolangan sertifikat ishlamaydi.
  • Port 443, 80, 88 yoki 8443. Server ommaviy IP manzilda bo'lishi kerak (SSRF qoidalari).
  • Python 3.8+, flask, requests, gunicorn.

1. Maxfiy kalit

Terminal
python3 -c "import secrets; print(secrets.token_urlsafe(32))"

Natija faqat A-Z a-z 0-9 _ - belgilaridan iborat — secret_token uchun mos.

2. Flask ilovasi

app.py
import hmac
import logging
import os

import requests
from flask import Flask, abort, request

TOKEN = os.environ["ZAMIN_BOT_TOKEN"]
SECRET = os.environ["ZAMIN_WEBHOOK_SECRET"]
API = f"https://api.zamin.app/bot{TOKEN}"

app = Flask(__name__)
log = logging.getLogger("bot")


def call(method, params):
    r = requests.post(f"{API}/{method}", json=params, timeout=5)
    body = r.json()
    if not body.get("ok"):
        log.warning("%s: %s %s", method, body.get("error_code"), body.get("description"))
    return body.get("result")


def handle(update):
    message = update.get("message")
    if message and "text" in message:
        chat_id = message["chat"]["id"]
        if message["text"].startswith("/start"):
            call("sendMessage", {"chat_id": chat_id, "text": "Salom! Men webhook orqali ishlayman 🚀"})
        else:
            call("sendMessage", {"chat_id": chat_id, "text": message["text"]})


@app.route("/zamin/webhook", methods=["POST"])
def webhook():
    # 1) Maxfiy sarlavhani doimiy vaqtli solishtirish bilan tekshiramiz
    got = request.headers.get("X-Zamin-Bot-Api-Secret-Token", "")
    if not hmac.compare_digest(got.encode(), SECRET.encode()):
        abort(403)
    update = request.get_json(silent=True)
    if not isinstance(update, dict):
        abort(400)
    # 2) Ichki xato bo'lsa ham 200 qaytaramiz: aks holda Zamin shu yangilanishni
    #    qayta-qayta yuboradi va keyingilari navbatda kutib qoladi.
    try:
        handle(update)
    except Exception:
        log.exception("update %s", update.get("update_id"))
    return "", 200


@app.route("/healthz")
def healthz():
    return "ok"

3. Ishga tushirish (gunicorn)

Terminal
pip3 install flask requests gunicorn
export ZAMIN_BOT_TOKEN="123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11"
export ZAMIN_WEBHOOK_SECRET="…1-qadamdagi qiymat…"
gunicorn -w 2 -b 127.0.0.1:8000 app:app

Oldiga TLS'ni hal qiladigan reverse proxy qo'ying (nginx, Caddy …) va /zamin/webhook'ni 127.0.0.1:8000'ga yo'naltiring. Masalan, nginx:

nginx
location /zamin/webhook {
    proxy_pass http://127.0.0.1:8000;
    proxy_set_header Host $host;
    client_max_body_size 1m;
}

4. Webhookni o'rnatish

set_webhook.py
import os

import requests

TOKEN = os.environ["ZAMIN_BOT_TOKEN"]
API = f"https://api.zamin.app/bot{TOKEN}"

r = requests.post(
    f"{API}/setWebhook",
    json={
        "url": os.environ["WEBHOOK_URL"],               # https://bot.example.com/zamin/webhook
        "secret_token": os.environ["ZAMIN_WEBHOOK_SECRET"],
        "allowed_updates": ["message", "callback_query", "my_chat_member"],
        "drop_pending_updates": False,
    },
    timeout=15,
)
print(r.json())
print(requests.get(f"{API}/getWebhookInfo", timeout=15).json())
Terminal
export WEBHOOK_URL="https://bot.example.com/zamin/webhook"
python3 set_webhook.py

5. systemd xizmati

/etc/systemd/system/zamin-bot.service
[Unit]
Description=Zamin bot (webhook)
After=network-online.target

[Service]
WorkingDirectory=/opt/zamin-bot
EnvironmentFile=/opt/zamin-bot/.env
ExecStart=/opt/zamin-bot/.venv/bin/gunicorn -w 2 -b 127.0.0.1:8000 app:app
Restart=always
User=zaminbot

[Install]
WantedBy=multi-user.target

.env faylida ZAMIN_BOT_TOKEN=… va ZAMIN_WEBHOOK_SECRET=… bo'ladi; unga faqat xizmat foydalanuvchisi kira olsin (chmod 600).

Tekshirish va nosozliklar

  • getWebhookInfo: pending_update_count o'sib borsa va last_error_message bo'lsa, yetkazishda muammo bor.
  • Wrong response from the webhook: 403 — sarlavha mos kelmayapti (secret noto'g'ri).
  • Connection timed out — javob 10 soniyadan uzoq: ishni fonga o'tkazing.
  • Connection failed — port yopiq, sertifikat noto'g'ri yoki server ishlamayapti.
  • Yetkazish ketma-ket: bitta yangilanishga xato qaytarsangiz, keyingilari ham kutadi. Shuning uchun app.py ichki xatoda ham 200 qaytaradi.
  • Tokenni /revoke qilsangiz, webhook o'chadi — set_webhook.py'ni yangi token bilan qayta ishga tushiring.