Введение
В прошлой статье я рассказывал о том, как можно при помощи регистрации своего телеграм бота или сайта в клиенте Yoomoney получать токен и с его помощью получать доступ к информации об аккаунте (истории операций, деталей операций и информации о счете), это в принципе единственный вариант получить доступ к этим данным и в целом это позволяло как-то проверять оплату на своем сайте или в телеграм боте, но все же с точки зрения пользователя такой подход в котором ему нужно прикладывать какие-то усилия для того, чтобы произвести банальную оплату явно не лучший вариант, всегда хочется все сделать уже привычным способом, а именно просто ввести данные с карты и получить услугу или товар. В этой статье мы научимся это делать! Все, что вам нужно это ваш ip адрес или доменное имя и порт.
Описание
Настройка уведомлений
Создание ссылки для оплаты
Проверка оплаты
Как я уже сказал все, что вам нужно это ip адрес вашего хостинга или доменное имя и порт. Я буду пользоваться утилитой Ngrok, для тех кто не знает, Ngrok - это такой инструмент который позволяет создать защищенное туннельное соединение между локальным компьютером и интернетом. Он позволяет временно выставить локальный сервер или другие локальные сервисы наружу, делая их доступными через общедоступный url, короче говоря ваш localhost будет доступен из внешней сети «интернет». Мне это необходимо для примера, так как весь пример будет выполняться на локальной машине
Видео туториал есть на GitHub проекта
Настройка уведомлений
Заходим в кошелек ЮMoney. Если кошелька нет, создаем его, после этого нам нужно подключить HTTP/HTTPS уведомления к нашему кошельку Yoomoney.

Указываем url на который хотим принимать уведомления и обязательно сохраняем секретное слово (оно нам еще понадобиться).
Ставим галочку «Отправлять HTTP‑уведомления».
Нажимаем кнопку «Готово».
Отлично, наш кошелек готов к отправке уведомлений!
Для дальнейших действий нам понадобиться библиотека 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. Мне будет очень приятно!