Продавец написал нам с конкретной просьбой. У него небольшой SaaS, он уже продаёт разовые файлы через API Getly и хотел, чтобы тот же API умел месячные планы: создать план, отправить клиента на страницу оплаты, узнать, когда платёж прошёл, узнать, когда не прошёл, в любой момент спросить, оплачен ли ещё человек. Он сравнил это со Stripe Billing, и правильно сделал. У нас этого не было. Был список вебхуков, обещавший шестнадцать событий, семь из которых код не отправлял никогда.
Это история двух недель после письма, рассказанная как решения, потому что продукт — это и есть решения.
Что это, одним абзацем
Getly Billing берёт регулярную оплату со своих клиентов продавца через Getly за то, что продавец ведёт сам. План живёт в API (POST /api/v1/billing/plans: сумма в центах от пятидесяти, интервал в днях, неделях, месяцах или годах, до пятидесяти двух). Страница подписки живёт на getly.store и создаётся под каждого клиента с идентификатором клиента, который передал продавец. Клиент платит картой — это настоящая Stripe-подписка, которая продлевается сама, — или в USDT/USDC, что покупает ровно один период. Дальше бэкенд продавца получает пять вебхуков — создана, продлена, платёж не прошёл, отменена, истекла, — и каждый несёт тот самый идентификатор клиента, поэтому обработчику не нужен поиск. Когда вебхука недостаточно, один GET отвечает, оплачен ли человек. План никогда не появляется в каталоге маркетплейса; подписчик попадает на сайт продавца, не на наш.
Решение первое: стоит столько же, сколько ваш собственный трафик
Подписчик чужого SaaS не нашёл этот SaaS на Getly. Он пришёл с сайта продавца, зарегистрировался на странице продавца и был отправлен к нам только заплатить. Это ровно та ситуация, которую наша модель цен уже называет собственным трафиком, а собственный трафик платит десять процентов. Поэтому Getly Billing берёт десять процентов с каждого платежа и больше ничего — ни абонплаты, ни платы за план, ни за подключение. Мы рассматривали надбавку за платформу и отказались по простой причине: число уже стоит в таблице цен, а второе число для той же ситуации потребовало бы второго объяснения.
Решение второе: куда идут деньги, зависит от того, что есть у продавца
Первый черновик отправлял каждый платёж прямо на Stripe Connect продавца, потому что так чище всего считать. Это исключило бы большинство продавцов: Stripe подключило лишь небольшое меньшинство магазинов, которые вообще что-то продали, и это сделало бы крипту невозможной — у стейблкоина нет перевода через Connect. Отгруженная версия гибридная. Если у магазина есть аккаунт Connect, перевод происходит внутри Stripe с каждого инвойса, а наша комиссия снимается как application fee. Если нет, деньги приходят на счёт Getly и выплачиваются 1-го и 15-го ровно как продажа на маркетплейсе, через тот же журнал, который уже читает прогон выплат. Крипта всегда проходит через Getly. Продавец в обоих случаях видит один дашборд.
Решение третье: крипта платит по периодам, и никто не делает вид, что иначе
Криптоплатёж нельзя списать. Поэтому крипто-план — не подписка в карточном смысле, а период, купленный одним инвойсом. Подписчику напоминают за семь дней до конца периода, и он платит снова из своего аккаунта Getly. Заплатил рано — новый период стекается к концу текущего; заплатил поздно — начинается сегодня, потому что никто не должен платить за уже потерянные дни. Если не платит никто, ежечасная задача закрывает период, и эндпоинт продавца получает событие «истекла». Мы говорим это прямо на странице подписки, до нажатия, потому что клиент, ждавший автопродления и получивший тишину, обвинит продавца, а продавец обвинит нас.
Решение четвёртое: доступ по заявке
Это решение основателя, и именно оно скорее всего раздражит спешащего разработчика, поэтому заслуживает объяснения. Когда Getly списывает деньги с карты, Getly — продавец записи: списание несёт наше имя, спор приходит на наш счёт, вопрос регулятора — к нам. Продавать файл, который мы храним, — одно. Брать ежемесячно за сервис, которого мы не видим, — другое. Поэтому до первого списания продавец сообщает нам публичный сайт, на котором работает продукт, и несколько предложений о том, что это, и человек это читает. До одобрения каждый вызов на запись отвечает конкретным кодом ошибки, который говорит ровно это, со ссылкой на форму; чтение работает, так что интеграцию можно построить и проверить до конца ревью. Обычно ревью занимает меньше дня. Мы предпочтём потерять продавца, который не хочет сказать, что продаёт, чем узнать это из чарджбэка.
Что нашло тестирование и не нашло чтение
Перед отгрузкой мы прогнали всё на копии боевой базы со Stripe в тестовом режиме, headless-браузером, платящим тестовой картой, и тест-часами Stripe, которые проматывают месяц за минуту. Всё по списку работало: заявка, гейт, планы, чекаут, первый платёж, настоящее продление, отмена со стороны подписчика, крипто-путь с напоминаниями и истечением. Одно — нет. Когда карта отклонялась, эндпоинт продавца никогда не получал событие о неудачном платеже. Stripe присылает смену статуса подписки на мгновение раньше, чем неудачный инвойс, наш синк статуса уже записал «просрочена», и обработчик отказа решил, что продавцу сообщили. Исправление — дедупликация по инвойсу, а не по статусу: продавцу сообщают один раз на инвойс, а повторные попытки Stripe по тому же инвойсу молчат. Прочитать код дважды это бы не нашло; нашёл порядок двух событий на проводе.
Если вы ведёте что-то, за что люди должны платить каждый месяц, и уже работаете с нашим API, на лендинге есть версия в пять шагов, а в справочнике — всё остальное. Подавайте заявку из дашборда; API открывается в момент, когда человек говорит «да».



