Skip to content

maxigo-bot/maxigo-client

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

15 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

maxigo-client

Go Reference Go Report Card CI codecov License: MIT Go Version

Idiomatic Go HTTP client for Max Bot API (OpenAPI schema v0.0.10). Zero external dependencies.

Why This Project?

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.

Documentation

Installation

go get github.com/maxigo-bot/maxigo-client

Quick Start

package 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)
}

Bot API v2 and the Russian Trusted CA

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.

Features

  • 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

Type-Safe Constructors

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 clipboard

Attachments:

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)      // location

Example — 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
}

API Overview

// 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)

Error Handling

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.

Ecosystem

Package Description
maxigo-client Idiomatic Go HTTP client for Max Bot API (zero external deps)
maxigo-bot Bot framework with router, middleware, and context

License

MIT