Request and handle phone number and location with Telegram Bot API
We are still working at sample bot for taking orders in online store. Last time we finished with a project deployed on heroku, connected to mongodb and able to store messages to the database
If we want to take and handle orders from our customers we need to know their contact phone to confirm the order and optionally their location to deliver the order. Telegram provides both these things with custom keyboards
The main idea here is to use a keyboard with buttons “Share my phone number” and “Share my location”. When user presses this button our server-side handler receives a message containing location or contact info.
sendMessage
supports different types of reply markups. We are interesting in InlineKeyboardMarkup and ReplyKeyboardMarkup — both of them supports custom buttons. Inline keyboards appears next to the messages they belong to, and reply keyboards appears at the bottom of the screen. Both keyboards have array of arrays of Buttons (one keyboard may have several rows of buttons). For our task inline keyboards are useless — only reply keyboars support request for contact or location
Lets create a handler for /place_order
message. We are still using https://github.com/yagop/node-telegram-bot-api based on EventEmitter that will come in handy in our work. Let’s pretend that our customer has choosen goods or services and the last step is to tell us his contact and delivery details
bot.onText(/^\/place_order/, function (msg, match) {
var option = {
"parse_mode": "Markdown",
"reply_markup": {
"one_time_keyboard": true,
"keyboard": [[{
text: "My phone number",
request_contact: true
}], ["Cancel"]]
}
};
bot.sendMessage(msg.chat.id, "How can we contact you?", option).then(() => {
// handle user phone
})
});
How can we handle phone number got from user? Let’s take a look to the Telegram workflow.
When user sends something to our bot the message comes to the Telegram server and is being stored there for 24h until the bot receives it. The bot uses webhooks or long polling to get updates from the server. Each Update containes at most one of the optional parameters — we are interested in Message.
Message itself has a lot of optional parameters, so when our Bot API client receives updates they are processed as text, photo, game, sticker, contact, location, etc. node-telegram-bot-api emits an event for each type of content so we just need to add a listener
bot.on("contact",(msg)=>{
bot.sendMessage(msg.chat.id,
util.format('Thank you %s with phone %s!', msg.contact.first_name, msg.contact.phone_number),
option)
})
It will fire every time when user sends us his contact information. To prevent handling the message from different places let’s change .on()
with .once()
and now our handler will process just first message. More complex example is using addListener
and removeListener
to prevent it being alive after user presses “Cancel” button
For your Bot API library you should find getUpdates()
implementation and see how different types of content inside a message are emitted to client side
Next important thing is to request delivery details. Let’s assume that our customer use the bot at home or at office — so we can offer him current location as a default for delivery. Let’s request current location of our customer after receiving his contact info:
bot.onText(/^\/place_order/, function (msg, match) {
var option = {
"parse_mode": "Markdown",
"reply_markup": {
"one_time_keyboard": true,
"keyboard": [[{
text: "My phone number",
request_contact: true
}], ["Cancel"]]
}
};
bot.sendMessage(msg.chat.id, "How can we contact you?", option).then(() => {
bot.once("contact",(msg)=>{
var option = {
"parse_mode": "Markdown",
"reply_markup": {
"one_time_keyboard": true,
"keyboard": [[{
text: "My location",
request_location: true
}], ["Cancel"]]
}
};
bot.sendMessage(msg.chat.id,
util.format('Thank you %s with phone %s! And where are you?', msg.contact.first_name, msg.contact.phone_number),
option)
.then(() => {
bot.once("location",(msg)=>{
bot.sendMessage(msg.chat.id, "We will deliver your order to " + [msg.location.longitude,msg.location.latitude].join(";"));
})
})
})
})
});
It works fine now. There are a lot of clients for Bot API but the common workflow is to send Reply Keyboard with request_contact=true
or with request_location=true
and properly handle getUpdates()
result
Next time we will take a look to states and workflow of our bot and will implement small sample for real online store