A Go client library for interacting with the Message Gateway Bot API. This client provides a comprehensive set of methods for managing bots, channels, chats, dialogs, messages, and more.
go get github.com/retailcrm/bot-api-client-goRequests use User-Agent: retailcrm-bot-api-client-go/<version> by default. The version is resolved from Go build information for the client dependency. Pass WithUserAgent to override it.
package main
import (
"github.com/retailcrm/bot-api-client-go"
"log"
)
func main() {
client, err := bot_api_client.NewClientWithResponses(
"https://mg-s1.retailcrm.pro/api/bot/v1/",
bot_api_client.WithBotToken("BOT_TOKEN"),
)
if err != nil {
log.Fatalf("Error creating client: %v", err)
return
}
}response, err := client.SendMessageWithResponse(
context.Background(),
bot_api_client.SendMessageJSONRequestBody{},
)
if err != nil {
log.Fatalf("Error sending message: %v", err)
}
if response.JSONDefault != nil {
log.Printf("Error: %s", response.JSONDefault.Errors[0])
}
if response.JSON200 != nil {
log.Printf("Message id: %d", response.JSON200.MessageId)
}package main
import (
"context"
"github.com/retailcrm/bot-api-client-go/ws"
"log"
)
func main() {
controller, err := ws.NewController(
"wss://mg-s1.retailcrm.pro/api/bot/v1/ws",
"BOT_TOKEN",
)
if err != nil {
log.Fatalf("Error creating client: %v", err)
return
}
err = controller.SubscribeToReceiveEventsOperation(
context.Background(),
ws.EventsChannelParameters{Events: "message_new"},
func(ctx context.Context, msg ws.EventMessageFromEventsChannel) error {
switch data := msg.Payload.Data.(type) {
case ws.MessageDataSchema:
log.Printf("New event `%s` content: `%s`", msg.Payload.Type, *data.Message.Content)
}
return nil
},
)
if err != nil {
log.Fatalf("Error subscribing: %v", err)
return
}
select {}
}The library provides two built-in rate limiters. Configure one of them with the corresponding middleware.
- Recommended:
NewHeaderRateLimiter(initialLimit)follows the server'sX-RateLimit-Limit,X-RateLimit-Remaining, andX-RateLimit-Resetheaders. Before the first response with valid headers, it usesinitialLimit; the server headers then replace it. It reserves available slots for concurrent requests and waits for the reset time when the current window is exhausted. Use it when the API is the source of truth for the limit. NewDefaultLimiter(rate, burst)creates a local token-bucket limiter. It limits the average request rate toraterequests per second and permits short bursts of up toburstrequests. Use it only when server rate-limit headers are unavailable and the request rate is known by the client.
Do not combine the two limiters for the same request flow: they enforce different policies and would both delay requests.
limiter := bot_api_client.NewHeaderRateLimiter(70)
client, err := bot_api_client.NewClientWithResponses(
"https://mg-s1.retailcrm.pro/api/bot/v1/",
bot_api_client.WithMiddlewares(
bot_api_client.Limiter(limiter),
),
)The library supports middleware to wrap HTTP requests. Typical use cases are logging and rate limiting, but you can also implement your own (e.g. retries, tracing, headers injection).
package main
import (
"context"
"log"
"os"
"time"
"github.com/retailcrm/bot-api-client-go"
)
func main() {
// standard Go logger
stdLogger := log.New(os.Stdout, "[bot-api] ", log.LstdFlags)
logger := bot_api_client.NewDefaultLogger(stdLogger)
// rate limiter: 2 requests per second, burst up to 5
limiter := bot_api_client.NewDefaultLimiter(2, 5)
// create client with middlewares
client, err := bot_api_client.NewClientWithResponses(
"https://api.example.com",
bot_api_client.WithMiddlewares(
bot_api_client.Logging(logger),
bot_api_client.Limiter(limiter),
),
)
if err != nil {
log.Fatalf("failed to create client: %v", err)
}
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
resp, err := client.SendMessageWithResponse(
ctx,
bot_api_client.SendMessageRequestBody{},
)
if err != nil {
log.Fatalf("request failed: %v", err)
}
log.Printf("status: %s", resp.Status)
}Middlewares are applied in the order they are passed to WithMiddlewares.
That means the following code:
WithMiddlewares(
Logging(logger),
Limiter(limiter),
)will wrap the underlying HTTP client like this:
Request
│
▼
Logging (start := time.Now())
│ └── measures total time:
│ - waiting in Limiter
│ - network request
│ - response handling
▼
Limiter (may wait before sending)
│
▼
Transport (http.Client → real HTTP request)
│
▼
Logging (dur := time.Since(start))
So:
- The request goes through
Loggingfirst, - then through
Limiter, - and finally reaches the underlying HTTP transport.
A middleware has the signature:
type Middleware func(HttpRequestDoer) HttpRequestDoerIt receives the next HttpRequestDoer in the chain and must return a new one.
This allows you to implement cross-cutting concerns like logging, tracing, caching, retries, etc.
Middleware typically has three phases:
- Before — runs before calling
next.Do(req)(e.g. inject headers, modify context). - Do — forwards the request to the next middleware or transport.
- After — runs after the response is received or an error occurred.
func RequestIDMiddleware() bot_api_client.Middleware {
return func(next bot_api_client.HttpRequestDoer) bot_api_client.HttpRequestDoer {
return bot_api_client.DoerFunc(func(req *http.Request) (*http.Response, error) {
// BEFORE: add a request ID into context and header
reqID := uuid.New().String()
ctx := context.WithValue(req.Context(), "requestID", reqID)
req = req.WithContext(ctx)
req.Header.Set("X-Request-ID", reqID)
// DO: pass to the next middleware / transport
resp, err := next.Do(req)
// AFTER: log result with the request ID
if err != nil {
log.Printf("[req:%s] failed: %v", reqID, err)
return nil, err
}
log.Printf("[req:%s] completed with status %d", reqID, resp.StatusCode)
return resp, nil
})
}
}client, err := bot_api_client.NewClient(
"https://api.example.com",
bot_api_client.WithMiddlewares(
RequestIDMiddleware(),
bot_api_client.Logging(logger),
),
)This middleware:
- Before: generates a unique request ID, stores it in the request context, and sets the
X-Request-IDheader. - Do: forwards the request to the next handler.
- After: logs the outcome together with the request ID.