Введение

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

Описание

  • Настройка уведомлений

  • Создание ссылки для оплаты

  • Проверка оплаты

Как я уже сказал все, что вам нужно это ip адрес вашего хостинга или доменное имя и порт. Я буду пользоваться утилитой Ngrok, для тех кто не знает, Ngrok - это такой инструмент который позволяет создать защищенное туннельное соединение между локальным компьютером и интернетом. Он позволяет временно выставить локальный сервер или другие локальные сервисы наружу, делая их доступными через общедоступный url, короче говоря ваш localhost будет доступен из внешней сети «интернет». Мне это необходимо для примера, так как весь пример будет выполняться на локальной машине

Видео туториал есть на GitHub проекта

Настройка уведомлений

Заходим в кошелек ЮMoney. Если кошелька нет, создаем его, после этого нам нужно подключить HTTP/HTTPS уведомления к нашему кошельку Yoomoney.

  1. Указываем url на который хотим принимать уведомления и обязательно сохраняем секретное слово (оно нам еще понадобиться).

  2. Ставим галочку «Отправлять HTTP‑уведомления».

  3. Нажимаем кнопку «Готово».

Отлично, наш кошелек готов к отправке уведомлений!

Для дальнейших действий нам понадобиться библиотека yoomoney-api, ее можно установить с помощью следующей CLI команды:

dotnet add package yoomoney-api --version 1.4.0

вставляем код, изменяем нужные вам параметры и запускаем его:

using yoomoney_api.notification;
using yoomoney_api.quickpay;
using static System.Console;

var label = Guid.NewGuid().ToString();
var quickpay = new Quickpay(receiver: "4100118408605024", quickpayForm: "shop", sum: 10, 
	label: label, paymentType: "AC"); //Payment method. Possible values: PC - payment from the YuMoney wallet; AC - from a bank card.
WriteLine(quickpay.LinkPayment);

//заменяем --> ("YOUR_IP_ADDRESS_OR_DNS_NAME","NOTIFICATION_SECRET",YOUR_PORT")
PaymentListenerToYooMoney paymentListenerToYooMoney = new(label,DateTime.Today,"NOTIFICATION_SECRET");
var resultPayment = await paymentListenerToYooMoney.Listen("YOUR_IP_ADDRESS_OR_DNS_NAME","YOUR_PORT");
WriteLine(resultPayment);

в свойстве quickpay.LinkPayment будет находится ссылка для оплаты, а так же в консоли отобразиться следующая информация:

https://yoomoney.ru/transfer/quickpay?requestId=353432303336353332305f39366662343561383966646635393039633365396165366566656231366237383762333062346237

IP-appec: XXX.X.X.X // Доменное имя: https://XXXXXXXXXXX, IP: XX.XXX.XXX.XX
Сервер запущен. Ожидание подключений...

Что произойдет в приложении на данном этапе? В данный момент у нас выполнится код который отправит на сервер Yoomoney указанные вами параметры и вернет ссылку для оплаты, а так же асинхронно сервер будет ожидать TCP подключений в течении 12 минут или до успешной оплаты (почему именно 12 расскажу далее), после чего его время жизни будет перкращено.

Какие наши следующие действия? Прежде чем проводить оплату давайте все‑таки проверим, что все работает. Для этого нам нужно перейти на страницу, на которой мы подключали уведомления и нажать кнопку «Протестировать».

ngrok                                                                                                                                                                                               (Ctrl+C to quit)

Build better APIs with ngrok. Early access: ngrok.com/early-access

Session Status                online
Account                       arabaleevdennis@gmail.com (Plan: Free)
Version                       3.4.0
Region                        Europe (eu)
Latency                       56ms
Web Interface                 http://127.0.0.1:4040
Forwarding                    https://urchin-intimate-uniformly.ngrok-free.app -> http://127.0.0.1:3000

Connections                   ttl     opn     rt1     rt5     p50     p90
                              4       0       0.01    0.01    0.01    0.05

HTTP Requests
-------------

POST /
POST /

Отлично, Ngrok показывает 2 POST / запроса, смотрим что же у нас там в консоли программы:

/Users/lilrockstar/RiderProjects/ConsoleApp7/ConsoleApp7/bin/Debug/net7.0/ConsoleApp7
https://yoomoney.ru/transfer/quickpay?requestId=353432313036303037355f31316533343866613130336137623165386531626634393566633231643731326465363137303431

IP-appec: 127.0.0.1
Сервер запущен. Ожидание подключений...

Подключен клиент.
Не текущий платеж...

Подключен клиент.
Не текущий платеж...

А наша программа отлично приняла эти 2 запроса. Я не стал обозначать тестовые запросы, поэтому программа нам указывает на то, что это не текущий платеж (так как это не платеж, а просто тестовый запрос).

Проверка оплаты

Теперь нам осталось перейти по ссылке и произвести оплату (программу можно не перезапускать). После того как мы перешли по ссылке, ввели данные карты и код, нам нужно дождаться уведомления об оплате от нашего банка с которого мы оплачиваем, уведомление о списании придет раньше чем о зачислении. Как только пришло уведомление о списании денег в Ngrok поступил еще один пост запрос:

ngrok                                                                                                                                                                                               (Ctrl+C to quit)

Build better APIs with ngrok. Early access: ngrok.com/early-access

Session Status                online
Account                       arabaleevdennis@gmail.com (Plan: Free)
Version                       3.4.0
Region                        Europe (eu)
Latency                       56ms
Web Interface                 http://127.0.0.1:4040
Forwarding                    https://urchin-intimate-uniformly.ngrok-free.app -> http://127.0.0.1:3000

Connections                   ttl     opn     rt1     rt5     p50     p90
                              4       0       0.01    0.01    0.01    0.05

HTTP Requests
-------------

POST /
POST /
POST /

отлично, проверяем консоль нашего приложения:

/Users/lilrockstar/RiderProjects/ConsoleApp7/ConsoleApp7/bin/Debug/net7.0/ConsoleApp7
https://yoomoney.ru/transfer/quickpay?requestId=353432313036303037355f31316533343866613130336137623165386531626634393566633231643731326465363137303431

IP-appec: 127.0.0.1
Сервер запущен. Ожидание подключений...

Подключен клиент.
Не текущий платеж...

Подключен клиент.
Не текущий платеж...

Подключен клиент.
HTTP Requests
-------------

POST /
Текущий платеж:
        NotificationType   --> card-incoming
        OperationId        --> 753616322448916124
        DateTime           --> 2023-11-18 13:52
        Amount             --> 9.70
        WithdrawAmount     --> 10.00
        Firstname          -->  Null
        Lastname           -->  Null
        Fathersname        -->  Null
        Email              -->  Null
        Phone              -->  Null
        City               -->  Null
        Street             -->  Null
        Building           -->  Null
        Suite              -->  Null
        Flat               -->  Null
        Zip                -->  Null
        Sender             -->  Null
        Unaccepted         --> false
        Codepro            --> false
        Currency           --> 643
        Label              --> 8cfc9e98-ce15-4187-9b1b-e30a07c336a1

Успешно!
Сервер завершил работу

Ура, мы отследили наш платеж!

Что произойдет в приложении на данном этапе? После того как к нам придет в консоль «Подключен клиент», приложение асинхронно установит TCP соединение с Yoomoney и будет ожидать HTTP POST / или HTTPS POST / запрос, после того как данные придут, создастся массив байтов в который из потока мы прочитаем данные запроса, но почему мы уверены что это именно наш платеж и он пришел именно от Yoomoney?

Все просто, дело в том, что у нас есть такой уникальный параметр как Label который мы передаем при создании ссылки для оплаты, этот параметр прикрепляется к платежу и приходит нам обратно с уведомлением. Так же параметр DateTime который тоже возвращается в запросе, и вот тут нам пригождается наше секретное слово, на основе переданных параметров Yoomoney генерирует хеш который приходит нам параметром sha1_hash .

Для менее опытных следует сказать, что конечно стоит закреплять каждый платеж пользователя за этим самым пользователем (например в бд, достаточно сохранять туда дату, параметр label и amount, этого достаточно, чтобы отследить любой платеж).

На этапе обработки запроса наша программа тоже генерирует хеш-код на основе параметров запроса вместе с уникальным label который мы создали при генерации ссылки и серкетным словом которое мы получили при регистрации уведомлений. После того как все данные приняты мы сверяем параметры: label + DataTime.Date + sha1_hash из запроса с нашими сохраненными, если все эти данные совпадают платеж считается «Успешным».

Почему именно 12 минут? Дело в том, что Yoomoney после успешного пополнения счета отправляет на зарегистрированный url 3 уведомления (сразу после поступления средств на текущий счет, через 10 и через час), логично предположить, что если уведомление не пришло сразу и через 10 минут, оно не придет и через час, 2 минуты выделяется на то, чтобы пользователь произвел оплату (при нормальных обстоятельствах этого вполне достаточно), если он не уложится в эти 2 минуты, то 10 минут ему точно предостаточно! Если же после оплаты при нормальных обстоятельствах сообщение не придет сразу, то оно отследится через 10 минут. Если же все-таки каким-то загадочным образом платеж зачислился, но уведомление не пришло, то мы берем datetime и label этого платежа и обращаемся к коду предыдущей статьи, благодаря которому мы можем получить доступ к истории операций и по указанным параметрам его найти и проверить параметр status является ли он success ( то есть успешным). Следует сделать вывод: «Не один платеж не останется незамеченным, если средства действительно поступили насчет».

Так же стоит отметить, что только по протоколу HTTPS можно будет иметь доступ к контактной информации (однако в текущей версии api с этим возникаю проблемы, а поддержка Yoomoney пока что игнорирует вопросы и просьбы).

Пример того как должно было быть:

var quickpay = new Quickpay(
	receiver: "4100118408605024",
	quickpayForm: "shop",
	sum: 10, 
	label: label,
	paymentType: "AC",
	firstname:"Oleg",
	lastname:"Olegov",
	fathersname:"Olegovich",
	city:"Saint Petersburg",
	street:"Begovaya street",
	zip:"197374",
	building:"11",
	suite:"1",
	flat:"43",
	phone:"+7987674115",
	sender:"4100167987654");

//replace --> ("YOUR_IP_ADDRESS_OR_DNS_NAME","NOTIFICATION_SECRET",YOUR_PORT")
PaymentListenerToYooMoney paymentListenerToYooMoney = new(label,DateTime.Today,"NOTIFICATION_SECRET");
var resultPayment = await paymentListenerToYooMoney.Listen("YOUR_IP_ADDRESS_OR_DNS_NAME","YOUR_PORT");
WriteLine(resultPayment);

Вывод:

Подключен клиент.
HTTP Requests
-------------

POST /
Текущий платеж:
        NotificationType   --> card-incoming
        OperationId        --> 753525659460074104
        DateTime           --> 2020-01-12 01:22
        Amount             --> 9.70
        WithdrawAmount     --> 10.00
        Firstname          -->  Oleg
        Lastname           -->  Olegov
        Fathersname        -->  Olegovich
        Email              -->  Oleg@gmail.com
        Phone              -->  +79957773555
        City               -->  Saint Petersburg
        Street             -->  Begovaya street
        Building           -->  11
        Suite              -->  1
        Flat               -->  43
        Zip                -->  197374
        Sender             -->  4100167987654
        Unaccepted         --> false
        Codepro            --> false
        Currency           --> 643
        Label              --> 560bb09d-5986-38e9-abf8-cl59f21c0bh5

Успешно!
Сервер завершил работу

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

Отлично, теперь мы можем принимать платежи!

Заключение

Если данный пост вам помог, то поставьте звезду на GitHub. Мне будет очень приятно!

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


  1. mrrnvaa
    18.11.2023 13:32

    Спасибо, как раз то, что я искал!


    1. willdiealone Автор
      18.11.2023 13:32
      -3

      Супер!


  1. rSedoy
    18.11.2023 13:32
    +3

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


    1. willdiealone Автор
      18.11.2023 13:32
      -1

      ну это для физ лиц, считай просто обычный перевод на карту, почему не работает на айфонах? у меня айфон, я своего бота сделал с оплатой , все нормально работает


      1. willdiealone Автор
        18.11.2023 13:32
        -1

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


    1. Maxim_Q
      18.11.2023 13:32

      ...по закону нужна онлайн-касса, которая в ЮMoney дороже чем у конкурентов...

      Кажется они берут стандартную комиссию 3,5% с каждого платежа и +1,2% если чек нужно в налоговую автоматом отправить, абон платы нет. Есть где-то дешевле?


  1. Screami
    18.11.2023 13:32
    +1

    Если будет много платежей, то кошелек в бан улетит и все. Я перешёл на wallet телеграмовсий и никаких проблем


    1. willdiealone Автор
      18.11.2023 13:32
      -1

      Это не имеет отношения к этой статье, так как это не кошелек и не встроенный функционал telegram, вы оплачиваете переходя по ссылке, telegram ничего не знает об этом.


      1. valera_efremov
        18.11.2023 13:32
        +1

        Имеется ввиду, что Юмани кошелек улетит в бан за подозрительные операции.

        По статье добавлю. Вы перемудрили. Всё гораздо проще, у ЮМани есть пример html формы. Даже если написано, что принимают данные по POST, всё равно можно пользователя тупо из телеграм отправить по GET ссылке https://yoomoney.ru/quickpay/confirm.xml? с необходимыми параметрами, а юмани перенаправит уже сам на https://yoomoney.ru/transfer/quickpay?requestId И получаете callback http уведомление. Зачем вам Ngrok и пакет yoomoney-api. Всё делается в десяток строк кода.


        1. willdiealone Автор
          18.11.2023 13:32
          -1

          в каком месте я перемудрил? Я и отправляю запрос с необходимыми параметрами и тд. Ngrok мне нужен, так как я делаю все это на локальной машине и уведомление с клиента юмани на localhost придти не может, а Ngrok - это такой инструмент который позволяет создать защищенное туннельное соединение между локальным компьютером и интернетом. Он позволяет временно выставить локальный сервер или другие локальные сервисы наружу, делая их доступными через общедоступный url, короче говоря ваш localhost будет доступен из внешней сети «интернет». Ngrok используется просто для примера. Я и отправляю пользователя по ссылке, yoomoney-api позволяет отлежить текущий успешный платеж, принятием уведомления об оплате от Юмани


        1. willdiealone Автор
          18.11.2023 13:32
          -1

          в десяток строк кода это и делается в каком то смысле, увитывая, что пишен на довольно высоком уровне


        1. willdiealone Автор
          18.11.2023 13:32
          -1

          и почему кошелек юмани должен отлететь в бан? За какие операции?? Переводы по карте?? ????

          Я видел множество сервисов которые имеют такой подход, но у всех все работает не первый год)


    1. Xokare228
      18.11.2023 13:32

      При больших объёмах имеет смысл легализоваться и использовать взрослую ЮКассу, тогда вопросов не будет


      1. willdiealone Автор
        18.11.2023 13:32
        -1

        согласен, с вами


    1. NIKTO56
      18.11.2023 13:32
      +1

      Пока не было необходимости, но может быть в дальнейшем пригодится. Про wallet телеграм даже не слышала раньше.


  1. sasmoney
    18.11.2023 13:32
    +1

    И получаем блокировку кошелька за просто так


    1. willdiealone Автор
      18.11.2023 13:32
      -1

      о каком кошельке идет речь? Причем тут кошелек? вы переходите по ссылке и оплату производите на стороне браузера заполняя данные карты и тд. Telegram ничего не знает об этом!


  1. heiheshang
    18.11.2023 13:32

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


    1. willdiealone Автор
      18.11.2023 13:32

      вы имеете ввиду чтобы уведомление шло еще по одному пути? Они будут отправляться по указанному урлу и только.


      1. heiheshang
        18.11.2023 13:32

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


        1. willdiealone Автор
          18.11.2023 13:32
          -1

          согласен, с вами


        1. OwDafuq
          18.11.2023 13:32

          Можно сделать API общий для всех ваших проектов, который будет принимать пуши от платежки и раскидывать уведомления дальше (HTTP REST, RMQ, etc.), никаких проблем, вроде, это не должно составить


          1. heiheshang
            18.11.2023 13:32

            Если разработкой занимаются независимые организации, вы можете просто не договорится об этом.


            1. OwDafuq
              18.11.2023 13:32

              Если бы да кабы :)

              Спорить можно вечно

              Я так думаю, что в нормальных командах можно сразу обговорить эти детали, чтобы потом не возникало проблем


              1. heiheshang
                18.11.2023 13:32

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