Синхронизация подписок с App Store и Google Play ломается не на оплате, а на границах состояний
Внешний магазин живет по своей модели: purchase, renewal, grace, retry, canceled, refunded. Внутри биллинга эти события надо свести к единому жизненному циклу, иначе появляются двойные активации, «вечные» доступы и revenue leakage. Идемпотентность в биллинге — это не рекомендация, а базовый вопрос выживания системы.
Критично хранить не только текущий статус, но и причинно-следственную цепочку: кто прислал событие, какой у него event_id, к какой entitlement-группе оно относится, был ли уже применен переход. Для каждого входящего апдейта нужен дедуп по ключу магазина и транзакционный апдейт локального состояния. Без этого повторная доставка webhook или pull-ответа превращается в повторное включение доступа.
Отдельная зона риска — расхождения по времени. Магазин может уже считать подписку истекшей, а ваш backend еще держит grace-период; или наоборот. Поэтому статус доступа лучше вычислять не по одному полю, а по набору правил: paid_until, grace_window, refund_flag, cancel_at_period_end. Если правила конфликтуют, приоритет у консервативной блокировки доступа, а не у оптимистичного продления.
Самая надежная схема — event sourcing для входящих сигналов + периодический reconciliation job, который сверяет локальные entitlementы с магазином и помечает аномалии: пропущенное продление, неожиданный refund, расхождение по SKU, смена аккаунта. Такой контур не убирает ошибки полностью, но делает их наблюдаемыми и управляемыми.
Если синхронизация подписок у вас строится вокруг единого статуса «активна/неактивна», система рано или поздно начнет терять деньги. Нужна модель состояний, дедупликация, транзакционность и регулярная сверка — только так магазин и ваш биллинг перестают спорить о праве пользователя на доступ.
Подписки: биллинг-лаб
@subscriptions_billing_lab_arb
Синхронизация подписок с App Store и Google Play ломается не на оплате, а на границах состояний
Этот пост опубликован в Telegram-канале Подписки: биллинг-лаб. Подписаться можно по ссылке: @subscriptions_billing_lab_arb.