Всем привет! Я прошёл сложный путь от создания бота до получения первых платежей, поэтому, как порядочный разработчик, хочу поделить информацией, за которую, я уверен, кто-то кому-то платит большие деньги, а в это время ваши полезные труды пылятся на задворках интернета.

Краткая инструкция

  1. Создаём своего бота BotFather в приложении Telegram (это может сделать любой пользователь, на этом этапе не надо быть программистом).

  2. Прописываем полезную, нужную людям логику бота на вашем языке программирования (здесь надо искать готовые решения или кодить как я).

  3. Вы считаете, что бот готов. Теперь максимально тестируем своего бота сами, потом просим протестировать друзей, потом напоминаем им об этом, правим логику, снова тестируем сами, потом снова друзья. Вот теперь бот готов и протестирован, его можно вывести в люди и тестирование продолжится на них. Вы даже не представляете, что творят люди в боте! Вопросы и варианты выбора надо сделать максимально простыми. Представьте, что вы показываете бота детям в садике. Поможет логирование действий пользователей!

  4. За пару-тройку месяцев использования бота реальными подписчиками вы поправите его ~96 раз. Только спустя пол года, действия пользователей перестают пугать, т.к. теперь вы знаете, что хочет общая масса. Теперь, в идеале, спустя столько времени, можно продавать подписку на дополнительный, улучшенный функционал бота.

  5. Оформляем самозанятость. Это очень легко сделать через Госуслуги. Ставим себе приложение Мой налог. Всё очень просто и понятно. ИП и ООО оформлять тоже не сложно, но тут сами смотрите как лучше именно для вас.

  6. Подключаем платёжную систему. Заходим в BotFather, выбираем через кого будем получать платежи. Вот первая шестёрка финалистов. Я выбрал того, с кем мне было понятнее всего продолжать после поиска в стиле "платежи Телеграм для самозанятого". Не рекламирую, за это сразу летят дизлайки, типа подкупили и т.д. Далее по тексту поймёте кого выбрал.

  7. На данном этапе бот готов, протестирован, Вы самозанятый, подключена платёжная система. Пора продавать платную подписку на плюшки! А как? Я не менеджер по продажам. Решил сделать пресловутое Приведи друга.
    И вот к чему это привело..

Инструкция по приёму платежей


Я создал личный кабинет для приёма платежей на сайте. Заполнил все данные для договора и в течении 5 дней заключил его (подписывал через смс). Также выбрал авто отправку чеков в ФНС, за это платим 1,2 % комиссии с каждого перевода. Это освобождает от рутины делать чеки своими руками в приложении Мой налог и отправляет чек покупателю. За каждый платёж тоже комиссия (у каждого своя, писать нельзя, скажу, что до 4%).

Важный момент, если Вы подключаете авто отправку чеков в налоговую, то надо предусмотреть в коде, чтобы у покупателя запрашивался телефон или почта. Остальные нюансы и обработчик опишу в коде.

Java код логики приёма и обработки платежей Java (экономлю Вам нервы и время)
// Должно присутствовать в коде:

// 1. обработчик успешного платежа
} else if (update.hasMessage() && update.getMessage().hasSuccessfulPayment()) {
    handler.successfulPaymentHandler(update.getMessage().getSuccessfulPayment());
                    
// 2. проверка
} else if (update.hasPreCheckoutQuery()) {
  handler.paymentPreCheckout(update.getPreCheckoutQuery());
  

/* ВОТ ТАКОЕ РАБОЧЕЕ, ГОТОВОЕ НЕПРОСТО НАЙТИ, ДЕЛЮСЬ */
  
// Проверка перед платежом. 
// AnswerPreCheckoutQuery прям должен быть в коде!
    public void paymentPreCheckout(PreCheckoutQuery query) {
        AnswerPreCheckoutQuery answer = new AnswerPreCheckoutQuery();

        if (query != null && query.getInvoicePayload().startsWith("avandy-news")) {
            answer.setOk(true);
            answer.setPreCheckoutQueryId(query.getId());
        } else {
            answer.setOk(false);
            answer.setErrorMessage("Попробуйте снова!");
        }

        try {
            messageService.execute(answer);
        } catch (TelegramApiException e) {
            log.error("paymentPreCheckout error = {}", e.getMessage());
        }
    }
  
// Обработчик успешного платежа
// ВАЖНО! в sum учитываются копейки, т.е. 25000 = 250,00 рублей
    public void handlePayment(SuccessfulPayment successfulPayment) {
        String payload = successfulPayment.getInvoicePayload();
        long chatId = Long.parseLong(payload.substring(payload.indexOf("#") + 1));
        String currency = successfulPayment.getCurrency();
        String providerPaymentChargeId = successfulPayment.getProviderPaymentChargeId();

        if (successfulPayment.getInvoicePayload().startsWith("avandy-news")) {
            Integer totalAmount = successfulPayment.getTotalAmount(); // здесь 25000
            // в базу запишем реальные 250 рублей, а не 25000 копеек
            double sum = (double) totalAmount / 100; // Учитываются копейки, т.е. 25000 = 250р.

            // Сохранить чек в БД
            // сохраняйте String providerPaymentChargeId, так потом проще возврат оформить
            paymentsService.save(new Payments(chatId, sum, currency, providerPaymentChargeId));
            sendMessage(chatId, "Оплата прошла успешно! " + premiumActivatedText);
        } else {
            sendMessage(chatId, "Ошибка оплаты, попробуйте снова!");
        }
    }

  // Выставление счёта через Юкассу
    public void getInvoice(long chatId, int type) {
        String description = "Подписка на получение премиальных возможности бота";
        List<LabeledPrice> labeledPrices = new ArrayList<>();
        String label = pay1month;       
        labeledPrices.add(new LabeledPrice(label, type * 100)); // умножаем на 100, чтобы были копейки 00

        try {
            SendInvoice invoice = getSendInvoice(chatId, description, labeledPrices);
            
            // Отправка счёта
            messageService.execute(invoice);
            
        } catch (TelegramApiException e) {
            log.error("{}: {} {}", "Ошибка при отправке счёта на оплату", chatId, e.getMessage());
        }

    }

  /* И ВОТ САМЫЙ СОК, СКОЛЬКО Ж Я НАМУЧИЛСЯ С МЕЛОЧАМИ */ 
    // Создание чека/инвоиса на одну услугу
    private SendInvoice getSendInvoice(long chatId, String description, List<LabeledPrice> labeledPrices) {
        SendInvoice invoice = new SendInvoice();
        String label = labeledPrices.get(0).getLabel();
        int amount = labeledPrices.get(0).getAmount() / 100;

        // Если телефон не сохранён в БД, то запроси его при платеже
        // иначе некуда отправлять чек ФНС. Это обязательное требование.
        // Можно запрашивать email. Т.е. или email или телефон должны быть,
        // если выбрана авто отправка чеков в ФНС и покупателю (фискализация)
        // ВАЖНО! А вот здесь уже 25000 != 250р. Дурдом :) 
        // поэтому предыдущие 25000 делим на 100
       String phoneNumber = userService.getPhoneNumber(chatId);        
       if (phoneNumber == null || phoneNumber.isEmpty()) {
            invoice.setNeedPhoneNumber(true);
            invoice.setSendPhoneNumberToProvider(true);
        }

        invoice.setChatId(String.valueOf(chatId));
        invoice.setProviderToken(PROVIDER_TOKEN); //Токен получаете после подписания договора
        invoice.setTitle("Avandy News");
        invoice.setDescription(description);
        invoice.setPayload("avandy-news#" + chatId);
        invoice.setStartParameter("payment-invoice");
        invoice.setCurrency("RUB");
        invoice.setPrices(labeledPrices);

        // Без этого тоже не пройдёт платёж, т.к. подключена фискализация
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("receipt",
                new JSONObject()
                        .put("items", new JSONArray().put(
                                new JSONObject()
                                        .put("description", label)
                                        .put("amount", new JSONObject()
                                                .put("value", amount + ".00") // ВОТ ДОГАДАЙСЯ САМ, ЧТО НАДО ТАК!!
                                                .put("currency", "RUB"))
                                        .put("vat_code", 1) // Это НДС так называется, 1 значит БЕЗ НДС
                                        .put("quantity", 1))));
        invoice.setProviderData(jsonObject.toString());

        return invoice;
    }
  

Алгоритм действий пользователя:

  1. Пользователь нажимает в боте кнопку, которую сделали Вы, с желаемым периодом подписки;

  2. Телеграм присылает ему сообщение с кнопкой Оплатить (эту кнопку делает Телеграм);

  3. Нажимает Оплатить и переходит на страницу платежа (её мы не программируем), вводит карту, подтверждает платёж;

  4. Получает из бота сообщение, что ему подключена премиум подписка;

  5. Получает официальный чек платежа на телефон, а для нас в приложении Мой налог отобразится чек с суммой и налогом 6% (ФНС даёт скидку для начинающих самозанятых);

  6. В личном кабинете также будет отображена сумма покупки, плюс уведомления о платеже на вашу почту и телефон.

    Пример:

Создание реферальной системы продаж "Приведи друга"

"Так это же сетевой маркетинг и это плохо!". Как оказывается это прекрасно для таких как я, которые сидят, кодят себе в удовольствие в своём уголке и читают эту статью до этих слов. Я не косметику предлагаю, а абстрактного бота, который что-то делает.

Суть

Я говорю своим друзьям: "Предложите моего бота своим знакомым и когда они купят подписку на год, то 10% получите лично вы за каждую их оплату".
Т.е. позовёт мой друг троих человек, они купят подписку по 2000 р. на год и он получит свои 2000 * 3 человека * 10% = 600р. улыбнётся и забудет, НО.. сидит он на рыбалке себе спокойно, пьёт чай, ага, и тут ему прилетает тысяча рублей, с чего бы.. а с того, что эти трое пригласили в сумме ещё 20 человек, 10 из них купили подписку.
Друзья, которых позвал он это первый уровень, друзья друзей это 2 уровень и так до бесконечности.

Я соорудил такую конструкцию бонусов (кэшбэком их назвал):

  • за 1 уровень мой друг получает 10% от продаж [я пригласил троих, итого 3 покупателя]

  • за 2 и 3 уровни он получает 5% [друзья 1 уровня пригласили двадцать пользователей, десять из них о оформили подписку, итого 13 покупателей]

  • 4 и ниже уровни это 1% бонуса (1% сделано чтобы не разориться, выплачивая всем цепочкам бонусы) [итого миллиард покупателей]

Главное чтобы ваши друзья были активны в плане предложения бота другим знакомым, ну и чтобы ваш бот был востребован и как-то облегчал жизнь людям, иначе кто купит подписку? Лучшая картинка, описывающая эту пресловутую схему.

Как десерт это мои страшные, но подробные расчёты по схеме премий [10-5-5-1-1-1-....1], которые показывают чистую прибыль (минус налог, комиссии, выплаты бонусов пользователям) бота при 13 покупках годовой подписки стоимостью в 2000 рублей в 18 298 р. / 26 000 [70,3%].

И это я пригласил только одного Арсика и забыл про это! Только одного человека! Потому бонус = 1% c 4 уровня, чтобы не разориться, выплачивая каждую пятницу в 20:00 ваши бонусы.

Процесс приглашения

В боте в Меню - Инфо я добавил кнопку Пригласить

В эти три ёлочки зашит Ваш уникальный chat_id, который даёт Telegram, но преобразованный, б - безопасность. Ссылка под капотом выглядит так:

"<a href=\"https://t.me/AvandyNewsBot?start=" + chatId + "\"><b>»»»</b></a>"

В итоге когда тот кому вы перешлёте это сообщение перейдёт в бота - в базу данных Postgres запишется ваш уникальный chat_id в поле "кто пригласил". Этого достаточно для жёстких иерархических рекурсивных запросов, чтобы получить всё что нужно.

Пример рекурсивного запроса в Spring Boot
// Цепь приглашённых пользователей и расчёт бонуса, исходя из уровня [1 ур.-10%, 2-3 ур.-5%, >= 4 ур.-1%]
@NamedNativeQuery(
        name = "FindReferalls",
        query = "with recursive referral_chain as (select *, 0 as level from users where chat_id = ?1" +
                "                                  union all" +
                "                                  select u.*, r.level + 1 from users u" +
                "                                      join referral_chain r on u.referall_id = r.chat_id)" +
                " select level," +
                "        r.chat_id," +
                "        coalesce(r.user_name, r.first_name) as user_name," +
                "        sum," +
                "        case" +
                "            when (p.sum > 0 and r.level = 1) then p.sum * 0.10" +
                "            when (p.sum > 0 and r.level in (2, 3)) then p.sum * 0.05" +
                "            when (p.sum > 0 and r.level >= 4) then p.sum * 0.01" +
                "            else 0 end as award, " +
                "        p.currency," +
                "        r.referall_theme" +
                "  from referral_chain r " +
                "    left join payments p on p.chat_id = r.chat_id" +
                " where r.chat_id != ?1" +
                " order by r.level, r.user_name",
        resultSetMapping = "ReferallResultMapping")

Итоги

  1. Сделан Telegram bot

  2. Вы самозанятый

  3. Ваш бот продаётся сам по себе (если он не .. плохой), а вы только смотрите в табличку с поступившими платежами и автоматически рассчитанными бонусами, чтобы порадовать подписчиков бота в пятницу вечером.

Просто попробуйте..

Комментарии (27)


  1. SuharkovMP
    18.07.2024 12:55
    +1

    Я говорю своим друзьям: "Предложите моего бота своим знакомым и когда они купят подписку на год

    Не если купят, а когда купят...

    Была ли полезна данная статья?

    Да

    Понравилась, но не полностью

    Вариант "Нет" отсутствует...

    А вы с оптимизмом смотрите в будущее.


    1. mrprogre Автор
      18.07.2024 12:55

      Оптимизм, к некотором роде, двигатель прогресса. Если всё сразу отрицать, то можно ничего и не сделать. Я понимаю о чём Вы, не факт что много заработаешь. Но я же что-то сделал, чтобы такой шанс вообще появился, понимаете и поделился схемой! Точнее рассказал очевидное, но тем не менее. Нет теперь есть.


  1. aleksandy
    18.07.2024 12:55

    Итить

    Integer totalAmount = successfulPayment.getTotalAmount(); // здесь 25000
    // в базу запишем реальные 250 рублей, а не 25000 копеек
    double sum = (double) totalAmount / 100; // Учитываются к

    1. Если деньги считаются в копейках минимальном номинале, то типом должен быть long.

    2. Деньги и вещественные типы данных никогда не должны пересекаться. Вообще.


    1. mrprogre Автор
      18.07.2024 12:55

      Про long принято, про вещественные не понял.. double и деньги не должны пересекаться?


      1. dtkdtk
        18.07.2024 12:55
        +1

        Не должны пересекаться, скорее всего, потому, что вычисления вещественных неточные. Если вы сложите 0.1 и 0.2 - получите отнюдь не 0.3, а 0.300000014. Это может казаться нестрашным, но сам факт погрешности при вычисления с деньгами...

        На это можно "забить", но я бы, например, так делать не стал.


        1. mrprogre Автор
          18.07.2024 12:55

          да да, про эти приколы дабла я знаю. Спасибо, отличный совет! Теперь буду использовать long! Уже не зря дизлайков нахватал :)


  1. nki
    18.07.2024 12:55
    +1

    Сдаю ботов в аренду. Платёж настроил для банка, которого нет в списка телеги. По партнёрской программе выплачиваю два первых платежа от приведённого клиента.


    1. mrprogre Автор
      18.07.2024 12:55

      Во, спасибо за комментарий.. столько труда выложил, мыслей, а дизлайкают безбожно :)


      1. nki
        18.07.2024 12:55
        +1

        Видимо тут не ваша аудитория.


  1. Foamorea
    18.07.2024 12:55

    Мавроди, перелогинься


    1. mrprogre Автор
      18.07.2024 12:55

      не, тут же всё по честному! просто было любопытно как лучше всего продавать.. вот и пришёл к такой схеме. А что лучше этого?


  1. mrprogre Автор
    18.07.2024 12:55

    За что дизлайки то ставите? почему -4 за рекламу реклама? что я рекламирую? уже все ссылки на своего бота убрал!


  1. Bone
    18.07.2024 12:55
    +1

    Предполагаю, что реферальные выплаты тоже должны быть как-то юридически оформлены. По крайней, если их станет много.


    1. mrprogre Автор
      18.07.2024 12:55

      Спасибо! Хороший вопрос, уточню в ФНС, добавлю комментарий. Погуглил, нет точного объяснения конкретно для самозанятого.


  1. ELENA_CHE
    18.07.2024 12:55
    +1

    классный бот!


    1. mrprogre Автор
      18.07.2024 12:55

      Да, в подписчиках у него аккаунт МЧС Республики Беларусь :))


      1. mrprogre Автор
        18.07.2024 12:55

        а точнее РЦУРЧС Республики Беларусь


  1. Rafriell
    18.07.2024 12:55
    +3

    Полезно для саморазвития. Автор - пришли ссылку на бота


    1. mrprogre Автор
      18.07.2024 12:55
      +1

      Ссылка на бота: Avandy News Bot


      1. Rafriell
        18.07.2024 12:55
        +1

        Благодарю!


      1. skrinby
        18.07.2024 12:55

        Прикольно! А код бота можно попросить?


        1. mrprogre Автор
          18.07.2024 12:55

          Основные алгоритмы бота были построены на моей десктопной новостной программе, которая попала в Реестр российского ПО, код общедоступен
          https://github.com/mrprogre/avandy-news


  1. EverySeeingEye
    18.07.2024 12:55
    +2

    Побольше бы таких статей!


    1. mrprogre Автор
      18.07.2024 12:55

      после такой волны негатива Ваш комментарий как глоток свежего воздуха))


  1. Diesel_Van_Faust
    18.07.2024 12:55
    +1

    Автор красавец! Немногие поймут.


  1. crazy_kayaker
    18.07.2024 12:55

    Чуть потыкал бота и заметил, что кнопки не перестают мигать после обработки. Может быть это у меня проблемы, но возможно ты забыл где-то отправлять answer на колбэки


    1. mrprogre Автор
      18.07.2024 12:55

      А на что жали? По идее все кнопки задействованы, после каждой какой-то ответ.