Skip to main content

Calling the API

gotd generates a Go method for every method in the Telegram schema. You reach them through client.API(), which returns a *tg.Client.

return client.Run(ctx, func(ctx context.Context) error {
api := client.API()

state, err := api.UpdatesGetState(ctx)
if err != nil {
return err
}
// state: &tg.UpdatesState{Pts:197 Qts:0 Date:1606855030 Seq:1 UnreadCount:106}
fmt.Printf("%+v\n", state)
return nil
})

api is also obtainable as tg.NewClient(client) — the two are equivalent, and the latter is handy when you want the raw client without the telegram.Client wrapper (for example inside a takeout session).

Naming convention​

Schema method names map to Go method names by dropping dots and PascalCasing:

Telegram methodgotd method
help.getNearestDCapi.HelpGetNearestDC
auth.signInapi.AuthSignIn
messages.sendMessageapi.MessagesSendMessage
channels.getParticipantsapi.ChannelsGetParticipants

Methods with several parameters take a generated request struct:

res, err := api.MessagesGetMessages(ctx, []tg.InputMessageClass{
&tg.InputMessageID{ID: 42},
})

Each generated type carries the official Telegram documentation as Go doc comments, including links back to core.telegram.org.

Sum types: the ...Class interfaces​

Where the schema has a type with multiple constructors, gotd generates an interface named SomethingClass and one struct per constructor. Use a type switch to handle them:

res, err := api.MessagesGetMessages(ctx, ids)
if err != nil {
return err
}
switch m := res.(type) {
case *tg.MessagesMessages:
useMessages(m.Messages)
case *tg.MessagesMessagesSlice:
useMessages(m.Messages)
case *tg.MessagesChannelMessages:
useMessages(m.Messages)
}

Many generated types also offer helpers like AsNotEmpty() and typed getters (GetUsername()) that return (value, ok) for optional fields.

Errors and FLOOD_WAIT​

RPC errors come back as *tgerr.Error. Match them by type with the tgerr package:

import "github.com/gotd/td/tgerr"

if _, err := api.MessagesSendMessage(ctx, req); err != nil {
if tgerr.Is(err, "FLOOD_WAIT") {
// rate limited; back off
}
return err
}

Rather than handle FLOOD_WAIT everywhere, install the floodwait middleware, which retries automatically.

MTProto JSON​

You can also invoke methods using Telegram's MTProto JSON format via api.InvokeJSON, passing JSON with an @type field and receiving JSON back. This is useful for bridging dynamic callers; for Go code the typed methods above are preferred.

When to drop to the raw API​

The helpers cover the common cases (sending messages, uploads, downloads, pagination) far more ergonomically. Reach for the raw API when you need a method the helpers don't wrap — which is most of the schema.