У вас в doPost первой строкой идёт парсинг входящего события, а второй строкой вы уже обрабатываете сообщение (message).
Но входящее событие может и не иметь этого поля в себе!
Потому что если к вам приходит callbac_query, то поля message не будет, будет только callback_query - смотрите документацию телеграм по объекту Update.
Вам нужно второй строкой понять, что вам пришло: message или callback_query.
Вы это можете сделать через hasOwnProperty.
Будет что-то типа:
if (contents.hasOwnProperty('callback_query'))
{
Тут код на случай ответа из кнопки
}
if (contents.hasOwnProperty('message'))
{
Тут код на случай получения обычного сообщения
}
P.S. В ТГ есть группа по разработке ботов с гуглом, недавно там публиковали эфиры по разработке бота учёта финансов.
Админ:
https://t.me/andreintys
P.P.S. Тоже сделал своего бота, но без прикрепления фото чеков.
Внесение суммы, выбор категории, еженедельные и ежемесечные отчёты по тратам. Могу выслать вам код и таблицу.
Мой тг @dolinin_pa