all repos — telegram-bot-api @ 26a3c9542175cf8cf2ae304c8ad0548dfe65fae7

Golang bindings for the Telegram Bot API

types.go (view raw)

   1package tgbotapi
   2
   3import (
   4	"encoding/json"
   5	"errors"
   6	"fmt"
   7	"net/url"
   8	"strings"
   9	"time"
  10)
  11
  12// APIResponse is a response from the Telegram API with the result
  13// stored raw.
  14type APIResponse struct {
  15	Ok          bool                `json:"ok"`
  16	Result      json.RawMessage     `json:"result"`
  17	ErrorCode   int                 `json:"error_code"`
  18	Description string              `json:"description"`
  19	Parameters  *ResponseParameters `json:"parameters"`
  20}
  21
  22// ResponseParameters are various errors that can be returned in APIResponse.
  23type ResponseParameters struct {
  24	MigrateToChatID int64 `json:"migrate_to_chat_id"` // optional
  25	RetryAfter      int   `json:"retry_after"`        // optional
  26}
  27
  28// Update is an update response, from GetUpdates.
  29type Update struct {
  30	UpdateID           int                 `json:"update_id"`
  31	Message            *Message            `json:"message"`
  32	EditedMessage      *Message            `json:"edited_message"`
  33	ChannelPost        *Message            `json:"channel_post"`
  34	EditedChannelPost  *Message            `json:"edited_channel_post"`
  35	InlineQuery        *InlineQuery        `json:"inline_query"`
  36	ChosenInlineResult *ChosenInlineResult `json:"chosen_inline_result"`
  37	CallbackQuery      *CallbackQuery      `json:"callback_query"`
  38	ShippingQuery      *ShippingQuery      `json:"shipping_query"`
  39	PreCheckoutQuery   *PreCheckoutQuery   `json:"pre_checkout_query"`
  40}
  41
  42// UpdatesChannel is the channel for getting updates.
  43type UpdatesChannel <-chan Update
  44
  45// Clear discards all unprocessed incoming updates.
  46func (ch UpdatesChannel) Clear() {
  47	for len(ch) != 0 {
  48		<-ch
  49	}
  50}
  51
  52// User represents a Telegram user or bot.
  53type User struct {
  54	// ID is a unique identifier for this user or bot
  55	ID int `json:"id"`
  56	// FirstName user's or bot's first name
  57	FirstName string `json:"first_name"`
  58	// LastName user's or bot's last name
  59	// optional
  60	LastName string `json:"last_name"`
  61	// UserName user's or bot's username
  62	// optional
  63	UserName string `json:"username"`
  64	// LanguageCode IETF language tag of the user's language
  65	// more info: https://en.wikipedia.org/wiki/IETF_language_tag
  66	// optional
  67	LanguageCode string `json:"language_code"`
  68	// IsBot true, if this user is a bot
  69	// optional
  70	IsBot bool `json:"is_bot"`
  71}
  72
  73// String displays a simple text version of a user.
  74//
  75// It is normally a user's username, but falls back to a first/last
  76// name as available.
  77func (u *User) String() string {
  78	if u == nil {
  79		return ""
  80	}
  81	if u.UserName != "" {
  82		return u.UserName
  83	}
  84
  85	name := u.FirstName
  86	if u.LastName != "" {
  87		name += " " + u.LastName
  88	}
  89
  90	return name
  91}
  92
  93// GroupChat is a group chat.
  94type GroupChat struct {
  95	ID    int    `json:"id"`
  96	Title string `json:"title"`
  97}
  98
  99// ChatPhoto represents a chat photo.
 100type ChatPhoto struct {
 101	// SmallFileID is a file identifier of small (160x160) chat photo.
 102	// This file_id can be used only for photo download and
 103	// only for as long as the photo is not changed.
 104	SmallFileID string `json:"small_file_id"`
 105	// BigFileID is a file identifier of big (640x640) chat photo.
 106	// This file_id can be used only for photo download and
 107	// only for as long as the photo is not changed.
 108	BigFileID string `json:"big_file_id"`
 109}
 110
 111// Chat contains information about the place a message was sent.
 112type Chat struct {
 113	// ID is a unique identifier for this chat
 114	ID int64 `json:"id"`
 115	// Type of chat, can be either “private”, “group”, “supergroup” or “channel”
 116	Type string `json:"type"`
 117	// Title for supergroups, channels and group chats
 118	// optional
 119	Title string `json:"title"`
 120	// UserName for private chats, supergroups and channels if available
 121	// optional
 122	UserName string `json:"username"`
 123	// FirstName of the other party in a private chat
 124	// optional
 125	FirstName string `json:"first_name"`
 126	// LastName of the other party in a private chat
 127	// optional
 128	LastName string `json:"last_name"`
 129	// AllMembersAreAdmins
 130	// optional
 131	AllMembersAreAdmins bool `json:"all_members_are_administrators"`
 132	// Photo is a chat photo
 133	Photo *ChatPhoto `json:"photo"`
 134	// Description for groups, supergroups and channel chats
 135	// optional
 136	Description string `json:"description,omitempty"`
 137	// InviteLink is a chat invite link, for groups, supergroups and channel chats.
 138	// Each administrator in a chat generates their own invite links,
 139	// so the bot must first generate the link using exportChatInviteLink
 140	// optional
 141	InviteLink string `json:"invite_link,omitempty"`
 142	// PinnedMessage Pinned message, for groups, supergroups and channels
 143	// optional
 144	PinnedMessage *Message `json:"pinned_message"`
 145}
 146
 147// IsPrivate returns if the Chat is a private conversation.
 148func (c Chat) IsPrivate() bool {
 149	return c.Type == "private"
 150}
 151
 152// IsGroup returns if the Chat is a group.
 153func (c Chat) IsGroup() bool {
 154	return c.Type == "group"
 155}
 156
 157// IsSuperGroup returns if the Chat is a supergroup.
 158func (c Chat) IsSuperGroup() bool {
 159	return c.Type == "supergroup"
 160}
 161
 162// IsChannel returns if the Chat is a channel.
 163func (c Chat) IsChannel() bool {
 164	return c.Type == "channel"
 165}
 166
 167// ChatConfig returns a ChatConfig struct for chat related methods.
 168func (c Chat) ChatConfig() ChatConfig {
 169	return ChatConfig{ChatID: c.ID}
 170}
 171
 172// Message is returned by almost every request, and contains data about
 173// almost anything.
 174type Message struct {
 175	// MessageID is a unique message identifier inside this chat
 176	MessageID int `json:"message_id"`
 177	// From is a sender, empty for messages sent to channels;
 178	// optional
 179	From *User `json:"from"`
 180	// Date of the message was sent in Unix time
 181	Date int `json:"date"`
 182	// Chat is the conversation the message belongs to
 183	Chat *Chat `json:"chat"`
 184	// ForwardFrom for forwarded messages, sender of the original message;
 185	// optional
 186	ForwardFrom *User `json:"forward_from"`
 187	// ForwardFromChat for messages forwarded from channels,
 188	// information about the original channel;
 189	// optional
 190	ForwardFromChat *Chat `json:"forward_from_chat"`
 191	// ForwardFromMessageID for messages forwarded from channels,
 192	// identifier of the original message in the channel;
 193	// optional
 194	ForwardFromMessageID int `json:"forward_from_message_id"`
 195	// ForwardDate for forwarded messages, date the original message was sent in Unix time;
 196	// optional
 197	ForwardDate int `json:"forward_date"`
 198	// ReplyToMessage for replies, the original message.
 199	// Note that the Message object in this field will not contain further ReplyToMessage fields
 200	// even if it itself is a reply;
 201	// optional
 202	ReplyToMessage *Message `json:"reply_to_message"`
 203	// ViaBot through which the message was sent;
 204	// optional
 205	ViaBot *User `json:"via_bot"`
 206	// EditDate of the message was last edited in Unix time;
 207	// optional
 208	EditDate int `json:"edit_date"`
 209	// MediaGroupID is the unique identifier of a media message group this message belongs to;
 210	// optional
 211	MediaGroupID string `json:"media_group_id"`
 212	// AuthorSignature is the signature of the post author for messages in channels;
 213	// optional
 214	AuthorSignature string `json:"author_signature"`
 215	// Text is for text messages, the actual UTF-8 text of the message, 0-4096 characters;
 216	// optional
 217	Text string `json:"text"`
 218	// Entities is for text messages, special entities like usernames,
 219	// URLs, bot commands, etc. that appear in the text;
 220	// optional
 221	Entities *[]MessageEntity `json:"entities"`
 222	// CaptionEntities;
 223	// optional
 224	CaptionEntities *[]MessageEntity `json:"caption_entities"`
 225	// Audio message is an audio file, information about the file;
 226	// optional
 227	Audio *Audio `json:"audio"`
 228	// Document message is a general file, information about the file;
 229	// optional
 230	Document *Document `json:"document"`
 231	// Animation message is an animation, information about the animation.
 232	// For backward compatibility, when this field is set, the document field will also be set;
 233	// optional
 234	Animation *ChatAnimation `json:"animation"`
 235	// Game message is a game, information about the game;
 236	// optional
 237	Game *Game `json:"game"`
 238	// Photo message is a photo, available sizes of the photo;
 239	// optional
 240	Photo *[]PhotoSize `json:"photo"`
 241	// Sticker message is a sticker, information about the sticker;
 242	// optional
 243	Sticker *Sticker `json:"sticker"`
 244	// Video message is a video, information about the video;
 245	// optional
 246	Video *Video `json:"video"`
 247	// VideoNote message is a video note, information about the video message;
 248	// optional
 249	VideoNote *VideoNote `json:"video_note"`
 250	// Voice message is a voice message, information about the file;
 251	// optional
 252	Voice *Voice `json:"voice"`
 253	// Caption for the animation, audio, document, photo, video or voice, 0-1024 characters;
 254	// optional
 255	Caption string `json:"caption"`
 256	// Contact message is a shared contact, information about the contact;
 257	// optional
 258	Contact *Contact `json:"contact"`
 259	// Location message is a shared location, information about the location;
 260	// optional
 261	Location *Location `json:"location"`
 262	// Venue message is a venue, information about the venue.
 263	// For backward compatibility, when this field is set, the location field will also be set;
 264	// optional
 265	Venue *Venue `json:"venue"`
 266	// NewChatMembers that were added to the group or supergroup
 267	// and information about them (the bot itself may be one of these members);
 268	// optional
 269	NewChatMembers *[]User `json:"new_chat_members"`
 270	// LeftChatMember is a member was removed from the group,
 271	// information about them (this member may be the bot itself);
 272	// optional
 273	LeftChatMember *User `json:"left_chat_member"`
 274	// NewChatTitle is a chat title was changed to this value;
 275	// optional
 276	NewChatTitle string `json:"new_chat_title"`
 277	// NewChatPhoto is a chat photo was change to this value;
 278	// optional
 279	NewChatPhoto *[]PhotoSize `json:"new_chat_photo"`
 280	// DeleteChatPhoto is a service message: the chat photo was deleted;
 281	// optional
 282	DeleteChatPhoto bool `json:"delete_chat_photo"`
 283	// GroupChatCreated is a service message: the group has been created;
 284	// optional
 285	GroupChatCreated bool `json:"group_chat_created"`
 286	// SuperGroupChatCreated is a service message: the supergroup has been created.
 287	// This field can't be received in a message coming through updates,
 288	// because bot can't be a member of a supergroup when it is created.
 289	// It can only be found in ReplyToMessage if someone replies to a very first message
 290	// in a directly created supergroup;
 291	// optional
 292	SuperGroupChatCreated bool `json:"supergroup_chat_created"`
 293	// ChannelChatCreated is a service message: the channel has been created.
 294	// This field can't be received in a message coming through updates,
 295	// because bot can't be a member of a channel when it is created.
 296	// It can only be found in ReplyToMessage
 297	// if someone replies to a very first message in a channel;
 298	// optional
 299	ChannelChatCreated bool `json:"channel_chat_created"`
 300	// MigrateToChatID is the group has been migrated to a supergroup with the specified identifier.
 301	// This number may be greater than 32 bits and some programming languages
 302	// may have difficulty/silent defects in interpreting it.
 303	// But it is smaller than 52 bits, so a signed 64 bit integer
 304	// or double-precision float type are safe for storing this identifier;
 305	// optional
 306	MigrateToChatID int64 `json:"migrate_to_chat_id"`
 307	// MigrateFromChatID is the supergroup has been migrated from a group with the specified identifier.
 308	// This number may be greater than 32 bits and some programming languages
 309	// may have difficulty/silent defects in interpreting it.
 310	// But it is smaller than 52 bits, so a signed 64 bit integer
 311	// or double-precision float type are safe for storing this identifier;
 312	// optional
 313	MigrateFromChatID int64 `json:"migrate_from_chat_id"`
 314	// PinnedMessage is a specified message was pinned.
 315	// Note that the Message object in this field will not contain further ReplyToMessage
 316	// fields even if it is itself a reply;
 317	// optional
 318	PinnedMessage *Message `json:"pinned_message"`
 319	// Invoice message is an invoice for a payment;
 320	// optional
 321	Invoice *Invoice `json:"invoice"`
 322	// SuccessfulPayment message is a service message about a successful payment,
 323	// information about the payment;
 324	// optional
 325	SuccessfulPayment *SuccessfulPayment `json:"successful_payment"`
 326	// PassportData is a Telegram Passport data;
 327	// optional
 328	PassportData *PassportData `json:"passport_data,omitempty"`
 329}
 330
 331// Time converts the message timestamp into a Time.
 332func (m *Message) Time() time.Time {
 333	return time.Unix(int64(m.Date), 0)
 334}
 335
 336// IsCommand returns true if message starts with a "bot_command" entity.
 337func (m *Message) IsCommand() bool {
 338	if m.Entities == nil || len(*m.Entities) == 0 {
 339		return false
 340	}
 341
 342	entity := (*m.Entities)[0]
 343	return entity.Offset == 0 && entity.IsCommand()
 344}
 345
 346// Command checks if the message was a command and if it was, returns the
 347// command. If the Message was not a command, it returns an empty string.
 348//
 349// If the command contains the at name syntax, it is removed. Use
 350// CommandWithAt() if you do not want that.
 351func (m *Message) Command() string {
 352	command := m.CommandWithAt()
 353
 354	if i := strings.Index(command, "@"); i != -1 {
 355		command = command[:i]
 356	}
 357
 358	return command
 359}
 360
 361// CommandWithAt checks if the message was a command and if it was, returns the
 362// command. If the Message was not a command, it returns an empty string.
 363//
 364// If the command contains the at name syntax, it is not removed. Use Command()
 365// if you want that.
 366func (m *Message) CommandWithAt() string {
 367	if !m.IsCommand() {
 368		return ""
 369	}
 370
 371	// IsCommand() checks that the message begins with a bot_command entity
 372	entity := (*m.Entities)[0]
 373	return m.Text[1:entity.Length]
 374}
 375
 376// CommandArguments checks if the message was a command and if it was,
 377// returns all text after the command name. If the Message was not a
 378// command, it returns an empty string.
 379//
 380// Note: The first character after the command name is omitted:
 381// - "/foo bar baz" yields "bar baz", not " bar baz"
 382// - "/foo-bar baz" yields "bar baz", too
 383// Even though the latter is not a command conforming to the spec, the API
 384// marks "/foo" as command entity.
 385func (m *Message) CommandArguments() string {
 386	if !m.IsCommand() {
 387		return ""
 388	}
 389
 390	// IsCommand() checks that the message begins with a bot_command entity
 391	entity := (*m.Entities)[0]
 392	if len(m.Text) == entity.Length {
 393		return "" // The command makes up the whole message
 394	}
 395
 396	return m.Text[entity.Length+1:]
 397}
 398
 399// MessageEntity contains information about data in a Message.
 400type MessageEntity struct {
 401	// Type of the entity.
 402	// Can be:
 403	//  “mention” (@username),
 404	//  “hashtag” (#hashtag),
 405	//  “cashtag” ($USD),
 406	//  “bot_command” (/start@jobs_bot),
 407	//  “url” (https://telegram.org),
 408	//  “email” (do-not-reply@telegram.org),
 409	//  “phone_number” (+1-212-555-0123),
 410	//  “bold” (bold text),
 411	//  “italic” (italic text),
 412	//  “underline” (underlined text),
 413	//  “strikethrough” (strikethrough text),
 414	//  “code” (monowidth string),
 415	//  “pre” (monowidth block),
 416	//  “text_link” (for clickable text URLs),
 417	//  “text_mention” (for users without usernames)
 418	Type string `json:"type"`
 419	// Offset in UTF-16 code units to the start of the entity
 420	Offset int `json:"offset"`
 421	// Length
 422	Length int `json:"length"`
 423	// URL for “text_link” only, url that will be opened after user taps on the text
 424	// optional
 425	URL string `json:"url"`
 426	// User for “text_mention” only, the mentioned user
 427	// optional
 428	User *User `json:"user"`
 429}
 430
 431// ParseURL attempts to parse a URL contained within a MessageEntity.
 432func (e MessageEntity) ParseURL() (*url.URL, error) {
 433	if e.URL == "" {
 434		return nil, errors.New(ErrBadURL)
 435	}
 436
 437	return url.Parse(e.URL)
 438}
 439
 440// IsMention returns true if the type of the message entity is "mention" (@username).
 441func (e MessageEntity) IsMention() bool {
 442	return e.Type == "mention"
 443}
 444
 445// IsHashtag returns true if the type of the message entity is "hashtag".
 446func (e MessageEntity) IsHashtag() bool {
 447	return e.Type == "hashtag"
 448}
 449
 450// IsCommand returns true if the type of the message entity is "bot_command".
 451func (e MessageEntity) IsCommand() bool {
 452	return e.Type == "bot_command"
 453}
 454
 455// IsUrl returns true if the type of the message entity is "url".
 456func (e MessageEntity) IsUrl() bool {
 457	return e.Type == "url"
 458}
 459
 460// IsEmail returns true if the type of the message entity is "email".
 461func (e MessageEntity) IsEmail() bool {
 462	return e.Type == "email"
 463}
 464
 465// IsBold returns true if the type of the message entity is "bold" (bold text).
 466func (e MessageEntity) IsBold() bool {
 467	return e.Type == "bold"
 468}
 469
 470// IsItalic returns true if the type of the message entity is "italic" (italic text).
 471func (e MessageEntity) IsItalic() bool {
 472	return e.Type == "italic"
 473}
 474
 475// IsCode returns true if the type of the message entity is "code" (monowidth string).
 476func (e MessageEntity) IsCode() bool {
 477	return e.Type == "code"
 478}
 479
 480// IsPre returns true if the type of the message entity is "pre" (monowidth block).
 481func (e MessageEntity) IsPre() bool {
 482	return e.Type == "pre"
 483}
 484
 485// IsTextLink returns true if the type of the message entity is "text_link" (clickable text URL).
 486func (e MessageEntity) IsTextLink() bool {
 487	return e.Type == "text_link"
 488}
 489
 490// PhotoSize contains information about photos.
 491type PhotoSize struct {
 492	FileID   string `json:"file_id"`
 493	Width    int    `json:"width"`
 494	Height   int    `json:"height"`
 495	FileSize int    `json:"file_size"` // optional
 496}
 497
 498// Audio contains information about audio.
 499type Audio struct {
 500	FileID    string `json:"file_id"`
 501	Duration  int    `json:"duration"`
 502	Performer string `json:"performer"` // optional
 503	Title     string `json:"title"`     // optional
 504	MimeType  string `json:"mime_type"` // optional
 505	FileSize  int    `json:"file_size"` // optional
 506}
 507
 508// Document contains information about a document.
 509type Document struct {
 510	FileID    string     `json:"file_id"`
 511	Thumbnail *PhotoSize `json:"thumb"`     // optional
 512	FileName  string     `json:"file_name"` // optional
 513	MimeType  string     `json:"mime_type"` // optional
 514	FileSize  int        `json:"file_size"` // optional
 515}
 516
 517// Sticker contains information about a sticker.
 518type Sticker struct {
 519	FileUniqueID string     `json:"file_unique_id"`
 520	FileID       string     `json:"file_id"`
 521	Width        int        `json:"width"`
 522	Height       int        `json:"height"`
 523	Thumbnail    *PhotoSize `json:"thumb"`       // optional
 524	Emoji        string     `json:"emoji"`       // optional
 525	FileSize     int        `json:"file_size"`   // optional
 526	SetName      string     `json:"set_name"`    // optional
 527	IsAnimated   bool       `json:"is_animated"` // optional
 528}
 529
 530// StickerSet contains information about an sticker set.
 531type StickerSet struct {
 532	Name          string    `json:"name"`
 533	Title         string    `json:"title"`
 534	IsAnimated    bool      `json:"is_animated"`
 535	ContainsMasks bool      `json:"contains_masks"`
 536	Stickers      []Sticker `json:"stickers"`
 537}
 538
 539// ChatAnimation contains information about an animation.
 540type ChatAnimation struct {
 541	FileID    string     `json:"file_id"`
 542	Width     int        `json:"width"`
 543	Height    int        `json:"height"`
 544	Duration  int        `json:"duration"`
 545	Thumbnail *PhotoSize `json:"thumb"`     // optional
 546	FileName  string     `json:"file_name"` // optional
 547	MimeType  string     `json:"mime_type"` // optional
 548	FileSize  int        `json:"file_size"` // optional
 549}
 550
 551// Video contains information about a video.
 552type Video struct {
 553	FileID    string     `json:"file_id"`
 554	Width     int        `json:"width"`
 555	Height    int        `json:"height"`
 556	Duration  int        `json:"duration"`
 557	Thumbnail *PhotoSize `json:"thumb"`     // optional
 558	MimeType  string     `json:"mime_type"` // optional
 559	FileSize  int        `json:"file_size"` // optional
 560}
 561
 562// VideoNote contains information about a video.
 563type VideoNote struct {
 564	FileID    string     `json:"file_id"`
 565	Length    int        `json:"length"`
 566	Duration  int        `json:"duration"`
 567	Thumbnail *PhotoSize `json:"thumb"`     // optional
 568	FileSize  int        `json:"file_size"` // optional
 569}
 570
 571// Voice contains information about a voice.
 572type Voice struct {
 573	FileID   string `json:"file_id"`
 574	Duration int    `json:"duration"`
 575	MimeType string `json:"mime_type"` // optional
 576	FileSize int    `json:"file_size"` // optional
 577}
 578
 579// Contact contains information about a contact.
 580//
 581// Note that LastName and UserID may be empty.
 582type Contact struct {
 583	PhoneNumber string `json:"phone_number"`
 584	FirstName   string `json:"first_name"`
 585	LastName    string `json:"last_name"` // optional
 586	UserID      int    `json:"user_id"`   // optional
 587}
 588
 589// Location contains information about a place.
 590type Location struct {
 591	Longitude float64 `json:"longitude"`
 592	Latitude  float64 `json:"latitude"`
 593}
 594
 595// Venue contains information about a venue, including its Location.
 596type Venue struct {
 597	Location     Location `json:"location"`
 598	Title        string   `json:"title"`
 599	Address      string   `json:"address"`
 600	FoursquareID string   `json:"foursquare_id"` // optional
 601}
 602
 603// UserProfilePhotos contains a set of user profile photos.
 604type UserProfilePhotos struct {
 605	TotalCount int           `json:"total_count"`
 606	Photos     [][]PhotoSize `json:"photos"`
 607}
 608
 609// File contains information about a file to download from Telegram.
 610type File struct {
 611	FileID   string `json:"file_id"`
 612	FileSize int    `json:"file_size"` // optional
 613	FilePath string `json:"file_path"` // optional
 614}
 615
 616// Link returns a full path to the download URL for a File.
 617//
 618// It requires the Bot Token to create the link.
 619func (f *File) Link(token string) string {
 620	return fmt.Sprintf(FileEndpoint, token, f.FilePath)
 621}
 622
 623// ReplyKeyboardMarkup allows the Bot to set a custom keyboard.
 624type ReplyKeyboardMarkup struct {
 625	Keyboard        [][]KeyboardButton `json:"keyboard"`
 626	ResizeKeyboard  bool               `json:"resize_keyboard"`   // optional
 627	OneTimeKeyboard bool               `json:"one_time_keyboard"` // optional
 628	Selective       bool               `json:"selective"`         // optional
 629}
 630
 631// KeyboardButton is a button within a custom keyboard.
 632type KeyboardButton struct {
 633	Text            string `json:"text"`
 634	RequestContact  bool   `json:"request_contact"`
 635	RequestLocation bool   `json:"request_location"`
 636}
 637
 638// ReplyKeyboardHide allows the Bot to hide a custom keyboard.
 639type ReplyKeyboardHide struct {
 640	HideKeyboard bool `json:"hide_keyboard"`
 641	Selective    bool `json:"selective"` // optional
 642}
 643
 644// ReplyKeyboardRemove allows the Bot to hide a custom keyboard.
 645type ReplyKeyboardRemove struct {
 646	RemoveKeyboard bool `json:"remove_keyboard"`
 647	Selective      bool `json:"selective"`
 648}
 649
 650// InlineKeyboardMarkup is a custom keyboard presented for an inline bot.
 651type InlineKeyboardMarkup struct {
 652	InlineKeyboard [][]InlineKeyboardButton `json:"inline_keyboard"`
 653}
 654
 655// InlineKeyboardButton is a button within a custom keyboard for
 656// inline query responses.
 657//
 658// Note that some values are references as even an empty string
 659// will change behavior.
 660//
 661// CallbackGame, if set, MUST be first button in first row.
 662type InlineKeyboardButton struct {
 663	Text                         string        `json:"text"`
 664	URL                          *string       `json:"url,omitempty"`                              // optional
 665	CallbackData                 *string       `json:"callback_data,omitempty"`                    // optional
 666	SwitchInlineQuery            *string       `json:"switch_inline_query,omitempty"`              // optional
 667	SwitchInlineQueryCurrentChat *string       `json:"switch_inline_query_current_chat,omitempty"` // optional
 668	CallbackGame                 *CallbackGame `json:"callback_game,omitempty"`                    // optional
 669	Pay                          bool          `json:"pay,omitempty"`                              // optional
 670}
 671
 672// CallbackQuery is data sent when a keyboard button with callback data
 673// is clicked.
 674type CallbackQuery struct {
 675	ID              string   `json:"id"`
 676	From            *User    `json:"from"`
 677	Message         *Message `json:"message"`           // optional
 678	InlineMessageID string   `json:"inline_message_id"` // optional
 679	ChatInstance    string   `json:"chat_instance"`
 680	Data            string   `json:"data"`            // optional
 681	GameShortName   string   `json:"game_short_name"` // optional
 682}
 683
 684// ForceReply allows the Bot to have users directly reply to it without
 685// additional interaction.
 686type ForceReply struct {
 687	ForceReply bool `json:"force_reply"`
 688	Selective  bool `json:"selective"` // optional
 689}
 690
 691// ChatMember is information about a member in a chat.
 692type ChatMember struct {
 693	User                  *User  `json:"user"`
 694	Status                string `json:"status"`
 695	CustomTitle           string `json:"custom_title,omitempty"`              // optional
 696	UntilDate             int64  `json:"until_date,omitempty"`                // optional
 697	CanBeEdited           bool   `json:"can_be_edited,omitempty"`             // optional
 698	CanChangeInfo         bool   `json:"can_change_info,omitempty"`           // optional
 699	CanPostMessages       bool   `json:"can_post_messages,omitempty"`         // optional
 700	CanEditMessages       bool   `json:"can_edit_messages,omitempty"`         // optional
 701	CanDeleteMessages     bool   `json:"can_delete_messages,omitempty"`       // optional
 702	CanInviteUsers        bool   `json:"can_invite_users,omitempty"`          // optional
 703	CanRestrictMembers    bool   `json:"can_restrict_members,omitempty"`      // optional
 704	CanPinMessages        bool   `json:"can_pin_messages,omitempty"`          // optional
 705	CanPromoteMembers     bool   `json:"can_promote_members,omitempty"`       // optional
 706	CanSendMessages       bool   `json:"can_send_messages,omitempty"`         // optional
 707	CanSendMediaMessages  bool   `json:"can_send_media_messages,omitempty"`   // optional
 708	CanSendOtherMessages  bool   `json:"can_send_other_messages,omitempty"`   // optional
 709	CanAddWebPagePreviews bool   `json:"can_add_web_page_previews,omitempty"` // optional
 710}
 711
 712// IsCreator returns if the ChatMember was the creator of the chat.
 713func (chat ChatMember) IsCreator() bool { return chat.Status == "creator" }
 714
 715// IsAdministrator returns if the ChatMember is a chat administrator.
 716func (chat ChatMember) IsAdministrator() bool { return chat.Status == "administrator" }
 717
 718// IsMember returns if the ChatMember is a current member of the chat.
 719func (chat ChatMember) IsMember() bool { return chat.Status == "member" }
 720
 721// HasLeft returns if the ChatMember left the chat.
 722func (chat ChatMember) HasLeft() bool { return chat.Status == "left" }
 723
 724// WasKicked returns if the ChatMember was kicked from the chat.
 725func (chat ChatMember) WasKicked() bool { return chat.Status == "kicked" }
 726
 727// Game is a game within Telegram.
 728type Game struct {
 729	Title        string          `json:"title"`
 730	Description  string          `json:"description"`
 731	Photo        []PhotoSize     `json:"photo"`
 732	Text         string          `json:"text"`
 733	TextEntities []MessageEntity `json:"text_entities"`
 734	Animation    Animation       `json:"animation"`
 735}
 736
 737// Animation is a GIF animation demonstrating the game.
 738type Animation struct {
 739	FileID   string    `json:"file_id"`
 740	Thumb    PhotoSize `json:"thumb"`
 741	FileName string    `json:"file_name"`
 742	MimeType string    `json:"mime_type"`
 743	FileSize int       `json:"file_size"`
 744}
 745
 746// GameHighScore is a user's score and position on the leaderboard.
 747type GameHighScore struct {
 748	Position int  `json:"position"`
 749	User     User `json:"user"`
 750	Score    int  `json:"score"`
 751}
 752
 753// CallbackGame is for starting a game in an inline keyboard button.
 754type CallbackGame struct{}
 755
 756// WebhookInfo is information about a currently set webhook.
 757type WebhookInfo struct {
 758	URL                  string `json:"url"`
 759	HasCustomCertificate bool   `json:"has_custom_certificate"`
 760	PendingUpdateCount   int    `json:"pending_update_count"`
 761	LastErrorDate        int    `json:"last_error_date"`    // optional
 762	LastErrorMessage     string `json:"last_error_message"` // optional
 763	MaxConnections       int    `json:"max_connections"`    // optional
 764}
 765
 766// IsSet returns true if a webhook is currently set.
 767func (info WebhookInfo) IsSet() bool {
 768	return info.URL != ""
 769}
 770
 771// InputMediaPhoto contains a photo for displaying as part of a media group.
 772type InputMediaPhoto struct {
 773	Type      string `json:"type"`
 774	Media     string `json:"media"`
 775	Caption   string `json:"caption"`
 776	ParseMode string `json:"parse_mode"`
 777}
 778
 779// InputMediaVideo contains a video for displaying as part of a media group.
 780type InputMediaVideo struct {
 781	Type  string `json:"type"`
 782	Media string `json:"media"`
 783	// thumb intentionally missing as it is not currently compatible
 784	Caption           string `json:"caption"`
 785	ParseMode         string `json:"parse_mode"`
 786	Width             int    `json:"width"`
 787	Height            int    `json:"height"`
 788	Duration          int    `json:"duration"`
 789	SupportsStreaming bool   `json:"supports_streaming"`
 790}
 791
 792// InlineQuery is a Query from Telegram for an inline request.
 793type InlineQuery struct {
 794	ID       string    `json:"id"`
 795	From     *User     `json:"from"`
 796	Location *Location `json:"location"` // optional
 797	Query    string    `json:"query"`
 798	Offset   string    `json:"offset"`
 799}
 800
 801// InlineQueryResultArticle is an inline query response article.
 802type InlineQueryResultArticle struct {
 803	Type                string                `json:"type"`                            // required
 804	ID                  string                `json:"id"`                              // required
 805	Title               string                `json:"title"`                           // required
 806	InputMessageContent interface{}           `json:"input_message_content,omitempty"` // required
 807	ReplyMarkup         *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
 808	URL                 string                `json:"url"`
 809	HideURL             bool                  `json:"hide_url"`
 810	Description         string                `json:"description"`
 811	ThumbURL            string                `json:"thumb_url"`
 812	ThumbWidth          int                   `json:"thumb_width"`
 813	ThumbHeight         int                   `json:"thumb_height"`
 814}
 815
 816// InlineQueryResultPhoto is an inline query response photo.
 817type InlineQueryResultPhoto struct {
 818	Type                string                `json:"type"`      // required
 819	ID                  string                `json:"id"`        // required
 820	URL                 string                `json:"photo_url"` // required
 821	MimeType            string                `json:"mime_type"`
 822	Width               int                   `json:"photo_width"`
 823	Height              int                   `json:"photo_height"`
 824	ThumbURL            string                `json:"thumb_url"`
 825	Title               string                `json:"title"`
 826	Description         string                `json:"description"`
 827	Caption             string                `json:"caption"`
 828	ParseMode           string                `json:"parse_mode"`
 829	ReplyMarkup         *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
 830	InputMessageContent interface{}           `json:"input_message_content,omitempty"`
 831}
 832
 833// InlineQueryResultCachedPhoto is an inline query response with cached photo.
 834type InlineQueryResultCachedPhoto struct {
 835	Type                string                `json:"type"`          // required
 836	ID                  string                `json:"id"`            // required
 837	PhotoID             string                `json:"photo_file_id"` // required
 838	Title               string                `json:"title"`
 839	Description         string                `json:"description"`
 840	Caption             string                `json:"caption"`
 841	ParseMode           string                `json:"parse_mode"`
 842	ReplyMarkup         *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
 843	InputMessageContent interface{}           `json:"input_message_content,omitempty"`
 844}
 845
 846// InlineQueryResultGIF is an inline query response GIF.
 847type InlineQueryResultGIF struct {
 848	Type                string                `json:"type"`      // required
 849	ID                  string                `json:"id"`        // required
 850	URL                 string                `json:"gif_url"`   // required
 851	ThumbURL            string                `json:"thumb_url"` // required
 852	Width               int                   `json:"gif_width,omitempty"`
 853	Height              int                   `json:"gif_height,omitempty"`
 854	Duration            int                   `json:"gif_duration,omitempty"`
 855	Title               string                `json:"title,omitempty"`
 856	Caption             string                `json:"caption,omitempty"`
 857	ReplyMarkup         *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
 858	InputMessageContent interface{}           `json:"input_message_content,omitempty"`
 859}
 860
 861// InlineQueryResultCachedGIF is an inline query response with cached gif.
 862type InlineQueryResultCachedGIF struct {
 863	Type                string                `json:"type"`        // required
 864	ID                  string                `json:"id"`          // required
 865	GifID               string                `json:"gif_file_id"` // required
 866	Title               string                `json:"title"`
 867	Caption             string                `json:"caption"`
 868	ParseMode           string                `json:"parse_mode"`
 869	ReplyMarkup         *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
 870	InputMessageContent interface{}           `json:"input_message_content,omitempty"`
 871}
 872
 873// InlineQueryResultMPEG4GIF is an inline query response MPEG4 GIF.
 874type InlineQueryResultMPEG4GIF struct {
 875	Type                string                `json:"type"`      // required
 876	ID                  string                `json:"id"`        // required
 877	URL                 string                `json:"mpeg4_url"` // required
 878	Width               int                   `json:"mpeg4_width"`
 879	Height              int                   `json:"mpeg4_height"`
 880	Duration            int                   `json:"mpeg4_duration"`
 881	ThumbURL            string                `json:"thumb_url"`
 882	Title               string                `json:"title"`
 883	Caption             string                `json:"caption"`
 884	ReplyMarkup         *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
 885	InputMessageContent interface{}           `json:"input_message_content,omitempty"`
 886}
 887
 888// InlineQueryResultCachedMpeg4Gif is an inline query response with cached
 889// H.264/MPEG-4 AVC video without sound gif.
 890type InlineQueryResultCachedMpeg4Gif struct {
 891	Type                string                `json:"type"`          // required
 892	ID                  string                `json:"id"`            // required
 893	MGifID              string                `json:"mpeg4_file_id"` // required
 894	Title               string                `json:"title"`
 895	Caption             string                `json:"caption"`
 896	ParseMode           string                `json:"parse_mode"`
 897	ReplyMarkup         *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
 898	InputMessageContent interface{}           `json:"input_message_content,omitempty"`
 899}
 900
 901// InlineQueryResultVideo is an inline query response video.
 902type InlineQueryResultVideo struct {
 903	Type                string                `json:"type"`      // required
 904	ID                  string                `json:"id"`        // required
 905	URL                 string                `json:"video_url"` // required
 906	MimeType            string                `json:"mime_type"` // required
 907	ThumbURL            string                `json:"thumb_url"`
 908	Title               string                `json:"title"`
 909	Caption             string                `json:"caption"`
 910	Width               int                   `json:"video_width"`
 911	Height              int                   `json:"video_height"`
 912	Duration            int                   `json:"video_duration"`
 913	Description         string                `json:"description"`
 914	ReplyMarkup         *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
 915	InputMessageContent interface{}           `json:"input_message_content,omitempty"`
 916}
 917
 918// InlineQueryResultCachedVideo is an inline query response with cached video.
 919type InlineQueryResultCachedVideo struct {
 920	Type                string                `json:"type"`          // required
 921	ID                  string                `json:"id"`            // required
 922	VideoID             string                `json:"video_file_id"` // required
 923	Title               string                `json:"title"`         // required
 924	Description         string                `json:"description"`
 925	Caption             string                `json:"caption"`
 926	ParseMode           string                `json:"parse_mode"`
 927	ReplyMarkup         *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
 928	InputMessageContent interface{}           `json:"input_message_content,omitempty"`
 929}
 930
 931// InlineQueryResultCachedSticker is an inline query response with cached sticker.
 932type InlineQueryResultCachedSticker struct {
 933	Type                string                `json:"type"`            // required
 934	ID                  string                `json:"id"`              // required
 935	StickerID           string                `json:"sticker_file_id"` // required
 936	Title               string                `json:"title"`           // required
 937	ParseMode           string                `json:"parse_mode"`
 938	ReplyMarkup         *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
 939	InputMessageContent interface{}           `json:"input_message_content,omitempty"`
 940}
 941
 942// InlineQueryResultAudio is an inline query response audio.
 943type InlineQueryResultAudio struct {
 944	Type                string                `json:"type"`      // required
 945	ID                  string                `json:"id"`        // required
 946	URL                 string                `json:"audio_url"` // required
 947	Title               string                `json:"title"`     // required
 948	Caption             string                `json:"caption"`
 949	Performer           string                `json:"performer"`
 950	Duration            int                   `json:"audio_duration"`
 951	ReplyMarkup         *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
 952	InputMessageContent interface{}           `json:"input_message_content,omitempty"`
 953}
 954
 955// InlineQueryResultCachedAudio is an inline query response with cached audio.
 956type InlineQueryResultCachedAudio struct {
 957	Type                string                `json:"type"`          // required
 958	ID                  string                `json:"id"`            // required
 959	AudioID             string                `json:"audio_file_id"` // required
 960	Caption             string                `json:"caption"`
 961	ParseMode           string                `json:"parse_mode"`
 962	ReplyMarkup         *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
 963	InputMessageContent interface{}           `json:"input_message_content,omitempty"`
 964}
 965
 966// InlineQueryResultVoice is an inline query response voice.
 967type InlineQueryResultVoice struct {
 968	Type                string                `json:"type"`      // required
 969	ID                  string                `json:"id"`        // required
 970	URL                 string                `json:"voice_url"` // required
 971	Title               string                `json:"title"`     // required
 972	Caption             string                `json:"caption"`
 973	Duration            int                   `json:"voice_duration"`
 974	ReplyMarkup         *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
 975	InputMessageContent interface{}           `json:"input_message_content,omitempty"`
 976}
 977
 978// InlineQueryResultCachedVoice is an inline query response with cached voice.
 979type InlineQueryResultCachedVoice struct {
 980	Type                string                `json:"type"`          // required
 981	ID                  string                `json:"id"`            // required
 982	VoiceID             string                `json:"voice_file_id"` // required
 983	Title               string                `json:"title"`         // required
 984	Caption             string                `json:"caption"`
 985	ParseMode           string                `json:"parse_mode"`
 986	ReplyMarkup         *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
 987	InputMessageContent interface{}           `json:"input_message_content,omitempty"`
 988}
 989
 990// InlineQueryResultDocument is an inline query response document.
 991type InlineQueryResultDocument struct {
 992	Type                string                `json:"type"`  // required
 993	ID                  string                `json:"id"`    // required
 994	Title               string                `json:"title"` // required
 995	Caption             string                `json:"caption"`
 996	URL                 string                `json:"document_url"` // required
 997	MimeType            string                `json:"mime_type"`    // required
 998	Description         string                `json:"description"`
 999	ReplyMarkup         *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
1000	InputMessageContent interface{}           `json:"input_message_content,omitempty"`
1001	ThumbURL            string                `json:"thumb_url"`
1002	ThumbWidth          int                   `json:"thumb_width"`
1003	ThumbHeight         int                   `json:"thumb_height"`
1004}
1005
1006// InlineQueryResultCachedDocument is an inline query response with cached document.
1007type InlineQueryResultCachedDocument struct {
1008	Type                string                `json:"type"`             // required
1009	ID                  string                `json:"id"`               // required
1010	DocumentID          string                `json:"document_file_id"` // required
1011	Title               string                `json:"title"`            // required
1012	Caption             string                `json:"caption"`
1013	Description         string                `json:"description"`
1014	ParseMode           string                `json:"parse_mode"`
1015	ReplyMarkup         *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
1016	InputMessageContent interface{}           `json:"input_message_content,omitempty"`
1017}
1018
1019// InlineQueryResultLocation is an inline query response location.
1020type InlineQueryResultLocation struct {
1021	Type                string                `json:"type"`      // required
1022	ID                  string                `json:"id"`        // required
1023	Latitude            float64               `json:"latitude"`  // required
1024	Longitude           float64               `json:"longitude"` // required
1025	Title               string                `json:"title"`     // required
1026	ReplyMarkup         *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
1027	InputMessageContent interface{}           `json:"input_message_content,omitempty"`
1028	ThumbURL            string                `json:"thumb_url"`
1029	ThumbWidth          int                   `json:"thumb_width"`
1030	ThumbHeight         int                   `json:"thumb_height"`
1031}
1032
1033// InlineQueryResultVenue is an inline query response venue.
1034type InlineQueryResultVenue struct {
1035	Type                string                `json:"type"`      // required
1036	ID                  string                `json:"id"`        // required
1037	Latitude            float64               `json:"latitude"`  // required
1038	Longitude           float64               `json:"longitude"` // required
1039	Title               string                `json:"title"`     // required
1040	Address             string                `json:"address"`   // required
1041	FoursquareID        string                `json:"foursquare_id"`
1042	FoursquareType      string                `json:"foursquare_type"`
1043	ReplyMarkup         *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
1044	InputMessageContent interface{}           `json:"input_message_content,omitempty"`
1045	ThumbURL            string                `json:"thumb_url"`
1046	ThumbWidth          int                   `json:"thumb_width"`
1047	ThumbHeight         int                   `json:"thumb_height"`
1048}
1049
1050// InlineQueryResultGame is an inline query response game.
1051type InlineQueryResultGame struct {
1052	Type          string                `json:"type"`
1053	ID            string                `json:"id"`
1054	GameShortName string                `json:"game_short_name"`
1055	ReplyMarkup   *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
1056}
1057
1058// ChosenInlineResult is an inline query result chosen by a User
1059type ChosenInlineResult struct {
1060	ResultID        string    `json:"result_id"`
1061	From            *User     `json:"from"`
1062	Location        *Location `json:"location"`
1063	InlineMessageID string    `json:"inline_message_id"`
1064	Query           string    `json:"query"`
1065}
1066
1067// InputTextMessageContent contains text for displaying
1068// as an inline query result.
1069type InputTextMessageContent struct {
1070	Text                  string `json:"message_text"`
1071	ParseMode             string `json:"parse_mode"`
1072	DisableWebPagePreview bool   `json:"disable_web_page_preview"`
1073}
1074
1075// InputLocationMessageContent contains a location for displaying
1076// as an inline query result.
1077type InputLocationMessageContent struct {
1078	Latitude  float64 `json:"latitude"`
1079	Longitude float64 `json:"longitude"`
1080}
1081
1082// InputVenueMessageContent contains a venue for displaying
1083// as an inline query result.
1084type InputVenueMessageContent struct {
1085	Latitude     float64 `json:"latitude"`
1086	Longitude    float64 `json:"longitude"`
1087	Title        string  `json:"title"`
1088	Address      string  `json:"address"`
1089	FoursquareID string  `json:"foursquare_id"`
1090}
1091
1092// InputContactMessageContent contains a contact for displaying
1093// as an inline query result.
1094type InputContactMessageContent struct {
1095	PhoneNumber string `json:"phone_number"`
1096	FirstName   string `json:"first_name"`
1097	LastName    string `json:"last_name"`
1098}
1099
1100// Invoice contains basic information about an invoice.
1101type Invoice struct {
1102	Title          string `json:"title"`
1103	Description    string `json:"description"`
1104	StartParameter string `json:"start_parameter"`
1105	Currency       string `json:"currency"`
1106	TotalAmount    int    `json:"total_amount"`
1107}
1108
1109// LabeledPrice represents a portion of the price for goods or services.
1110type LabeledPrice struct {
1111	Label  string `json:"label"`
1112	Amount int    `json:"amount"`
1113}
1114
1115// ShippingAddress represents a shipping address.
1116type ShippingAddress struct {
1117	CountryCode string `json:"country_code"`
1118	State       string `json:"state"`
1119	City        string `json:"city"`
1120	StreetLine1 string `json:"street_line1"`
1121	StreetLine2 string `json:"street_line2"`
1122	PostCode    string `json:"post_code"`
1123}
1124
1125// OrderInfo represents information about an order.
1126type OrderInfo struct {
1127	Name            string           `json:"name,omitempty"`
1128	PhoneNumber     string           `json:"phone_number,omitempty"`
1129	Email           string           `json:"email,omitempty"`
1130	ShippingAddress *ShippingAddress `json:"shipping_address,omitempty"`
1131}
1132
1133// ShippingOption represents one shipping option.
1134type ShippingOption struct {
1135	ID     string          `json:"id"`
1136	Title  string          `json:"title"`
1137	Prices *[]LabeledPrice `json:"prices"`
1138}
1139
1140// SuccessfulPayment contains basic information about a successful payment.
1141type SuccessfulPayment struct {
1142	Currency                string     `json:"currency"`
1143	TotalAmount             int        `json:"total_amount"`
1144	InvoicePayload          string     `json:"invoice_payload"`
1145	ShippingOptionID        string     `json:"shipping_option_id,omitempty"`
1146	OrderInfo               *OrderInfo `json:"order_info,omitempty"`
1147	TelegramPaymentChargeID string     `json:"telegram_payment_charge_id"`
1148	ProviderPaymentChargeID string     `json:"provider_payment_charge_id"`
1149}
1150
1151// ShippingQuery contains information about an incoming shipping query.
1152type ShippingQuery struct {
1153	ID              string           `json:"id"`
1154	From            *User            `json:"from"`
1155	InvoicePayload  string           `json:"invoice_payload"`
1156	ShippingAddress *ShippingAddress `json:"shipping_address"`
1157}
1158
1159// PreCheckoutQuery contains information about an incoming pre-checkout query.
1160type PreCheckoutQuery struct {
1161	ID               string     `json:"id"`
1162	From             *User      `json:"from"`
1163	Currency         string     `json:"currency"`
1164	TotalAmount      int        `json:"total_amount"`
1165	InvoicePayload   string     `json:"invoice_payload"`
1166	ShippingOptionID string     `json:"shipping_option_id,omitempty"`
1167	OrderInfo        *OrderInfo `json:"order_info,omitempty"`
1168}
1169
1170// Error is an error containing extra information returned by the Telegram API.
1171type Error struct {
1172	Code    int
1173	Message string
1174	ResponseParameters
1175}
1176
1177func (e Error) Error() string {
1178	return e.Message
1179}
1180
1181// BotCommand represents a bot command.
1182type BotCommand struct {
1183	Command     string `json:"command"`
1184	Description string `json:"description"`
1185}