MAX
16 мин··

Примеры MAX Bot API на Go и Python без лишней магии

Минимальные и понятные примеры на Go и Python: отправка сообщений, webhook, секреты и аккуратная обработка ошибок в MAX Bot API.

Фактические детали в этой статье сверены по официальной документации MAX. Практики очередей, fallback-каналов и продуктовые советы здесь даны как инженерные рекомендации, а не как обещание платформы. Создание ботов, обзор Bot API, отправка сообщений, webhook, загрузка файлов.

Что общее для Go и Python

И Go, и Python хорошо подходят для MAX Bot API. Разница не в “правильном языке”, а в том, как вы держите базовую дисциплину: правильный URL, заголовок авторизации, обработка ошибок, очередь и webhook secret.

Важно не смешивать два разных слоя. Ниже в этой статье примеры именно для официального MAX Bot API. Если вы работаете через Relaya API и вам нужен уже готовый клиент, начните с Python SDK или общего обзора SDK Relaya.

  • Базовый домен: https://platform-api.max.ru.
  • Авторизация: Authorization: Bearer YOUR_MAX_BOT_TOKEN.
  • Для продового webhook нужен секрет и быстрый ответ сервером.
  • На 429 и 5xx не стоит отвечать мгновенным повтором в лоб.

Если нужно сначала понять саму модель API, лучше начать с общего обзора, а потом возвращаться к примерам кода.

Go: отправка сообщения

package main

import (
  "bytes"
  "encoding/json"
  "fmt"
  "net/http"
  "os"
  "time"
)

type sendMessageRequest struct {
  Text string `json:"text"`
}

func sendMessage(chatID string, text string) error {
  payload, _ := json.Marshal(sendMessageRequest{Text: text})

  req, err := http.NewRequest(
    http.MethodPost,
    fmt.Sprintf("https://platform-api.max.ru/messages?chat_id=%s", chatID),
    bytes.NewReader(payload),
  )
  if err != nil {
    return err
  }

  req.Header.Set("Authorization", "Bearer "+os.Getenv("MAX_BOT_TOKEN"))
  req.Header.Set("Content-Type", "application/json")

  client := &http.Client{Timeout: 30 * time.Second}
  resp, err := client.Do(req)
  if err != nil {
    return err
  }
  defer resp.Body.Close()

  if resp.StatusCode >= 400 {
    return fmt.Errorf("max api returned status %d", resp.StatusCode)
  }

  return nil
}

Для первого запуска этого достаточно. Дальше вы уже добавляете idempotency на своей стороне, очередь и retry.

Go: webhook

package main

import (
  "encoding/json"
  "net/http"
  "os"
)

type update struct {
  UpdateType string `json:"update_type"`
}

func webhookHandler(w http.ResponseWriter, r *http.Request) {
  if r.Header.Get("X-Max-Bot-Api-Secret") != os.Getenv("MAX_WEBHOOK_SECRET") {
    http.Error(w, "unauthorized", http.StatusUnauthorized)
    return
  }

  var body update
  if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
    http.Error(w, "bad request", http.StatusBadRequest)
    return
  }

  w.WriteHeader(http.StatusOK)
  _, _ = w.Write([]byte(`{"ok":true}`))

  go processUpdate(body)
}

Главное правило тут простое: сначала быстро подтвердить приём события, потом заниматься бизнес-логикой.

Python: отправка сообщения

import os
import requests

def send_message(chat_id: str, text: str) -> dict:
    response = requests.post(
        f"https://platform-api.max.ru/messages?chat_id={chat_id}",
        headers={
            "Authorization": f"Bearer {os.environ['MAX_BOT_TOKEN']}",
            "Content-Type": "application/json",
        },
        json={"text": text},
        timeout=30,
    )
    response.raise_for_status()
    return response.json()

Если дальше вам нужен control flow по ошибкам, добавляйте backoff вокруг этой функции, а не встраивайте жёсткий retry в каждую точку вызова.

Python: webhook

from fastapi import FastAPI, Header, HTTPException, Request

app = FastAPI()

@app.post("/webhook/max")
async def receive_update(
    request: Request,
    x_max_bot_api_secret: str | None = Header(default=None),
):
    if x_max_bot_api_secret != os.environ["MAX_WEBHOOK_SECRET"]:
        raise HTTPException(status_code=401, detail="unauthorized")

    update = await request.json()

    # Здесь лучше быстро подтвердить приём и вынести обработку в очередь
    await events_queue.put(update)
    return {"ok": True}

Для локальной разработки можно временно использовать long polling и читать события через GET /updates. Но как только вы идёте в продукт, webhook почти всегда удобнее и честнее.

Что не забыть перед продом

  • Не храните токен в коде, только в переменных окружения или секретном хранилище.
  • Отделите “ошибка запроса” от “ошибка темпа”: 400 и 401 не лечатся retry.
  • На 429 снижайте RPS и отправляйте задачу в очередь, а не спорьте с каналом.
  • Проверяйте webhook secret всегда, даже во внутренних стендах.

Если хочется закрыть инфраструктурную часть аккуратно, дальше полезно читать про лимиты, про 429 и про токены и секреты.

Полезный пример кода для MAX Bot API это не полторы тысячи строк “готового фреймворка”, а короткий клиент, понятный webhook и несколько правил, которые не дадут интеграции развалиться после первого реального трафика.

Создайте бесплатный MAX-профиль

Если хочется не просто читать, а сразу проверить сценарий руками: подключите MAX, отправьте себе тестовое сообщение и уже потом решайте, нужны ли другие каналы.