Request and handle phone number and location with Telegram Bot API

Pavel Gerasimov
Dev Tutorials
Published in
4 min readMar 12, 2017

--

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
})

});
Custom keyboard in reply

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(";"));
})
})
})
})

});
Sorry for hidden personal data but yes — it works!

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

--

--

Senior Engineering Manager at Wrike. Growth Engineering, Org and Leadership Transformation. Former CEO and co-founder of Le Talo Robotics