В Словении по указанию ЕС несколько лет назад начали борьбу со всем малым бизнесом и даже физлицами. Можно сказать стоят на страже как бы лишний евро в страну не зашёл. За переводы от физика к физику прилетает письмо из банка: “А ну-ка рассказывай каким бизнесом занимаешься”. Лезут просто в трусы в буквальном смысле. В России в последние годы творилась такая же вакханалия с закрытием счетов, при этом в России “бангстеры” стригли комиссии до 20%. В Словении хотя бы деньги без комиссий переводили. Сначала Unicredit и прочие брендовые банки нам отказали в счёте, потом и ноунейм банк. Вместе с корпоративным счётом закрывают и личный. Но есть лайфхак пункт 2 статьи 16 директивы 2014/92/EU, где сказано, что личный базовый счёт обязаны открывать даже бомжам и лицам, высылка которых невозможна.
2. Государства-члены должны гарантировать, что потребители, проживающие в Союзе на законных основаниях, включая потребителей без фиксированного адреса и лиц, ищущих убежища, а также потребителей, которым не предоставлен вид на жительство, но высылка которых невозможна по юридическим или фактическим причинам, имели право открывать и использовать платежный счет с базовыми функциями в кредитных организациях, расположенных на их территории. Такое право действует независимо от места жительства потребителя.
Государства-члены могут при полном соблюдении основных свобод, гарантированных Договорами, потребовать от потребителей, которые хотят открыть платежный счет с основными функциями на их территории, проявить искренний интерес к этому.
Государства-члены должны гарантировать, что осуществление права не будет слишком трудным или обременительным для потребителя.
В результате мы перешли в Revolut. А в Revolut нет ни загрузки платёжных поручений в XML, ни выгрузки выписок в XML, зато есть API.
Интегрироваться нужно было с самописной CRM, которая у нас с 2004 года постоянно дорабатывается на PHP.
Недостатки API Revolut банка
Scope не работает. Когда запрашиваем READ, то почему-то можно и писать, и отправлять платежи. Это позор! На мою претензию Revolut просто убрал scope из документации.
Нет возможности отозвать токен. Опять позор! Токен можно перезапросить и не сохранить, тогда старый перестанет действовать. Но это какой-то костыль.
Нет возможности в справочник контрагентов добавить второй счёт IBAN, хотя в ЛК на сайте такая возможность есть. Отправка платёжек работает через uuid контрагентов и uuid их IBAN. Удалить контрагента и создать заново с его счетами плохое решение, так как старые платежи же привязаны к старым UUID.
Можно создать несколько контрагентов с одинаковым именем и разными счетами. И получить бардак в данных. У контрагента нет уникального поля вроде ИНН или регистрационного номера, чтобы можно было различить две разных компании Ромашка.
Нет отдельной подписи платёжек. Когда отправляем платёж, то он сразу улетает в оплату — раздолье для хакеров. Нужен отдельный канал для подписи платёжек. Это может быть SMS, а лучше числовой генератор ENUM (TOTP).
Вот скрин, где запрашивался scope READ и Revolut отвечает, что будет выдан токен на чтение и на отправку платежей.
Думал может это просто интерфейс такой, верстальщики так сверстали. Так же не может быть в банке с 10М+ клиентов. Это же какой-то бред. Однако, работало на запись отлично!
В российских банках API работает по уму. Через DirectBank можно читать данные и писать — отправлять платёжки, зарплатные ведомости и что там ещё API DirectBank позволяет. При этом деньги никуда не отправятся пока лицо с правом подписи не зайдёт в ЛК или приложение и не подпишет платёжки. Подписание платёжек производится через независимый канал — СМС. Есть тут минус, что зависим от сотовой сети, СМСки не всегда доставляются оперативно. Значительно лучше бы использовать ENUM (TOTP) или аппаратный токен.
А у Revolut получаешь токен и отправляй платежи. Токен удобно хранить, чтобы не авторизовываться руками каждый раз. Однако, хранить токен с правами на отправку денег рискованно. Лично я так делать не стал.
Почему пришлось изобретать велосипед
Сначала я попробовал готовый уже имеющийся пакет на гитхабе. Но в нём нужно было, во-первых, городить свой огород с получением, ревалидацией и сохранением токенов, а это хотелось бы инкапсулировать под капот.
Во-вторых, этот модуль тянул с собой много зависимостей других модулей. А Revolut имеет такую особенность, что на непротиворечивые на первый взгляд параметры запроса отвечает:
Client error: resulted in a response: {"message":"Required 'profile id' is missing","code":2101}
И приходилось испытывать большие трудности с отладкой. Нужно было убедиться в том, что этот модуль отправляет всё точь в точь как указано в справочнике по API Revolut. Проследить это по коду кучи модулей, что там происходит было нереальной задачей. В результате пришлось править зашитую в модуль константу
const REVOLUT_PRODUCTION_ENDPOINT = 'https://b2b.revolut.com/api/';
на 'http://localhost:12345' и вывести запрос в консоль. В нашем модуле адрес apiUrl вынесен в параметры.
Ну и третье, что было важно, конкретно нам, это необходимость иметь модуль в старом проекте на php 5.6.
Поскольку ничего хитрого в отправке параметров нет и никакой математики внутри этого модуля Revolut-php тоже нет, то решил написать свой, но чтобы всё было в рамках одного файла, одного класса. Тут важен вопрос безопасности ещё, чтобы можно было проверить быстро исходный код, что в нём нет никаких закладок.
Наше решение Revolut-php
Итак, вот наш модуль Revolut-php. Всё в одном файле.
Из коробки по умолчанию уже работает получение и сохранение токенов. По умолчанию в файлах, но легко можно заменить код функции и хранить в базе или во внешнем каком-то хранилище да ещё и шифрование применить.
При этом мы не рекомендуем их сохранять, если есть риск, что кто-то может ими воспользоваться кроме вас.
Благодарности
Отдельное спасибо Павлу @maslick Маслову за помощь в тестировании и наведении порядка в нашем модуле Revolut-php. Павел специализируется на разработке облачных решений в AWS, любит open-source и открыт к новым челленджам и интересным предложениям.