К основному содержанию
скилл CX Codex

rc-subscription-states — скилл для Claude Code: доступ по подписке

Скилл для Android-проектов на RevenueCat: подсказывает агенту, как проверять доступ к платному контенту через CustomerInfo и EntitlementInfo.

Установить в Claude Code · Через Skills CLI (Vercel) Все способы и платформы ↓
npx skills add RevenueCat/ai-toolkit --skill rc-subscription-states -a claude-code
Открыть на GitHub

Что делает rc-subscription-states

Скилл ведёт агента по четырём фазам: сначала выясняет, какой идентификатор entitlement закрывает фичу и нужен ли просто булев ответ или ещё и причина отказа, потом планирует, потом пишет код, потом проверяет. Главная мысль, которую он проводит через весь код: доступ гейтится по entitlement.isActive == true, и больше ни по чему. Остальные поля — willRenew, periodType, expirationDate, billingIssueDetectedAt, unsubscribeDetectedAt, store — нужны только для объяснения контекста.

Внутри есть таблица соответствия семи состояний Google Play (ACTIVE, IN_GRACE_PERIOD, CANCELED до даты окончания, ON_HOLD, PAUSED, EXPIRED, PENDING) одному булеву полю RevenueCat. Если вы раньше собирали этот маппинг сами через Google Play Developer API, скилл снимает с вас эту работу. Ещё в нём готовые примеры на Kotlin: чтение CustomerInfo через awaitCustomerInfo(), принудительное обновление с CacheFetchPolicy.FETCH_CURRENT после выдачи промо на бэкенде, слушатель updatedCustomerInfoListener и вход по awaitLogIn() для мультидевайса.

Одна деталь, на которой легко ошибиться: слушатель не срабатывает, если SDK стартовал с попаданием в кэш и ничего не изменилось. Поэтому awaitCustomerInfo() при запуске нужен отдельно, в дополнение к подписке на обновления. Скилл рассчитан на Android и Kotlin — для других платформ и языков примеры не подойдут.

Какие задачи решает

  • закрыть платную фичу по активной подписке
  • показать предупреждение о проблеме с оплатой, не отбирая доступ
  • напомнить о скором окончании доступа после отмены
  • обновить CustomerInfo после промо, выданного поддержкой
  • связать анонимные покупки с залогиненным пользователем

Примеры запросов агенту

  • Проверь доступ к pro-функциям через entitlement.isActive и покажи экран подписки, если доступа нет
  • Добавь обработку billingIssueDetectedAt и unsubscribeDetectedAt в UI премиум-экрана
  • Настрой updatedCustomerInfoListener и вызов awaitCustomerInfo() при запуске

Как установить rc-subscription-states

1Через Skills CLI (Vercel)

npx skills add RevenueCat/ai-toolkit --skill rc-subscription-states -a claude-code

2Вручную: положить файлы

~/.claude/skills/rc-subscription-states/SKILL.md

Папка скилла целиком; для одного проекта — .claude/skills/rc-subscription-states/

По шагам, с командами для каждой платформы: Как установить скилл в Claude Code: пять способов

Вопросы о rc-subscription-states

Как установить rc-subscription-states в Claude?

Выполните npx skills add RevenueCat/ai-toolkit --skill rc-subscription-states -a claude-code. Скилл окажется в ~/.claude/skills/rc-subscription-states/SKILL.md.

Что делает rc-subscription-states?

Помогает агенту гейтить доступ к функциям по состоянию подписки RevenueCat на Android: читать CustomerInfo, проверять entitlement.isActive и разбирать willRenew, periodType и expirationDate, когда нужна более сложная логика.

Нужен ли этот скилл, если я уже сам разбираю состояния Google Play?

Он как раз для этого случая: вместо маппинга семи состояний Google Play на решение о доступе вы читаете одно булево поле isActive, которое RevenueCat считает на бэкенде.

Исходный текст

SKILL.md · MIT
---
name: rc-subscription-states
description: Use this skill when gating access based on RevenueCat subscription state on Android. Covers reading CustomerInfo, checking entitlement.isActive as the single source of truth for access, and drilling into willRenew, periodType, and expirationDate when deeper logic is needed.
license: Apache-2.0; see LICENSE
metadata:
  author: RevenueCat
  source: revenuecat-handbook chapter 11
  keywords:
  - android
  - revenuecat
  - customerinfo
  - entitlement
  - is-active
  - will-renew
---

# Subscription States

Decide whether a user has access, and drive state aware UI, using `CustomerInfo` and `EntitlementInfo` on Android.

## Phase 1: Discover

Confirm what you are actually checking before you write code.

- Which entitlement identifier gates the feature? (for example `pro_access`)
- Do you need a plain access boolean, or do you also need to explain *why* the user has or lacks access (billing issue, canceled but still paid, paused)?
- Do you need the cached value (fast, possibly stale) or a freshly fetched value (server authoritative)?
- Are you refreshing UI once on launch, or reacting to live changes (purchase, restore, background refresh)?

If you only need access on/off, you only need `isActive`. Everything else is optional context.

## Phase 2: Plan

### Google's seven states versus RevenueCat's boolean

Rolling your own tracker with the Google Play Developer API means mapping seven subscription states and deciding which grant access.

| Google state | Grants access? |
|---|---|
| ACTIVE | yes |
| IN_GRACE_PERIOD | yes |
| CANCELED (before `expirationDate`) | yes |
| ON_HOLD | no |
| PAUSED | no |
| EXPIRED | no |
| PENDING | no |

RevenueCat computes this on the backend from the Google `SubscriptionPurchaseV2` resource and exposes the result as one field: `EntitlementInfo.isActive`. You read a boolean instead of implementing the state machine.

### What to read, and when

| Need | Field |
|---|---|
| Does the user have access right now? | `entitlement.isActive` |
| Will the subscription renew at period end? | `entitlement.willRenew` |
| When does paid access end? | `entitlement.expirationDate` |
| Is this a trial, intro, prepaid, or normal period? | `entitlement.periodType` |
| Is there a payment problem? | `entitlement.billingIssueDetectedAt` |
| Has the user canceled but still has time left? | `entitlement.unsubscribeDetectedAt` |
| Which store issued the entitlement? | `entitlement.store` |

### Decision rules

- Gate features on `isActive == true`. Nothing else.
- Use `billingIssueDetectedAt != null` to show a fix payment prompt.
- Use `unsubscribeDetectedAt != null` with `expirationDate` to show a renewal reminder while access is still valid.
- Use `!willRenew` (when no billing issue and no explicit cancel timestamp) to show a non renewing notice.

## Phase 3: Execute

### Read CustomerInfo and check access

```kotlin
val customerInfo = Purchases.sharedInstance.awaitCustomerInfo()
val hasAccess = customerInfo.entitlements["pro_access"]?.isActive == true
```

`awaitCustomerInfo()` returns the disk cache immediately, then refreshes from the network in the background. Entitlement checks stay fast, even offline.

### Force a fresh fetch when you must

Use this after a server side grant (for example, a support agent issued a promo).

```kotlin
val fresh = Purchases.sharedInstance.awaitCustomerInfo(
    fetchPolicy = CacheFetchPolicy.FETCH_CURRENT
)
```

### Drive state aware UI

`isActive` gates access; the other fields explain context.

```kotlin
fun updateUI(entitlement: EntitlementInfo?) {
    if (entitlement == null || !entitlement.isActive) {
        showSubscribeScreen(); return
    }
    showPremiumContent()
    when {
        entitlement.billingIssueDetectedAt != null -> showBillingIssueWarning()
        entitlement.unsubscribeDetectedAt != null ->
            entitlement.expirationDate?.let { showExpiryNotice(it) }
        !entitlement.willRenew -> showNonRenewingNotice()
    }
}
```

### Messaging guide by signal

| Signal on an active entitlement | Message to show |
|---|---|
| `billingIssueDetectedAt != null` | Payment problem, update method |
| `unsubscribeDetectedAt != null` | Access ends on `expirationDate` |
| `willRenew == false` (no other signal) | Will not renew this period |
| `periodType == TRIAL` or `INTRO` | Trial or intro pricing in effect |

### Identify the user for multi device

```kotlin
val result = Purchases.sharedInstance.awaitLogIn("your_user_id")
val customerInfo = result.customerInfo
val createdNewUser = result.created
```

`awaitLogIn()` merges anonymous purchases with the identified user. `logOut()` starts a fresh anonymous session.

## Phase 4: Verify

### Listen for CustomerInfo updates

Register a listener so UI reacts to purchases, restores, and background refreshes without manual polling.

```kotlin
Purchases.sharedInstance.updatedCustomerInfoListener =
    UpdatedCustomerInfoListener { info ->
        val active = info.entitlements["pro_access"]?.isActive == true
        updateAccessGate(active)
    }
```

The listener does not fire when the SDK starts with a cache hit and nothing changed. Always call `awaitCustomerInfo()` on launch in addition to setting the listener.

### Test matrix

Walk through each case and confirm the UI responds correctly.

| Case | Expected `isActive` | Expected UI |
|---|---|---|
| Fresh purchase | true | Premium content |
| Grace period (billing issue, still granted) | true | Premium + billing warning |
| Canceled, still before `expirationDate` | true | Premium + expiry notice |
| On hold | false | Subscribe screen |
| Paused | false | Subscribe screen |
| Expired | false | Subscribe screen |
| Pending (no payment yet) | false | Subscribe screen |

### Sanity checks

- Access gate flips correctly when the listener fires after a purchase.
- `FETCH_CURRENT` updates `CustomerInfo` after a backend grant (promo, refund, support action).
- After `logOut()`, `CustomerInfo` reflects an anonymous user and `isActive` resets accordingly.
- Offline launch still returns cached `CustomerInfo` and gates access without a network call.

## References

- [Full chapter](https://www.revenuecat.com/guides/revenuecat-android-sdk/subscription-states)

© RevenueCat · MIT · RevenueCat/ai-toolkit

Похожие скиллы

Всё по теме «Мобильная разработка» →
subscription-lifecycle appeeky Скилл помогает разбирать подписочный цикл от пробного периода до продления, отмены и возврата ушедших подписчиков. Нужен для анализа конверсии, оттока и неудачных платежей. CX Codex +1 2 500установок capacitor-in-app-purchases capawesome-team Скилл ведёт агента по шагам: настройка товаров в App Store Connect и Google Play Console, выбор плагина, покупки, валидация чеков и тесты в песочнице. CX Codex +1 728установок asc-subscription-localization rorkai Массово заполняет названия и описания подписок или встроенных покупок в App Store Connect через утилиту asc. Избавляет от ручного кликанья по десяткам языков. CX Codex +1 6 800установок subscription-integration dodopayments Скилл по жизненному циклу подписок Dodo Payments после оплаты: триалы, смена плана, пауза, возврат после неудачного платежа. CX Codex +1 1 000установок asc-revenuecat-catalog-sync rorkai Сверяет каталог подписок и встроенных покупок App Store Connect с продуктами RevenueCat. Нужен перед запуском или при устранении расхождений между каталогами. CX Codex +1 6 100установок paywall-optimization appeeky Скилл для аудита и A/B-тестов пейвола в подписочных приложениях. Помогает найти слабую ступень воронки и починить её. CX Codex +1 1 900установок

Из того же набора25

rc-backend Скилл для работы с состоянием RevenueCat на сервере: чтение подписчиков, выдача и отзыв entitlements, атрибуты через REST API. CX Codex +1 635установок rc-setup Проведёт по дашборду RevenueCat и подключению Google Play: приложение, сервисный аккаунт, entitlements, offerings и публичный API-ключ. CX Codex +1 638установок rc-configuring-the-sdk Скилл проводит агента через подключение RevenueCat к Android-приложению: Gradle-зависимость, Purchases.configure, стратегия app user id и уровень логов. CX Codex +1 636установок rc-catalog-management Ведёт каталог Android-товаров между Play Console и панелью RevenueCat: импорт продуктов, привязка к entitlement, сборка офферов. CX Codex +1 627установок rc-error-handling Разбирает ошибки RevenueCat Android SDK: какой код что значит и что показать пользователю. Пригодится, когда платёжный флоу ломается на проде. CX Codex +1 627установок rc-revenuecat-api-quick-reference Справочник по Android SDK 10.x и REST API RevenueCat прямо в редакторе: сигнатуры вызовов, структура Offerings, поля CustomerInfo. CX Codex +1 624установок rc-price-changes Помогает провести новую цену подписки в Google Play через RevenueCat, не трогая код приложения. CX Codex +1 618установок rc-understanding-revenuecat Объясняет агенту, как устроен RevenueCat Android SDK 10.x, до того как он напишет хоть строчку кода. Пригодится, если вы переходите с чистого Play Billing. CX Codex +1 617установок

Спонсоры проекта

Компании, которые помогают держать аналитику открытой