Данная статья будет разбита на несколько частей.  Часть 1 - Вступление Часть 2 - Делаем клиент на TypeScript для Tinkoff эквайринг Часть 3 - Работа с картами МИР и иными картами поддерживающими 3DS V2 В рамках разработки нашего SaaS решения для автоматизации процессов кар-шерингов и авто-ренталов CarSense, перед нами стояла задача реализации системы рекуррентных платежей (Добавление карт пользователями для дальнейшего безакцептного списания).  Изначально мы использовали YooMoney, но крайне высокая комиссия не позволяла нам остаться на нем, в связи с чем было принято решение перейти на иной сервис эквайринга. Мы выбрали Tinkoff эквайринг. Данное решение стоило нам нескольких недель интеграции. В то время как в случае с ЮКассой интеграция заняла пару дней. С самого начала стало понятно, что будет это непросто, так как документация совершенно не помогает в интеграции, а, зачастую, вообще не описывает что и как должно работать. В интернете я не нашел ничего хотя бы отдаленно похожего на завершенное решение.  Интегрироваться с этим самостоятельно человеку в здравом уме не представляется возможным.  Но мы не такие, поэтому нам нужно было сделать свой клиент для организации приема платежей. Единственным источником правды был репозиторий реализации клиента на Flutter (ссылка) (что абсолютно небезопасно учитывая что все ключи хранятся прямо в нем). Выяснив, что сделать с этой документацией ничего нельзя, я начал реверсить то, что они написали в этом репозитории и адаптировать под клиент на бекенде.  В предыдущих реализациях нашего мобильного приложения мы уже пользовались этим клиентом, но отказались в силу того что НЕЛЬЗЯ ХРАНИТЬ СЕКРЕТНЫЕ КЛЮЧИ НА КЛИЕНТЕ! Следовательно, делаем вывод что как-то оно работает. Сам процесс разбора кода мы описывать не будем, кому интересно, могут сами пройти по ссылке и попробовать разобраться. Клиент мы реализовывали на TypeScript и Nodejs. Потому и примеры реализации будут на нем.  Сам Тиньков предоставляет нам схему (ссылка) по которой оно как бы работает. Говоря о рекуррентных платежах мы видим следующую картину: Что происходит между этими двумя вызовами никто описать не удосужился. Помимо прочего существует метод AddCard который присутствует в Flutter клиенте, и отсутствует в документации. Однако RemoveCard в документации есть. Есть ответы на которые нету вопросов, дальше это станет ясно. Реализовать все с использованием этого метода наверное можно, но в силу того, что из документации его судя по всему удалили, пользоваться им мы не будем.  Опишем наш базовый клиент signRequestPayload необходим для того, чтобы подписывать наши запросы. Здесь описана рабочая реализация того как это должно быть.  Init - Первичное создание платежа Данный метод нужен для того чтобы инициализировать платеж, но сам платеж при этом не создается. Теперь используем данные нашей карты. Их нужно зашифровать следующим образом Для того, чтобы платеж создать нужно использовать метод FinishAuthorize. Создаем из полученных данных acsUrl на который направим клиента  Добавлю вам пример на EJS того, что должно быть на этой странице, потому что Тиньков этого сделать не придумал В колбек мы указали свой сервер, где перехватим ответ от 3DS, следующим образом В документации вы об этом ничего не найдете. Там просто отсутствует информация о том, что делать после FinishAuthorize. Делаем это с картой Visa / MS, вроде бы работает да? Теперь пробуем добавить карту Мир. Не работает вообще ничего.  Это, и множество других, неинформативных, бессмысленных сообщений мы получим дальше.  Казалось бы что на сегодняшний день, когда образовалось огромное количество сложностей для работ зарубежных платежных систем Тиньков в первую очередь должен обеспечить работу карт Мир. Однако никто даже не парился о том, чтобы в документации доступно объяснить процесс интеграции. Об это там написано 1.5 слова, что нужно вызвать метод Check3DSVersion. На этом все заканчивается.  Мы потратили непростительное количество времени, чтобы это преодолеть. Но я очень сомневаюсь, что кто-то помимо нас готов бы был на это. Поддержка совершенно не помогает, они не обладают информацией о том, как работает сервис.  Зачастую они либо просто пропадают и игнорируют вопросы, либо предлагают решения не относящиеся к предмету проблемы.  Для того чтобы заставить это творение работать с картами 3DS V2 действительно необходимо вызвать метод проверки версии. Но помимо этого, нужно поменять сам запрос FinishAuthozire и привести его к следующему виду.  О том что эти данные должны быть в DATA в документации ничего не написано. Без них метод работать не будет. Интересно, что в Flutter клиенте перед его вызовом есть метод CollectData, который 1 - не нужен, 2 - неправильно написан в самом клиенте, настолько он не нужен  (ссылка) Complete3DSMethodV2 Если он не нужен, то уберите его, а если нужен, то сделайте, чтобы он работал submit3DS для 3DS V2 Ну и сам ASCUrl V2 В зависимости от версии выбираем тот или иной метод генерации Очень важный момент. URLSearchParams превращает симовл "%3D" в "%253D".  Это ломает процесс интеграции. Чтобы этого избежать я делаю так .toString().replace("%253D", "%3D") Страница для вызова ACS  Я не знаю каков статус продукта Tinkoff Acquiring но Текущее его состояние абсолютно неприемлемо. Выглядит так будто проект заброшен и им никто не пользуется.  На гитхабе есть один жизнеспособный клиент и это https://github.com/MadBrains/Tinkoff-Acquiring-SDK-Flutter/, но нельзя хранить приватные ключи в мобильном клиенте. Любой школьник в состоянии вытащить приватные ключи и откатить все проведенные транзакции. Прошу команду Тиньков обратить внимание на данный пост, сделать выводы и привести сервис в достойное состояние. Надеюсь данная статья поможет другим командам.  Всех благ! 🍺 Сказать "Спасибо": USDT TRC20 TPVQGCoPbyDZfcjAxVi1VmdApkVCifoqcm