Деньги остаются в ваших системах. Арифметика — в наших.
Платформа — это вычисление и запись. Она принимает то, что произошло в ваших системах, считает, сколько причитается, и отправляет обратно поручения. Она никогда не стоит в денежном пути.
Опубликованная спецификация и два клиента, написанных по ней.
Документ OpenAPI в репозитории, клиент на TypeScript и клиент на Dart. Ваш инженер прочитает всю поверхность API прежде, чем кто-то назначит созвон.
OpenAPI
api/openapi.yaml
Клиент на TypeScript
sdk/typescript
Клиент на Dart
sdk/dart
События, в доставке которых можно быть уверенным.
Одиннадцать типов событий, ставящихся в очередь в той же транзакции, что и породившее их изменение состояния.
- 01
Транзакционный outbox, а не POST по принципу «отправил и забыл»
Событие пишется в той транзакции, которая его вызвала, и рассылается потом из очереди с арендой. Нет окна, в котором вашей системе сообщили о том, что книга затем откатила, и нет окна, в котором книга зафиксировала, а никому не сообщили.internal/outbox
- 02
Подписано, с ротируемым идентификатором ключа
Каждая доставка несёт подпись HMAC-SHA256 с идентификатором ключа и меткой времени. Ротация перекрывается: старый ключ действителен, пока вы переключаетесь, поэтому смена секрета — не простой, который надо планировать.internal/outbox/sign.go
- 03
События расчётов идут первыми
Поручение на выплату не стоит в очереди за грудой уведомлений. Классы доставки — это отдельные полосы, и расчёты — та полоса, которая везёт денежное поручение.internal/events
- 04
Детерминированные id, поэтому повторный прогон ничего не меняет
Повторный прогон обработчика ставит в очередь тот же id события, а outbox отбрасывает дубликат. Это доставка «хотя бы один раз», которую действительно можно повторять, а не та, с которой надо быть осторожным.internal/events · internal/outbox
- 05
Проверка исходящего трафика на ваш URL
Адрес назначения задаёт оператор, и одно это делает его SSRF-вектором по конструкции. Диспетчер проверяет URL до отправки запроса и блокирует те адреса, которые вы и ожидаете от него заблокировать.internal/outbox/ssrf.go
- 06
Отступ, парковка и сверщик
Сбои откладываются со всё большим интервалом и в конце концов паркуются, а не долбят лежащий адрес. Межсистемный сверщик ловит по-настоящему потерянное событие, вместо того чтобы верить в безупречность очереди.internal/outbox · internal/reconciler
Команды, выполняемые ровно один раз, по идентификаторам ваших записей.
Вы сообщаете платформе, что произошла покупка, произошёл возврат, участник прошёл проверку. Повторять бесплатно, потому что ключ ваш.
Каждая входящая команда идемпотентна в пределах рабочего пространства и идентификатора, а ответ кэшируется. Отправьте ту же покупку дважды — второй вызов вернёт ответ первого: он не создаст вторую покупку и не выплатит второй круг комиссий по первой.
Контракт ошибок явный, потому что «повторять или нет» — это тот вопрос, на который клиентской интеграции действительно надо отвечать. Возвращённая ошибка освобождает расписку, и вы можете повторить. Отказ с кодом 4xx окончателен и кэшируется: команда отклонена по существу, и повтор отклонят снова.
internal/commands · internal/command
Платите так, как платите уже сейчас.
Платформа резервирует ровно нужные строки книги и выдаёт поручение. Исполняет платёж ваша сторона.
Если у вас есть система расчётов, она получает поручение на выплату как событие расчётного класса и вызывает обратно, чтобы отчитаться об оплате или сбое. Если её нет, консоль выплат перечисляет задолженность, вы платите из собственного кошелька и записываете исполненную цену и собственный идентификатор транзакции. Платёж, записанный без идентификатора, отклоняется — его невозможно было бы сверить с вашим кошельком, поэтому принять его значит лишь, что сверка сломается позже и дальше.
internal/claims · internal/httpapi/payouts.go
Ваш собственный домен, подтверждённый до подключения.
Заявите имя хоста, опубликуйте TXT-запись, которую сгенерирует платформа, и подключение произойдёт, как только запись начнёт разрешаться.
Порядок здесь важен, и в нём весь смысл. Привязать имя хоста — или добавить домен в список разрешённых у провайдера идентификации — до доказательства контроля значит позволить настоящему владельцу этого имени получать входы, предназначенные вам. Поэтому ничего не подключается и ничего не добавляется в список разрешённых для входа, пока запись не начнёт разрешаться. Фоновый механизм подхватывает её в течение минуты.
internal/domains
Возьмите песочницу и направьте её на стенд.
Бесплатно на любом тарифе, с той же поверхностью API, теми же событиями и теми же подписями, что и в бою.