title: Telegram inline keyboard and input data by user
body: <p>I'm developing a Telegram bot on Google Apps Script for personal purposes: entering expenses / incomes for different types.</p>
  <p>I have several types of expenses that I record in Google Spreadsheets.</p>
  <h2>My idea</h2>
  <p><a href="https://i.stack.imgur.com/Zu49g.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/Zu49g.png" alt="enter image description here" /></a></p>
  <p>I got a problem implementing the expense input.
  I liked how this is implemented in the official bot @BotFather</p>
  <h2>@BotFather</h2>
  <p><a href="https://i.stack.imgur.com/6HQ5B.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/6HQ5B.png" alt="enter image description here" /></a></p>
  <p>How can you implement this correctly? Preferably with GAS.</p>
  <p>Thanks.</p>
  <p><strong>Bot.gs</strong></p>
  <pre><code>var token = &quot;&lt;BOT_TOKEN&gt;&quot;;
  var telegramUrl = &quot;https://api.telegram.org/bot&quot; + token;
  var webAppUrl = &quot;https://script.google.com/macros/s/&lt;ID&gt;/exec&quot;;
  
  function getMe() {
    var url = telegramUrl + &quot;/getMe&quot;;
    var response = UrlFetchApp.fetch(url);
    Logger.log(response.getContentText());
  }
  
  function setWebhook() {
    var url = telegramUrl + &quot;/setWebhook?url=&quot; + webAppUrl;
    var response = UrlFetchApp.fetch(url);
    Logger.log(response.getContentText());
  }
  
  function deletWebhook() {
    var url = telegramUrl + &quot;/setWebhook&quot;;
    var response = UrlFetchApp.fetch(url);
  }
  
  function doGet(e) {
    return HtmlService.createHtmlOutput(&quot;Webhook is working.&quot;);
  }
  
  // Send message
  function sendMessage(chat_id, text) {
    var data = {
      method: &quot;post&quot;,
      payload: {
        method: &quot;sendMessage&quot;,
        chat_id: String(chat_id),
        text: text,
        parse_mode: &quot;HTML&quot;,
        disable_web_page_preview: true
      }
    };
    UrlFetchApp.fetch(&quot;https://api.telegram.org/bot&quot; + token + &quot;/&quot;, data);
  }
  
  // Delete message
  function deleteMessage(chat_id, message_id) {
    var data = {
      method: &quot;post&quot;,
      payload: {
        method: &quot;deleteMessage&quot;,
        chat_id: String(chat_id),
        message_id: parseInt(message_id, 10)
      }
    };
    UrlFetchApp.fetch(&quot;https://api.telegram.org/bot&quot; + token + &quot;/&quot;, data);
  }
  
  // Edit message
  function editMessage(chat_id, message_id, text) {
    var data = {
      method: &quot;post&quot;,
      payload: {
        method: &quot;editMessageText&quot;,
        chat_id: String(chat_id),
        message_id: parseInt(message_id, 10),
        text: text,
        parse_mode: &quot;HTML&quot;,
        disable_web_page_preview: true
      }
    };
    UrlFetchApp.fetch(&quot;https://api.telegram.org/bot&quot; + token + &quot;/&quot;, data);
  }
  
  // Send message and keyboard
  function sendMessageKeyboard(chat_id, text, keyboard) {
    var data = {
      method: &quot;post&quot;,
      payload: {
        method: &quot;sendMessage&quot;,
        chat_id: String(chat_id),
        text: text,
        parse_mode: &quot;HTML&quot;,
        reply_markup: JSON.stringify(keyboard)
      }
    };
    UrlFetchApp.fetch(&quot;https://api.telegram.org/bot&quot; + token + &quot;/&quot;, data);
  }
  
  // Hide keyboard
  function hideKeyBoard(chat_id, message_id) {
    var data = {
      method: &quot;post&quot;,
      payload: {
        method: &quot;editMessageReplyMarkup&quot;,
        chat_id: String(chat_id),
        message_id: parseInt(message_id, 10)
      }
    };
    UrlFetchApp.fetch(&quot;https://api.telegram.org/bot&quot; + token + &quot;/&quot;, data);
  }
  
  // Replace keyboard
  function replaceKeyBoard(chat_id, message_id,keyboard) {
    var data = {
      method: &quot;post&quot;,
      payload: {
        method: &quot;editMessageReplyMarkup&quot;,
        chat_id: String(chat_id),
        message_id: parseInt(message_id, 10),
        reply_markup: JSON.stringify(keyboard)
      }
    };
    UrlFetchApp.fetch(&quot;https://api.telegram.org/bot&quot; + token + &quot;/&quot;, data);
  }
  </code></pre>
  <p><strong>doPost.gs</strong></p>
  <pre><code>function doPost(e) {
    var contents = JSON.parse(e.postData.contents);
  
    if (contents.callback_query) {
  
      var message_id = contents.callback_query.message.message_id;
      var data = contents.callback_query.data;
      var multiData = data.split(&quot; &quot;);
      var chat_id = contents.callback_query.from.id;
  
      if (data == 'Back') {
        replaceKeyBoard(chat_id, message_id, KEYBOARD_COMPANIES);
  
      } else if (data == 'Cancel') {
        deleteMessage(chat_id, message_id);
        sendMessageKeyboard(chat_id, &quot;Choose the action:&quot;, KEYBOARD_COMPANIES);
  
      } else if (data == 'Common') {
        replaceKeyBoard(chat_id, message_id, KEYBOARD_COMMON);
  
      } else if ((multiData[1]) &amp;&amp; (multiData[0] == 'Common')) {
        deleteMessage(chat_id, message_id);
        sendMessageKeyboard(chat_id, &quot;&lt;b&gt;Expense: &quot; + multiData[0] + &quot; -&gt; &quot; + multiData[1] + &quot;.&lt;/b&gt; Input the value:&quot;, KEYBOARD_INPUT);
      }
  
  } else if (contents.message) {
  
      var chat_id = contents.message.from.id;
      var text = contents.message.text;
  
      if (text == &quot;/start&quot;) {
        deleteMessage(chat_id, contents.message.message_id)
        sendMessageKeyboard(chat_id, &quot;Choose the action:&quot;, KEYBOARD_COMPANIES);
  
      } else if (!isNaN(parseFloat(text)) &amp;&amp; isFinite(text)) {
        for (var i = 0; i &lt; logins.length; i++) {
          if (chat_id == logins[i]) {
            sBot.getRange(&quot;C&quot; + (i + 2)).setValue(text);
            replaceKeyBoard(chat_id, sBot.getRange(&quot;D&quot; + (i + 2)).getValue());
          }
        }
      }
    }
  }
  </code></pre>
  <p><strong>Keyboard.gs</strong></p>
  <pre><code>// 1 Companies
  var KEYBOARD_COMPANIES = {
    &quot;inline_keyboard&quot;: [
      [{ &quot;text&quot;: &quot;Common&quot;, 'callback_data': 'Common' }],
      [{ &quot;text&quot;: &quot;Smoky Unicorn&quot;, 'callback_data': 'Smoky Unicorn' }],
      [{ &quot;text&quot;: &quot;Pussy Stuff&quot;, 'callback_data': 'Pussy Stuff' }],
      [{ &quot;text&quot;: &quot;Trash Seller&quot;, 'callback_data': 'Trash Seller' }]
    ]
  };
  
  // 1.1 Common
  var KEYBOARD_COMMON = {
    &quot;inline_keyboard&quot;: [
      [{ &quot;text&quot;: &quot;Back&quot;, 'callback_data': 'Back' }],
      [{ &quot;text&quot;: &quot;Taxi&quot;, 'callback_data': 'Common Taxi' }],
      [{ &quot;text&quot;: &quot;Food&quot;, 'callback_data': 'Common Food' }],
      [{ &quot;text&quot;: &quot;Party&quot;, 'callback_data': 'Common Party' }]
    ]
  };
  
  // Reply
  var FORCE_REPLY = {
    &quot;force_reply&quot;: true
  };
  
  // Input the value
  var KEYBOARD_INPUT = {
    &quot;inline_keyboard&quot;: [
      [{ &quot;text&quot;: &quot;Cancel&quot;, 'callback_data': 'Cancel' }]
    ]
  };
  </code></pre>
  <p><strong>Functions.gs</strong></p>
  <pre><code>// Global
  var todayMonth = getMonthToday();
  var NEWL = String.fromCharCode(10); // newline
  
  var accId = &quot;&lt;Spreadsheet_ID&quot;; // Accounting Spreadsheet
  var acc = SpreadsheetApp.openById(accId);
  var sAcc = acc.getSheetByName(todayMonth);
  var sBot = acc.getSheetByName(&quot;Bot&quot;);
  
  // @usernames who have access to the bot
  var andreyChatId = sBot.getRange(&quot;B2&quot;).getValue();
  var donyChatId = sBot.getRange(&quot;B3&quot;).getValue();
  
  // chat_id who have access to the bot
  var logins = [&quot;99587408&quot;, &quot;155390785&quot;];
  
  // Get current month
  function getMonthToday() {
    var months = [&quot;January&quot;, &quot;February&quot;, &quot;March&quot;, &quot;April&quot;, &quot;May&quot;, &quot;June&quot;, &quot;July&quot;, &quot;August&quot;, &quot;September&quot;, &quot;October&quot;, &quot;November&quot;, &quot;December&quot;];
    var todayDate = new Date();
    var todayMonth = months[todayDate.getMonth()];
  
    return todayMonth;
  }
  </code></pre>