Idiomatic Go HTTP client for Max Bot API (OpenAPI schema v0.0.10). Zero external dependencies.
The official max-bot-api-client-go has systemic issues that make it unsuitable for production use:
| Category | Issues | Severity |
|---|---|---|
Errors swallowed via log.Println / slog.Error |
30+ places | Critical — library must not write to stdout |
| Untestable without real API | No WithBaseURL, uploads use http.DefaultClient |
Critical — impossible to unit test |
| Unnecessary dependencies | zerolog, yaml, env — 6 transitive deps | Critical — for an HTTP client |
| Broken API methods | GetChatID() returns 0 for callbacks |
Critical — callbacks unusable |
| Wrong types | time.Duration for Unix timestamps, int64→int casts |
Critical — data corruption on 32-bit |
No context.Context in uploads |
http.Get() without timeout or cancellation |
Critical — can hang forever |
| Non-idiomatic API | Builder pattern, SCREAMING_CASE, no functional options |
Major |
schemes.Error always non-nil |
Check() returns error even on success |
Critical — always errors |
maxigo-client fixes all of these.
- English Guide — full API reference with examples
- Документация на русском — полное описание API с примерами Requires Go 1.25+.
go get github.com/maxigo-bot/maxigo-clientpackage main
import (
"context"
"fmt"
"log"
maxigo "github.com/maxigo-bot/maxigo-client"
)
func main() {
client, err := maxigo.New("YOUR_BOT_TOKEN")
if err != nil {
log.Fatal(err)
}
bot, err := client.GetBot(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Printf("Bot: %s (ID: %d)\n", bot.FirstName, bot.UserID)
}The Max Bot API migrates to platform-api2.max.ru by 2026-07-19. The new
endpoint serves a TLS certificate issued by the Russian Trusted Root CA
(Минцифры), which is missing from most system trust stores — a default
http.Client fails the handshake with x509: certificate signed by unknown authority.
The root certificate is embedded into the library (no system-wide installation needed), and trusting it is a one-option switch:
client, err := maxigo.New("YOUR_BOT_TOKEN",
maxigo.WithBaseURL(maxigo.BaseURLV2), // https://platform-api2.max.ru
maxigo.WithRussianTrustedCA(), // trust the Минцифры root
)WithRussianTrustedCA() appends the root to the system pool, so regular
certificates (Let's Encrypt etc.) keep working, and only this client's
transport is affected — http.DefaultTransport is never touched.
If you bring your own http.Client via WithHTTPClient, build the pool
yourself:
pool, err := maxigo.RussianTrustedCertPool() // system roots + Минцифры root
// use it in your transport's tls.Config{RootCAs: pool}The raw certificate is exported as maxigo.RussianTrustedRootCAPEM
(valid until 2032-02-27). In a future release BaseURLV2 and the added root
will become the defaults.
- Zero external dependencies — only stdlib
- All methods take
context.Context - Structured error handling with
errors.As - Full Max Bot API coverage: messages, chats, uploads, webhooks, long polling
- Bot API v2 ready — embedded Russian Trusted Root CA (
WithRussianTrustedCA,BaseURLV2) - Type-safe constructors for all button types and attachments
- Contact ownership verification for
request_contact(VerifyHash) Optional[T]generics for three-state fields (unset / zero / value)- Opt-in automatic retry for rate limits and attachment processing (
WithRetry) - Testable without real API via
WithBaseURL
No need to remember string constants — use constructors for buttons and attachments:
Buttons:
maxigo.NewCallbackButton("Click", "payload") // callback
maxigo.NewCallbackButtonWithIntent("Yes", "yes", maxigo.IntentPositive) // callback with intent
maxigo.NewLinkButton("Open", "https://example.com") // link
maxigo.NewRequestContactButton("Share contact") // request contact
maxigo.NewRequestGeoLocationButton("Send location", true) // request geo (quick=true)
maxigo.NewChatButton("Create chat", "Title") // create chat
maxigo.NewMessageButton("Send") // message from user
maxigo.NewOpenAppButton("Open WebApp", "bot_username") // open mini-app
maxigo.NewClipboardButton("Copy code", "PROMO-2026") // copy payload to clipboardAttachments:
maxigo.NewInlineKeyboardAttachment(buttons) // inline keyboard
maxigo.NewPhotoAttachment(payload) // image
maxigo.NewVideoAttachment(payload) // video
maxigo.NewAudioAttachment(payload) // audio
maxigo.NewFileAttachment(payload) // file
maxigo.NewStickerAttachment(payload) // sticker
maxigo.NewContactAttachment(payload) // contact card
maxigo.NewShareAttachment(payload) // share link
maxigo.NewLocationAttachment(lat, lng) // locationExample — inline keyboard with contact and geo buttons:
msg, err := client.SendMessage(ctx, chatID, &maxigo.NewMessageBody{
Text: maxigo.Some("Choose an option:"),
Attachments: []maxigo.AttachmentRequest{
maxigo.NewInlineKeyboardAttachment([][]maxigo.Button{
{
maxigo.NewRequestContactButton("Share contact"),
maxigo.NewRequestGeoLocationButton("Send location", false),
},
{
maxigo.NewCallbackButtonWithIntent("Cancel", "cancel", maxigo.IntentNegative),
},
}),
},
})Verifying a shared contact:
When a user shares their phone number via a request_contact button, the
contact attachment carries a hash — HMAC-SHA256 of the vCard keyed with the
bot token. Verifying it proves the number belongs to the sender's Max account
(contacts sent any other way have no hash), so it can serve as a lightweight
authorization:
if contact.Payload.VerifyHash("YOUR_BOT_TOKEN") {
phone := contact.Payload.Phone() // verified number from the vCard
}// Bot
client.GetBot(ctx)
client.EditBot(ctx, patch)
// Messages
client.SendMessage(ctx, chatID, body)
client.SendMessageToUser(ctx, userID, body)
client.SendMessageToPhones(ctx, phoneNumbers, body)
client.EditMessage(ctx, messageID, body)
client.DeleteMessage(ctx, messageID)
client.AnswerCallback(ctx, callbackID, answer)
// Chats
client.GetChat(ctx, chatID)
client.GetChats(ctx, opts)
client.EditChat(ctx, chatID, patch)
client.GetMembers(ctx, chatID, opts)
client.SendAction(ctx, chatID, action)
// Phone numbers
client.CheckPhoneNumbers(ctx, phoneNumbers)
// Uploads
client.UploadPhoto(ctx, filename, reader)
client.UploadMedia(ctx, uploadType, filename, reader)
// Webhooks
client.Subscribe(ctx, url, types, secret)
client.Unsubscribe(ctx, url)
// Long Polling
client.GetUpdates(ctx, opts)var e *maxigo.Error
if errors.As(err, &e) {
fmt.Printf("[%s] %s %d: %s\n", e.Op, e.Kind, e.StatusCode, e.Message)
}Error kinds: ErrAPI, ErrNetwork, ErrTimeout, ErrDecode. See guide for details.
| Package | Description |
|---|---|
| maxigo-client | Idiomatic Go HTTP client for Max Bot API (zero external deps) |
| maxigo-bot | Bot framework with router, middleware, and context |
MIT