Java library for interacting with Telegram Bot API
- Full support of all Bot API 6.9 methods
- Telegram Passport and Decryption API
- Bot Payments
- Gaming Platform
Gradle:
implementation 'com.github.pengrad:java-telegram-bot-api:6.9.1'Maven:
<dependency>
<groupId>com.github.pengrad</groupId>
<artifactId>java-telegram-bot-api</artifactId>
<version>6.9.1</version>
</dependency>JAR with all dependencies on release page
// Create your bot passing the token received from @BotFatherTelegramBotbot = newTelegramBot("BOT_TOKEN");
// Register for updatesbot.setUpdatesListener(updates -> {
// ... process updates// return id of last processed update or confirm them allreturnUpdatesListener.CONFIRMED_UPDATES_ALL;
// Create Exception Handler
}, e -> {
if (e.response() != null) {
// got bad response from telegrame.response().errorCode();
e.response().description();
} else {
// probably network errore.printStackTrace();
}
});
// Send messageslongchatId = update.message().chat().id();
SendResponseresponse = bot.execute(newSendMessage(chatId, "Hello!"));- Creating your bot
- Making requests
- Getting updates
- Available types
- Available methods
- Updating messages
- Stickers
- Inline mode
- Payments
- Telegram Passport
- Games
TelegramBotbot = newTelegramBot("BOT_TOKEN");Network operations based on OkHttp library.
You can build bot with custom OkHttpClient, for specific timeouts or interceptors.
TelegramBotbot = newTelegramBot.Builder("BOT_TOKEN").okHttpClient(client).build();Synchronous
BaseResponseresponse = bot.execute(request);Asynchronous
bot.execute(request, newCallback() {
@OverridepublicvoidonResponse(BaseRequestrequest, BaseResponseresponse) {
}
@OverridepublicvoidonFailure(BaseRequestrequest, IOExceptione) {
}
});Request in response to update
Stringresponse = request.toWebhookResponse();You can use getUpdates request, parse incoming Webhook request, or set listener to receive updates.
Update object just copies Telegram's response.
classUpdate {
IntegerupdateId();
Messagemessage();
MessageeditedMessage();
InlineQueryinlineQuery();
ChosenInlineResultchosenInlineResult();
CallbackQuerycallbackQuery();
}Building request
GetUpdatesgetUpdates = newGetUpdates().limit(100).offset(0).timeout(0);The getUpdates method returns the earliest 100 unconfirmed updates. To confirm an update, use the offset parameter when calling getUpdates like this:
offset = updateId of last processed update + 1
All updates with updateId less than offset will be marked as confirmed on the server and will no longer be returned.
Executing
// syncGetUpdatesResponseupdatesResponse = bot.execute(getUpdates);
List<Update> updates = updatesResponse.updates();
...
Messagemessage = update.message()
// asyncbot.execute(getUpdates, newCallback<GetUpdates, GetUpdatesResponse>() {
@OverridepublicvoidonResponse(GetUpdatesrequest, GetUpdatesResponseresponse) {
List<Update> updates = response.updates();
}
@OverridepublicvoidonFailure(GetUpdatesrequest, IOExceptione) {
}
});Building request
SetWebhookrequest = newSetWebhook()
.url("url")
.certificate(newbyte[]{}) // byte[]
.certificate(newFile("path")); // or file Executing
// syncBaseResponseresponse = bot.execute(request);
booleanok = response.isOk();
// asyncbot.execute(request, newCallback<SetWebhook, BaseResponse>() {
@OverridepublicvoidonResponse(SetWebhookrequest, BaseResponseresponse) {
}
@OverridepublicvoidonFailure(SetWebhookrequest, IOExceptione) {
}
});Using Webhook you can parse request to Update
Updateupdate = BotUtils.parseUpdate(stringRequest); // from StringUpdateupdate = BotUtils.parseUpdate(reader); // or from java.io.ReaderMessagemessage = update.message();You can set a listener to receive incoming updates as if using Webhook.
This will trigger executing getUpdates requests in a loop.
bot.setUpdatesListener(newUpdatesListener() {
@Overridepublicintprocess(List<Update> updates) {
// process updatesreturnUpdatesListener.CONFIRMED_UPDATES_ALL;
}
// Create Exception Handler
}, newExceptionHandler() {
@overridepublicvoidonException(TelegramExceptione)
{
if (e.response() != null) {
// got bad response from telegrame.response().errorCode();
e.response().description();
} else {
// probably network errore .printStackTrace();
}
}
});Listener should return id of the last processed (confirmed) update.
To confirm all updates return UpdatesListener.CONFIRMED_UPDATES_ALL, this should be enough in most cases.
To not confirm any updates return UpdatesListener.CONFIRMED_UPDATES_NONE, these updates will be redelivered.
To set a specific update as last confirmed, just return the required updateId.
To stop receiving updates
bot.removeGetUpdatesListener();All types have the same name as original ones.
Type's fields are methods in lowerCamelCase.
Types used in responses (Update, Message, User, Document...) are in com.pengrad.telegrambot.model package.
Types used in requests (Keyboard, InlineQueryResult, ParseMode, InputMessageContent...) are in com.pengrad.telegrambot.model.request package.
When creating a request's type, required params should be passed in the constructor, optional params can be added in chains.
ForceReply, ReplyKeyboardRemove
KeyboardforceReply = newForceReply(isSelective); // or just new ForceReply();KeyboardreplyKeyboardRemove = newReplyKeyboardRemove(); // new ReplyKeyboardRemove(isSelective)ReplyKeyboardMarkup
KeyboardreplyKeyboardMarkup = newReplyKeyboardMarkup(
newString[]{"first row button1", "first row button2"},
newString[]{"second row button1", "second row button2"})
.oneTimeKeyboard(true) // optional
.resizeKeyboard(true) // optional
.selective(true); // optionalKeyboardButton
Keyboardkeyboard = newReplyKeyboardMarkup(
newKeyboardButton[]{
newKeyboardButton("text"),
newKeyboardButton("contact").requestContact(true),
newKeyboardButton("location").requestLocation(true)
}
); InlineKeyboardMarkup
InlineKeyboardMarkupinlineKeyboard = newInlineKeyboardMarkup(
newInlineKeyboardButton[]{
newInlineKeyboardButton("url").url("www.google.com"),
newInlineKeyboardButton("callback_data").callbackData("callback_data"),
newInlineKeyboardButton("Switch!").switchInlineQuery("switch_inline_query")
});ChatActionaction = ChatAction.typing;
ChatActionaction = ChatAction.upload_photo;
ChatActionaction = ChatAction.find_location;All request methods have the same names as original ones.
Required params should be passed in the constructor.
Optional params can be added in chains.
All send requests (SendMessage, SendPhoto, SendLocation...) return SendResponse object that contains Message.
SendMessagerequest = newSendMessage(chatId, "text")
.parseMode(ParseMode.HTML)
.disableWebPagePreview(true)
.disableNotification(true)
.replyToMessageId(1)
.replyMarkup(newForceReply());
// syncSendResponsesendResponse = bot.execute(request);
booleanok = sendResponse.isOk();
Messagemessage = sendResponse.message();
// asyncbot.execute(request, newCallback<SendMessage, SendResponse>() {
@OverridepublicvoidonResponse(SendMessagerequest, SendResponseresponse) {
}
@OverridepublicvoidonFailure(SendMessagerequest, IOExceptione) {
}
});ParseModeparseMode = ParseMode.Markdown;
ParseModeparseMode = ParseMode.HTML;GetFilerequest = newGetFile("fileId")
GetFileResponsegetFileResponse = bot.execute(request);
Filefile = getFileResponse.file(); // com.pengrad.telegrambot.model.Filefile.fileId();
file.filePath(); // relative pathfile.fileSize();To get downloading link as https://api.telegram.org/file/<BOT_TOKEN>/<FILE_PATH>
StringfullPath = bot.getFullFilePath(file); // com.pengrad.telegrambot.model.FileAll requests return BaseResponse if not mention here
classBaseResponse {
booleanisOk();
interrorCode();
Stringdescription();
}GetMe request returns GetMeResponse
classGetMeResponse {
Useruser();
}GetChatAdministrators
classGetChatAdministratorsResponse {
List<ChatMember> administrators()
}GetChatMembersCount
classGetChatMembersCountResponse {
intcount() }GetChatMember
classGetChatMemberResponse {
ChatMemberchatMember()
}GetChat
classGetChatResponse {
Chatchat()
}GetUserProfilePhotos
classGetUserProfilePhotosResponse {
UserProfilePhotosphotos()
}StopPoll
classPollResponse {
Pollpoll()
}Normal message
EditMessageTexteditMessageText = newEditMessageText(chatId, messageId, "new test")
.parseMode(ParseMode.HTML)
.disableWebPagePreview(true)
.replyMarkup(newReplyKeyboardRemove());
BaseResponseresponse = bot.execute(editMessageText);Inline message
EditMessageTexteditInlineMessageText = newEditMessageText(inlineMessageId, "new text");
BaseResponseresponse = bot.execute(editInlineMessageText);Delete message
DeleteMessagedeleteMessage = newDeleteMessage(chatId, messageId);
BaseResponseresponse = bot.execute(deleteMessage);Send sticker
// File or byte[] or string fileId of existing sticker or string URLSendStickersendSticker = newSendSticker(chatId, imageFile);
SendResponseresponse = bot.execute(sendSticker);Get sticker set
GetStickerSetgetStickerSet = newGetStickerSet(stickerSet);
GetStickerSetResponseresponse = bot.execute(getStickerSet);
StickerSetstickerSet = response.stickerSet();Upload sticker file
// File or byte[] or string URLUploadStickerFileuploadStickerFile = newUploadStickerFile(chatId, stickerFile);
GetFileResponseresponse = bot.execute(uploadStickerFile);Getting updates
GetUpdatesResponseupdatesResponse = bot.execute(newGetUpdates());
List<Update> updates = updatesResponse.updates();
...
InlineQueryinlineQuery = update.inlineQuery();
ChosenInlineResultchosenInlineResult = update.chosenInlineResult();
CallbackQuerycallbackQuery = update.callbackQuery();If using webhook, you can parse request to InlineQuery
Updateupdate = BotUtils.parseUpdate(stringRequest); // from StringUpdateupdate = BotUtils.parseUpdate(reader); // from java.io.ReaderInlineQueryinlineQuery = update.inlineQuery();InlineQueryResultr1 = newInlineQueryResultPhoto("id", "photoUrl", "thumbUrl");
InlineQueryResultr2 = newInlineQueryResultArticle("id", "title", "message text").thumbUrl("url");
InlineQueryResultr3 = newInlineQueryResultGif("id", "gifUrl", "thumbUrl");
InlineQueryResultr4 = newInlineQueryResultMpeg4Gif("id", "mpeg4Url", "thumbUrl");
InlineQueryResultr5 = newInlineQueryResultVideo(
"id", "videoUrl", InlineQueryResultVideo.MIME_VIDEO_MP4, "message", "thumbUrl", "video title")
.inputMessageContent(newInputLocationMessageContent(21.03f, 105.83f));BaseResponseresponse = bot.execute(newAnswerInlineQuery(inlineQuery.id(), r1, r2, r3, r4, r5));
// or fullbot.execute(
newAnswerInlineQuery(inlineQuery.id(), newInlineQueryResult[]{r1, r2, r3, r4, r5})
.cacheTime(cacheTime)
.isPersonal(isPersonal)
.nextOffset("offset")
.switchPmParameter("pmParam")
.switchPmText("pmText")
);Send invoice
SendInvoicesendInvoice = newSendInvoice(chatId, "title", "desc", "my_payload",
"providerToken", "my_start_param", "USD", newLabeledPrice("label", 200))
.needPhoneNumber(true)
.needShippingAddress(true)
.isFlexible(true)
.replyMarkup(newInlineKeyboardMarkup(newInlineKeyboardButton[]{
newInlineKeyboardButton("just pay").pay(),
newInlineKeyboardButton("google it").url("www.google.com")
}));
SendResponseresponse = bot.execute(sendInvoice);Answer shipping query
LabeledPrice[] prices = newLabeledPrice[]{
newLabeledPrice("delivery", 100),
newLabeledPrice("tips", 50)
};
AnswerShippingQueryanswerShippingQuery = newAnswerShippingQuery(shippingQueryId,
newShippingOption("1", "VNPT", prices),
newShippingOption("2", "FREE", newLabeledPrice("free delivery", 0))
);
BaseResponseresponse = bot.execute(answerShippingQuery);
// answer with errorAnswerShippingQueryanswerShippingError = newAnswerShippingQuery(id, "Can't deliver here!");
BaseResponseresponse = bot.execute(answerShippingError);Answer pre-checkout query
AnswerPreCheckoutQueryanswerCheckout = newAnswerPreCheckoutQuery(preCheckoutQueryId);
BaseResponseresponse = bot.execute(answerPreCheckoutQuery);
// answer with errorAnswerPreCheckoutQueryanswerCheckout = newAnswerPreCheckoutQuery(id, "Sorry, item not available");
BaseResponseresponse = bot.execute(answerPreCheckoutQuery);When the user confirms your request by pressing the ‘Authorize’ button, the Bot API sends an Update with the field passport_data to the bot that contains encrypted Telegram Passport data. Telegram Passport Manual
You can get encrypted Passport data from Update (via UpdatesListener or Webhook)
PassportDatapassportData = update.message().passportData();PassportData contains anarray of EncryptedPassportElement and EncryptedCredentials.
You need to decrypt Credentials using private key (public key you uploaded to @BotFather)
StringprivateKey = "...";
EncryptedCredentialsencryptedCredentials = passportData.credentials();
Credentialscredentials = encryptedCredentials.decrypt(privateKey);These Credentials can be used to decrypt encrypted data in EncryptedPassportElement.
EncryptedPassportElement[] encryptedPassportElements = passportData.data();
for (EncryptedPassportElementelement : encryptedPassportElements) {
DecryptedDatadecryptedData = element.decryptData(credentials);
// DecryptedData can be cast to specific type by checking instanceOf if (decryptedDatainstanceofPersonalDetails) {
PersonalDetailspersonalDetails = (PersonalDetails) decryptedData;
}
// Or by checking type of passport elementif (element.type() == EncryptedPassportElement.Type.address) {
ResidentialAddressaddress = (ResidentialAddress) decryptedData;
}
}EncryptedPassportElement also contains an array of PassportFile (file uploaded to Telegram Passport).
You need to download them 1 by 1 and decrypt content.
This library supports downloading and decryption, returns decrypted byte[]
EncryptedPassportElementelement = ...
// Combine all files List<PassportFile> files = newArrayList<PassportFile>();
files.add(element.frontSide());
files.add(element.reverseSide());
files.add(element.selfie());
if (element.files() != null) {
files.addAll(Arrays.asList(element.files()));
}
if (element.translation() != null) {
files.addAll(Arrays.asList(element.translation()));
}
// Decryptfor (PassportFilefile : files) {
if (file == null) continue;
byte[] data = element.decryptFile(file, credentials, bot); // GetFile request and decrypt content// save to file if needednewFileOutputStream("files/" + element.type()).write(data);
}SetPassportDataErrorssetPassportDataErrors = newSetPassportDataErrors(chatId,
newPassportElementErrorDataField("personal_details", "first_name", "dataHash",
"Please enter a valid First name"),
newPassportElementErrorSelfie("driver_license", "fileHash",
"Can't see your face on photo")
);
bot.execute(setPassportDataErrors);Send game
SendResponseresponse = bot.execute(newSendGame(chatId, "my_super_game"));Set game score
BaseResponseresponse = bot.execute(newSetGameScore(userId, score, chatId, messageId));Get game high scores
GetGameHighScoresResponseresponse = bot.execute(newGetGameHighScores(userId, chatId, messageId));
GameHighScore[] scores = response.result();