all repos — telegram-bot-api @ 42d132b90a3e5cf1146827cdd7c2f1f8757221de

Golang bindings for the Telegram Bot API

configs.go (view raw)

  1package tgbotapi
  2
  3import (
  4	"encoding/json"
  5	"io"
  6	"net/url"
  7	"strconv"
  8)
  9
 10// Telegram constants
 11const (
 12	// APIEndpoint is the endpoint for all API methods,
 13	// with formatting for Sprintf.
 14	APIEndpoint = "https://api.telegram.org/bot%s/%s"
 15	// FileEndpoint is the endpoint for downloading a file from Telegram.
 16	FileEndpoint = "https://api.telegram.org/file/bot%s/%s"
 17)
 18
 19// Constant values for ChatActions
 20const (
 21	ChatTyping         = "typing"
 22	ChatUploadPhoto    = "upload_photo"
 23	ChatRecordVideo    = "record_video"
 24	ChatUploadVideo    = "upload_video"
 25	ChatRecordAudio    = "record_audio"
 26	ChatUploadAudio    = "upload_audio"
 27	ChatUploadDocument = "upload_document"
 28	ChatFindLocation   = "find_location"
 29)
 30
 31// API errors
 32const (
 33	// ErrAPIForbidden happens when a token is bad
 34	ErrAPIForbidden = "forbidden"
 35)
 36
 37// Constant values for ParseMode in MessageConfig
 38const (
 39	ModeMarkdown = "Markdown"
 40	ModeHTML     = "HTML"
 41)
 42
 43// Library errors
 44const (
 45	// ErrBadFileType happens when you pass an unknown type
 46	ErrBadFileType = "bad file type"
 47	ErrBadURL      = "bad or empty url"
 48)
 49
 50// Chattable is any config type that can be sent.
 51type Chattable interface {
 52	values() (url.Values, error)
 53	method() string
 54}
 55
 56// Fileable is any config type that can be sent that includes a file.
 57type Fileable interface {
 58	Chattable
 59	params() (map[string]string, error)
 60	name() string
 61	getFile() interface{}
 62	useExistingFile() bool
 63}
 64
 65// BaseChat is base type for all chat config types.
 66type BaseChat struct {
 67	ChatID              int64 // required
 68	ChannelUsername     string
 69	ReplyToMessageID    int
 70	ReplyMarkup         interface{}
 71	DisableNotification bool
 72}
 73
 74// values returns url.Values representation of BaseChat
 75func (chat *BaseChat) values() (url.Values, error) {
 76	v := url.Values{}
 77	if chat.ChannelUsername != "" {
 78		v.Add("chat_id", chat.ChannelUsername)
 79	} else {
 80		v.Add("chat_id", strconv.FormatInt(chat.ChatID, 10))
 81	}
 82
 83	if chat.ReplyToMessageID != 0 {
 84		v.Add("reply_to_message_id", strconv.Itoa(chat.ReplyToMessageID))
 85	}
 86
 87	if chat.ReplyMarkup != nil {
 88		data, err := json.Marshal(chat.ReplyMarkup)
 89		if err != nil {
 90			return v, err
 91		}
 92
 93		v.Add("reply_markup", string(data))
 94	}
 95
 96	v.Add("disable_notification", strconv.FormatBool(chat.DisableNotification))
 97
 98	return v, nil
 99}
100
101// BaseFile is a base type for all file config types.
102type BaseFile struct {
103	BaseChat
104	File        interface{}
105	FileID      string
106	UseExisting bool
107	MimeType    string
108	FileSize    int
109}
110
111// params returns a map[string]string representation of BaseFile.
112func (file BaseFile) params() (map[string]string, error) {
113	params := make(map[string]string)
114
115	if file.ChannelUsername != "" {
116		params["chat_id"] = file.ChannelUsername
117	} else {
118		params["chat_id"] = strconv.FormatInt(file.ChatID, 10)
119	}
120
121	if file.ReplyToMessageID != 0 {
122		params["reply_to_message_id"] = strconv.Itoa(file.ReplyToMessageID)
123	}
124
125	if file.ReplyMarkup != nil {
126		data, err := json.Marshal(file.ReplyMarkup)
127		if err != nil {
128			return params, err
129		}
130
131		params["reply_markup"] = string(data)
132	}
133
134	if file.MimeType != "" {
135		params["mime_type"] = file.MimeType
136	}
137
138	if file.FileSize > 0 {
139		params["file_size"] = strconv.Itoa(file.FileSize)
140	}
141
142	params["disable_notification"] = strconv.FormatBool(file.DisableNotification)
143
144	return params, nil
145}
146
147// getFile returns the file.
148func (file BaseFile) getFile() interface{} {
149	return file.File
150}
151
152// useExistingFile returns if the BaseFile has already been uploaded.
153func (file BaseFile) useExistingFile() bool {
154	return file.UseExisting
155}
156
157// BaseEdit is base type of all chat edits.
158type BaseEdit struct {
159	ChatID          int64
160	ChannelUsername string
161	MessageID       int
162	InlineMessageID string
163	ReplyMarkup     *InlineKeyboardMarkup
164}
165
166func (edit BaseEdit) values() (url.Values, error) {
167	v := url.Values{}
168
169	if edit.InlineMessageID == "" {
170		if edit.ChannelUsername != "" {
171			v.Add("chat_id", edit.ChannelUsername)
172		} else {
173			v.Add("chat_id", strconv.FormatInt(edit.ChatID, 10))
174		}
175		v.Add("message_id", strconv.Itoa(edit.MessageID))
176	} else {
177		v.Add("inline_message_id", edit.InlineMessageID)
178	}
179
180	if edit.ReplyMarkup != nil {
181		data, err := json.Marshal(edit.ReplyMarkup)
182		if err != nil {
183			return v, err
184		}
185		v.Add("reply_markup", string(data))
186	}
187
188	return v, nil
189}
190
191// MessageConfig contains information about a SendMessage request.
192type MessageConfig struct {
193	BaseChat
194	Text                  string
195	ParseMode             string
196	DisableWebPagePreview bool
197}
198
199// values returns a url.Values representation of MessageConfig.
200func (config MessageConfig) values() (url.Values, error) {
201	v, err := config.BaseChat.values()
202	if err != nil {
203		return v, err
204	}
205	v.Add("text", config.Text)
206	v.Add("disable_web_page_preview", strconv.FormatBool(config.DisableWebPagePreview))
207	if config.ParseMode != "" {
208		v.Add("parse_mode", config.ParseMode)
209	}
210
211	return v, nil
212}
213
214// method returns Telegram API method name for sending Message.
215func (config MessageConfig) method() string {
216	return "sendMessage"
217}
218
219// ForwardConfig contains information about a ForwardMessage request.
220type ForwardConfig struct {
221	BaseChat
222	FromChatID          int64 // required
223	FromChannelUsername string
224	MessageID           int // required
225}
226
227// values returns a url.Values representation of ForwardConfig.
228func (config ForwardConfig) values() (url.Values, error) {
229	v, err := config.BaseChat.values()
230	if err != nil {
231		return v, err
232	}
233	v.Add("from_chat_id", strconv.FormatInt(config.FromChatID, 10))
234	v.Add("message_id", strconv.Itoa(config.MessageID))
235	return v, nil
236}
237
238// method returns Telegram API method name for sending Forward.
239func (config ForwardConfig) method() string {
240	return "forwardMessage"
241}
242
243// PhotoConfig contains information about a SendPhoto request.
244type PhotoConfig struct {
245	BaseFile
246	Caption string
247}
248
249// Params returns a map[string]string representation of PhotoConfig.
250func (config PhotoConfig) params() (map[string]string, error) {
251	params, _ := config.BaseFile.params()
252
253	if config.Caption != "" {
254		params["caption"] = config.Caption
255	}
256
257	return params, nil
258}
259
260// Values returns a url.Values representation of PhotoConfig.
261func (config PhotoConfig) values() (url.Values, error) {
262	v, err := config.BaseChat.values()
263	if err != nil {
264		return v, err
265	}
266
267	v.Add(config.name(), config.FileID)
268	if config.Caption != "" {
269		v.Add("caption", config.Caption)
270	}
271	return v, nil
272}
273
274// name returns the field name for the Photo.
275func (config PhotoConfig) name() string {
276	return "photo"
277}
278
279// method returns Telegram API method name for sending Photo.
280func (config PhotoConfig) method() string {
281	return "sendPhoto"
282}
283
284// AudioConfig contains information about a SendAudio request.
285type AudioConfig struct {
286	BaseFile
287	Caption   string
288	Duration  int
289	Performer string
290	Title     string
291}
292
293// values returns a url.Values representation of AudioConfig.
294func (config AudioConfig) values() (url.Values, error) {
295	v, err := config.BaseChat.values()
296	if err != nil {
297		return v, err
298	}
299
300	v.Add(config.name(), config.FileID)
301	if config.Duration != 0 {
302		v.Add("duration", strconv.Itoa(config.Duration))
303	}
304
305	if config.Performer != "" {
306		v.Add("performer", config.Performer)
307	}
308	if config.Title != "" {
309		v.Add("title", config.Title)
310	}
311	if config.Caption != "" {
312		v.Add("caption", config.Caption)
313	}
314
315	return v, nil
316}
317
318// params returns a map[string]string representation of AudioConfig.
319func (config AudioConfig) params() (map[string]string, error) {
320	params, _ := config.BaseFile.params()
321
322	if config.Duration != 0 {
323		params["duration"] = strconv.Itoa(config.Duration)
324	}
325
326	if config.Performer != "" {
327		params["performer"] = config.Performer
328	}
329	if config.Title != "" {
330		params["title"] = config.Title
331	}
332	if config.Caption != "" {
333		params["caption"] = config.Caption
334	}
335
336	return params, nil
337}
338
339// name returns the field name for the Audio.
340func (config AudioConfig) name() string {
341	return "audio"
342}
343
344// method returns Telegram API method name for sending Audio.
345func (config AudioConfig) method() string {
346	return "sendAudio"
347}
348
349// DocumentConfig contains information about a SendDocument request.
350type DocumentConfig struct {
351	BaseFile
352	Caption string
353}
354
355// values returns a url.Values representation of DocumentConfig.
356func (config DocumentConfig) values() (url.Values, error) {
357	v, err := config.BaseChat.values()
358	if err != nil {
359		return v, err
360	}
361
362	v.Add(config.name(), config.FileID)
363	if config.Caption != "" {
364		v.Add("caption", config.Caption)
365	}
366
367	return v, nil
368}
369
370// params returns a map[string]string representation of DocumentConfig.
371func (config DocumentConfig) params() (map[string]string, error) {
372	params, _ := config.BaseFile.params()
373
374	if config.Caption != "" {
375		params["caption"] = config.Caption
376	}
377
378	return params, nil
379}
380
381// name returns the field name for the Document.
382func (config DocumentConfig) name() string {
383	return "document"
384}
385
386// method returns Telegram API method name for sending Document.
387func (config DocumentConfig) method() string {
388	return "sendDocument"
389}
390
391// StickerConfig contains information about a SendSticker request.
392type StickerConfig struct {
393	BaseFile
394}
395
396// values returns a url.Values representation of StickerConfig.
397func (config StickerConfig) values() (url.Values, error) {
398	v, err := config.BaseChat.values()
399	if err != nil {
400		return v, err
401	}
402
403	v.Add(config.name(), config.FileID)
404
405	return v, nil
406}
407
408// params returns a map[string]string representation of StickerConfig.
409func (config StickerConfig) params() (map[string]string, error) {
410	params, _ := config.BaseFile.params()
411
412	return params, nil
413}
414
415// name returns the field name for the Sticker.
416func (config StickerConfig) name() string {
417	return "sticker"
418}
419
420// method returns Telegram API method name for sending Sticker.
421func (config StickerConfig) method() string {
422	return "sendSticker"
423}
424
425// VideoConfig contains information about a SendVideo request.
426type VideoConfig struct {
427	BaseFile
428	Duration int
429	Caption  string
430}
431
432// values returns a url.Values representation of VideoConfig.
433func (config VideoConfig) values() (url.Values, error) {
434	v, err := config.BaseChat.values()
435	if err != nil {
436		return v, err
437	}
438
439	v.Add(config.name(), config.FileID)
440	if config.Duration != 0 {
441		v.Add("duration", strconv.Itoa(config.Duration))
442	}
443	if config.Caption != "" {
444		v.Add("caption", config.Caption)
445	}
446
447	return v, nil
448}
449
450// params returns a map[string]string representation of VideoConfig.
451func (config VideoConfig) params() (map[string]string, error) {
452	params, _ := config.BaseFile.params()
453
454	if config.Caption != "" {
455		params["caption"] = config.Caption
456	}
457
458	return params, nil
459}
460
461// name returns the field name for the Video.
462func (config VideoConfig) name() string {
463	return "video"
464}
465
466// method returns Telegram API method name for sending Video.
467func (config VideoConfig) method() string {
468	return "sendVideo"
469}
470
471// VideoNoteConfig contains information about a SendVideoNote request.
472type VideoNoteConfig struct {
473	BaseFile
474	Duration int
475	Length   int
476}
477
478// values returns a url.Values representation of VideoNoteConfig.
479func (config VideoNoteConfig) values() (url.Values, error) {
480	v, err := config.BaseChat.values()
481	if err != nil {
482		return v, err
483	}
484
485	v.Add(config.name(), config.FileID)
486	if config.Duration != 0 {
487		v.Add("duration", strconv.Itoa(config.Duration))
488	}
489
490	// Telegram API seems to have a bug, if no length is provided or it is 0, it will send an error response
491	if config.Length != 0 {
492		v.Add("length", strconv.Itoa(config.Length))
493	}
494
495	return v, nil
496}
497
498// params returns a map[string]string representation of VideoNoteConfig.
499func (config VideoNoteConfig) params() (map[string]string, error) {
500	params, _ := config.BaseFile.params()
501
502	if config.Length != 0 {
503		params["length"] = strconv.Itoa(config.Length)
504	}
505	if config.Duration != 0 {
506		params["duration"] = strconv.Itoa(config.Duration)
507	}
508
509	return params, nil
510}
511
512// name returns the field name for the VideoNote.
513func (config VideoNoteConfig) name() string {
514	return "video_note"
515}
516
517// method returns Telegram API method name for sending VideoNote.
518func (config VideoNoteConfig) method() string {
519	return "sendVideoNote"
520}
521
522// VoiceConfig contains information about a SendVoice request.
523type VoiceConfig struct {
524	BaseFile
525	Caption  string
526	Duration int
527}
528
529// values returns a url.Values representation of VoiceConfig.
530func (config VoiceConfig) values() (url.Values, error) {
531	v, err := config.BaseChat.values()
532	if err != nil {
533		return v, err
534	}
535
536	v.Add(config.name(), config.FileID)
537	if config.Duration != 0 {
538		v.Add("duration", strconv.Itoa(config.Duration))
539	}
540	if config.Caption != "" {
541		v.Add("caption", config.Caption)
542	}
543
544	return v, nil
545}
546
547// params returns a map[string]string representation of VoiceConfig.
548func (config VoiceConfig) params() (map[string]string, error) {
549	params, _ := config.BaseFile.params()
550
551	if config.Duration != 0 {
552		params["duration"] = strconv.Itoa(config.Duration)
553	}
554	if config.Caption != "" {
555		params["caption"] = config.Caption
556	}
557
558	return params, nil
559}
560
561// name returns the field name for the Voice.
562func (config VoiceConfig) name() string {
563	return "voice"
564}
565
566// method returns Telegram API method name for sending Voice.
567func (config VoiceConfig) method() string {
568	return "sendVoice"
569}
570
571// LocationConfig contains information about a SendLocation request.
572type LocationConfig struct {
573	BaseChat
574	Latitude  float64 // required
575	Longitude float64 // required
576}
577
578// values returns a url.Values representation of LocationConfig.
579func (config LocationConfig) values() (url.Values, error) {
580	v, err := config.BaseChat.values()
581	if err != nil {
582		return v, err
583	}
584
585	v.Add("latitude", strconv.FormatFloat(config.Latitude, 'f', 6, 64))
586	v.Add("longitude", strconv.FormatFloat(config.Longitude, 'f', 6, 64))
587
588	return v, nil
589}
590
591// method returns Telegram API method name for sending Location.
592func (config LocationConfig) method() string {
593	return "sendLocation"
594}
595
596// VenueConfig contains information about a SendVenue request.
597type VenueConfig struct {
598	BaseChat
599	Latitude     float64 // required
600	Longitude    float64 // required
601	Title        string  // required
602	Address      string  // required
603	FoursquareID string
604}
605
606func (config VenueConfig) values() (url.Values, error) {
607	v, err := config.BaseChat.values()
608	if err != nil {
609		return v, err
610	}
611
612	v.Add("latitude", strconv.FormatFloat(config.Latitude, 'f', 6, 64))
613	v.Add("longitude", strconv.FormatFloat(config.Longitude, 'f', 6, 64))
614	v.Add("title", config.Title)
615	v.Add("address", config.Address)
616	if config.FoursquareID != "" {
617		v.Add("foursquare_id", config.FoursquareID)
618	}
619
620	return v, nil
621}
622
623func (config VenueConfig) method() string {
624	return "sendVenue"
625}
626
627// ContactConfig allows you to send a contact.
628type ContactConfig struct {
629	BaseChat
630	PhoneNumber string
631	FirstName   string
632	LastName    string
633}
634
635func (config ContactConfig) values() (url.Values, error) {
636	v, err := config.BaseChat.values()
637	if err != nil {
638		return v, err
639	}
640
641	v.Add("phone_number", config.PhoneNumber)
642	v.Add("first_name", config.FirstName)
643	v.Add("last_name", config.LastName)
644
645	return v, nil
646}
647
648func (config ContactConfig) method() string {
649	return "sendContact"
650}
651
652// GameConfig allows you to send a game.
653type GameConfig struct {
654	BaseChat
655	GameShortName string
656}
657
658func (config GameConfig) values() (url.Values, error) {
659	v, err := config.BaseChat.values()
660	if err != nil {
661		return v, err
662	}
663
664	v.Add("game_short_name", config.GameShortName)
665
666	return v, nil
667}
668
669func (config GameConfig) method() string {
670	return "sendGame"
671}
672
673// SetGameScoreConfig allows you to update the game score in a chat.
674type SetGameScoreConfig struct {
675	UserID             int
676	Score              int
677	Force              bool
678	DisableEditMessage bool
679	ChatID             int
680	ChannelUsername    string
681	MessageID          int
682	InlineMessageID    string
683}
684
685func (config SetGameScoreConfig) values() (url.Values, error) {
686	v := url.Values{}
687
688	v.Add("user_id", strconv.Itoa(config.UserID))
689	v.Add("score", strconv.Itoa(config.Score))
690	if config.InlineMessageID == "" {
691		if config.ChannelUsername == "" {
692			v.Add("chat_id", strconv.Itoa(config.ChatID))
693		} else {
694			v.Add("chat_id", config.ChannelUsername)
695		}
696		v.Add("message_id", strconv.Itoa(config.MessageID))
697	} else {
698		v.Add("inline_message_id", config.InlineMessageID)
699	}
700	v.Add("disable_edit_message", strconv.FormatBool(config.DisableEditMessage))
701
702	return v, nil
703}
704
705func (config SetGameScoreConfig) method() string {
706	return "setGameScore"
707}
708
709// GetGameHighScoresConfig allows you to fetch the high scores for a game.
710type GetGameHighScoresConfig struct {
711	UserID          int
712	ChatID          int
713	ChannelUsername string
714	MessageID       int
715	InlineMessageID string
716}
717
718func (config GetGameHighScoresConfig) values() (url.Values, error) {
719	v := url.Values{}
720
721	v.Add("user_id", strconv.Itoa(config.UserID))
722	if config.InlineMessageID == "" {
723		if config.ChannelUsername == "" {
724			v.Add("chat_id", strconv.Itoa(config.ChatID))
725		} else {
726			v.Add("chat_id", config.ChannelUsername)
727		}
728		v.Add("message_id", strconv.Itoa(config.MessageID))
729	} else {
730		v.Add("inline_message_id", config.InlineMessageID)
731	}
732
733	return v, nil
734}
735
736func (config GetGameHighScoresConfig) method() string {
737	return "getGameHighScores"
738}
739
740// ChatActionConfig contains information about a SendChatAction request.
741type ChatActionConfig struct {
742	BaseChat
743	Action string // required
744}
745
746// values returns a url.Values representation of ChatActionConfig.
747func (config ChatActionConfig) values() (url.Values, error) {
748	v, err := config.BaseChat.values()
749	if err != nil {
750		return v, err
751	}
752	v.Add("action", config.Action)
753	return v, nil
754}
755
756// method returns Telegram API method name for sending ChatAction.
757func (config ChatActionConfig) method() string {
758	return "sendChatAction"
759}
760
761// EditMessageTextConfig allows you to modify the text in a message.
762type EditMessageTextConfig struct {
763	BaseEdit
764	Text                  string
765	ParseMode             string
766	DisableWebPagePreview bool
767}
768
769func (config EditMessageTextConfig) values() (url.Values, error) {
770	v, err := config.BaseEdit.values()
771	if err != nil {
772		return v, err
773	}
774
775	v.Add("text", config.Text)
776	v.Add("parse_mode", config.ParseMode)
777	v.Add("disable_web_page_preview", strconv.FormatBool(config.DisableWebPagePreview))
778
779	return v, nil
780}
781
782func (config EditMessageTextConfig) method() string {
783	return "editMessageText"
784}
785
786// EditMessageCaptionConfig allows you to modify the caption of a message.
787type EditMessageCaptionConfig struct {
788	BaseEdit
789	Caption string
790}
791
792func (config EditMessageCaptionConfig) values() (url.Values, error) {
793	v, _ := config.BaseEdit.values()
794
795	v.Add("caption", config.Caption)
796
797	return v, nil
798}
799
800func (config EditMessageCaptionConfig) method() string {
801	return "editMessageCaption"
802}
803
804// EditMessageReplyMarkupConfig allows you to modify the reply markup
805// of a message.
806type EditMessageReplyMarkupConfig struct {
807	BaseEdit
808}
809
810func (config EditMessageReplyMarkupConfig) values() (url.Values, error) {
811	return config.BaseEdit.values()
812}
813
814func (config EditMessageReplyMarkupConfig) method() string {
815	return "editMessageReplyMarkup"
816}
817
818// UserProfilePhotosConfig contains information about a
819// GetUserProfilePhotos request.
820type UserProfilePhotosConfig struct {
821	UserID int
822	Offset int
823	Limit  int
824}
825
826// FileConfig has information about a file hosted on Telegram.
827type FileConfig struct {
828	FileID string
829}
830
831// UpdateConfig contains information about a GetUpdates request.
832type UpdateConfig struct {
833	Offset  int
834	Limit   int
835	Timeout int
836}
837
838// WebhookConfig contains information about a SetWebhook request.
839type WebhookConfig struct {
840	URL            *url.URL
841	Certificate    interface{}
842	MaxConnections int
843}
844
845// FileBytes contains information about a set of bytes to upload
846// as a File.
847type FileBytes struct {
848	Name  string
849	Bytes []byte
850}
851
852// FileReader contains information about a reader to upload as a File.
853// If Size is -1, it will read the entire Reader into memory to
854// calculate a Size.
855type FileReader struct {
856	Name   string
857	Reader io.Reader
858	Size   int64
859}
860
861// InlineConfig contains information on making an InlineQuery response.
862type InlineConfig struct {
863	InlineQueryID     string        `json:"inline_query_id"`
864	Results           []interface{} `json:"results"`
865	CacheTime         int           `json:"cache_time"`
866	IsPersonal        bool          `json:"is_personal"`
867	NextOffset        string        `json:"next_offset"`
868	SwitchPMText      string        `json:"switch_pm_text"`
869	SwitchPMParameter string        `json:"switch_pm_parameter"`
870}
871
872// CallbackConfig contains information on making a CallbackQuery response.
873type CallbackConfig struct {
874	CallbackQueryID string `json:"callback_query_id"`
875	Text            string `json:"text"`
876	ShowAlert       bool   `json:"show_alert"`
877	URL             string `json:"url"`
878	CacheTime       int    `json:"cache_time"`
879}
880
881// ChatMemberConfig contains information about a user in a chat for use
882// with administrative functions such as kicking or unbanning a user.
883type ChatMemberConfig struct {
884	ChatID             int64
885	SuperGroupUsername string
886	UserID             int
887}
888
889// ChatConfig contains information about getting information on a chat.
890type ChatConfig struct {
891	ChatID             int64
892	SuperGroupUsername string
893}
894
895// ChatConfigWithUser contains information about getting information on
896// a specific user within a chat.
897type ChatConfigWithUser struct {
898	ChatID             int64
899	SuperGroupUsername string
900	UserID             int
901}
902
903type InvoiceConfig struct {
904	BaseChat
905	Title               string          // required
906	Description         string          // required
907	Payload             string          // required
908	ProviderToken       string          // required
909	StartParameter      string          // required
910	Currency            string          // required
911	Prices              *[]LabeledPrice // required
912	PhotoUrl            string
913	PhotoSize           int
914	PhotoWidth          int
915	PhotoHeight         int
916	NeedName            bool
917	NeedPhoneNumber     bool
918	NeedEmail           bool
919	NeedShippingAddress bool
920	IsFlexible          bool
921}
922
923func (config InvoiceConfig) values() (url.Values, error) {
924	v, err := config.BaseChat.values()
925	if err != nil {
926		return v, err
927	}
928	v.Add("title", config.Title)
929	v.Add("description", config.Description)
930	v.Add("payload", config.Payload)
931	v.Add("provider_token", config.ProviderToken)
932	v.Add("start_parameter", config.StartParameter)
933	v.Add("currency", config.Currency)
934	data, err := json.Marshal(config.Prices)
935	if err != nil {
936		return v, err
937	}
938	v.Add("prices", string(data))
939	if config.PhotoUrl != "" {
940		v.Add("photo_url", config.PhotoUrl)
941	}
942	if config.PhotoSize != 0 {
943		v.Add("photo_size", strconv.Itoa(config.PhotoSize))
944	}
945	if config.PhotoWidth != 0 {
946		v.Add("photo_width", strconv.Itoa(config.PhotoWidth))
947	}
948	if config.PhotoHeight != 0 {
949		v.Add("photo_height", strconv.Itoa(config.PhotoHeight))
950	}
951	if config.NeedName != false {
952		v.Add("need_name", strconv.FormatBool(config.NeedName))
953	}
954	if config.NeedPhoneNumber != false {
955		v.Add("need_phone_number", strconv.FormatBool(config.NeedPhoneNumber))
956	}
957	if config.NeedEmail != false {
958		v.Add("need_email", strconv.FormatBool(config.NeedEmail))
959	}
960	if config.NeedShippingAddress != false {
961		v.Add("need_shipping_address", strconv.FormatBool(config.NeedShippingAddress))
962	}
963	if config.IsFlexible != false {
964		v.Add("is_flexible", strconv.FormatBool(config.IsFlexible))
965	}
966
967	return v, nil
968}
969
970func (config InvoiceConfig) method() string {
971	return "sendInvoice"
972}
973
974type ShippingConfig struct {
975	ShippingQueryID string // required
976	Ok              bool   // required
977	ShippingOptions *[]ShippingOption
978	ErrorMessage    string
979}
980
981type PreCheckoutConfig struct {
982	PreCheckoutQueryID string // required
983	Ok                 bool   // required
984	ErrorMessage       string
985}