Install
$ agentstack add skill-revenuecat-play-billing-skills-subscription-state-diagram ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Subscription State Diagram
Phase 0: Intent
Use this skill when you need a single place to look up:
- What states a Google Play subscription can be in.
- Which RTDN (Real Time Developer Notification) moves a subscription from one state to the next.
- Whether a given state grants access to paid content.
- What token behavior to expect across renewals, pauses, holds, and resubscribes.
This is a reference skill. It does not write code for you. It hands you the map so you can point at a node, point at an edge, and then make a decision about access or acknowledgement.
Phase 1: Locate
Tell the skill which part of the state machine you care about. Pick the shortest path that matches your question.
| You want to know... | Jump to | |---------------------|---------| | What every state means and whether it grants access | States at a Glance | | Which RTDN fires on a specific transition | Transition Table | | Whether to grant access right now | Access Decision Flowchart | | What happens to the purchase token across events | Token Lifecycle | | The numeric code for a notification type | RTDN Quick Reference | | How long grace period, account hold, or token validity lasts | Time Windows |
A typical lookup looks like this:
- Name the current state (for example
IN_GRACE_PERIOD). - Name the event you observed (for example RTDN type 5).
- Find the row in the From
IN_GRACE_PERIODtable. - Read the target state and the access rule.
Phase 2: Reference Diagram
States at a Glance
| State | Access | Description | |-------|--------|-------------| | PENDING | No | Purchase initiated, payment not yet processed | | ACTIVE | Yes | Subscription is paid and current | | INGRACEPERIOD | Yes | Payment failed, Google is retrying, user keeps access | | ON_HOLD | No | Grace period expired, access revoked, awaiting payment fix | | PAUSED | No | User requested pause, access revoked | | CANCELED | Until expiry | Canceled but not expired, access until expiryTime | | EXPIRED | No | Subscription has ended |
Transition Table
Every edge in the diagram. Columns: origin state, destination state, trigger, RTDN name and numeric type.
| From | To | Trigger | RTDN | |------|----|---------|------| | PENDING | ACTIVE | Payment completes | SUBSCRIPTION_PURCHASED (4) | | PENDING | EXPIRED | Payment fails or times out | SUBSCRIPTION_PENDING_PURCHASE_CANCELED (20) | | ACTIVE | ACTIVE | Successful renewal | SUBSCRIPTION_RENEWED (2) | | ACTIVE | INGRACEPERIOD | Renewal fails, grace period enabled | SUBSCRIPTION_IN_GRACE_PERIOD (6) | | ACTIVE | ONHOLD | Renewal fails, no grace, account hold enabled | SUBSCRIPTION_ON_HOLD (5) | | ACTIVE | CANCELED | User or developer cancels | SUBSCRIPTION_CANCELED (3) | | ACTIVE | EXPIRED | Revoked or refunded | SUBSCRIPTION_REVOKED (12) | | ACTIVE | PAUSED | Pause takes effect at end of period | SUBSCRIPTION_PAUSED (10) | | INGRACEPERIOD | ACTIVE | Payment recovered | SUBSCRIPTION_RECOVERED (1) | | INGRACEPERIOD | ONHOLD | Grace expires without payment | SUBSCRIPTION_ON_HOLD (5) | | INGRACEPERIOD | EXPIRED | Grace expires, no account hold | SUBSCRIPTION_EXPIRED (13) | | ONHOLD | ACTIVE | User fixes payment | SUBSCRIPTION_RECOVERED (1) | | ONHOLD | EXPIRED | Account hold period expires | SUBSCRIPTION_EXPIRED (13) | | PAUSED | ACTIVE | Pause ends, payment succeeds | SUBSCRIPTION_RECOVERED (1) | | PAUSED | ON_HOLD | Pause ends, payment fails | SUBSCRIPTION_ON_HOLD (5) | | CANCELED | ACTIVE | User restores before expiration | SUBSCRIPTION_RESTARTED (7) | | CANCELED | EXPIRED | expiryTime reached | SUBSCRIPTION_EXPIRED (13) | | EXPIRED | ACTIVE | User resubscribes, new purchase token | SUBSCRIPTION_PURCHASED (4) |
RTDN Quick Reference by Number
| # | Name | Common Usage | |---|------|--------------| | 1 | RECOVERED | Restore access after hold or pause | | 2 | RENEWED | Extend access period | | 3 | CANCELED | Note cancellation, keep access until expiry | | 4 | PURCHASED | New subscription, grant access | | 5 | ONHOLD | Revoke access | | 6 | INGRACEPERIOD | Keep access, warn user | | 7 | RESTARTED | Restore access, same token | | 8 | PRICECHANGECONFIRMED | Deprecated | | 9 | DEFERRED | Extend billing date | | 10 | PAUSED | Revoke access at period end | | 11 | PAUSESCHEDULECHANGED | Check pause status | | 12 | REVOKED | Immediately revoke access | | 13 | EXPIRED | Revoke access, clean up | | 17 | ITEMSCHANGED | Check updated line items | | 18 | CANCELLATIONSCHEDULED | Note scheduled cancellation | | 19 | PRICECHANGEUPDATED | Check price change details | | 20 | PENDINGPURCHASECANCELED | Clean up pending records | | 22 | PRICESTEPUPCONSENT_UPDATED | Check consent status |
Time Windows
| Window | Duration | What Happens | |--------|----------|--------------| | Acknowledgement | 3 days | Unacknowledged purchases auto refund | | Grace period | 1 to 30 days, configurable | User keeps access while Google retries | | Silent grace period | 1 day minimum | Applies even when grace is set to 0 days | | Account hold | Up to 30 days, configurable | User loses access, can recover by fixing payment | | Token validity | 60 days post expiration | API calls still succeed in this window | | Pause duration | 1 week to 3 months | Depends on billing period |
Phase 3: Handling Guidance Per Transition
Each row tells you what to do when the RTDN lands. Pair this with the access rule in Phase 2.
| Transition | Your handler should | |------------|----------------------| | PENDING to ACTIVE | Acknowledge within 3 days, provision entitlement, store the purchase token | | PENDING to EXPIRED | Clean up the pending record, do not provision access | | ACTIVE to ACTIVE (renewal) | Extend the entitlement to the new expiryTime, keep the same token | | ACTIVE to INGRACEPERIOD | Keep access on, surface a payment warning, trigger In App Messaging | | ACTIVE to ONHOLD | Revoke access, tell the user to fix payment in Play | | ACTIVE to CANCELED | Keep access until expiryTime, show an expiry countdown, log the cancel reason | | ACTIVE to EXPIRED (revoke) | Revoke access immediately, note the refund or revocation | | ACTIVE to PAUSED | Access ends at period end, show resume date on next open | | INGRACEPERIOD to ACTIVE | Clear the warning banner, confirm expiryTime moved forward | | INGRACEPERIOD to ONHOLD | Revoke access, swap the warning for a fix payment prompt | | INGRACEPERIOD to EXPIRED | Revoke access, offer resubscribe | | ONHOLD to ACTIVE | Restore the entitlement, keep the existing token | | ONHOLD to EXPIRED | Revoke, offer resubscribe, stop polling the token after 60 days | | PAUSED to ACTIVE | Restore access, same token | | PAUSED to ON_HOLD | Keep access revoked, switch message to fix payment | | CANCELED to ACTIVE | Restore, same token, remove the expiry countdown | | CANCELED to EXPIRED | Revoke, offer resubscribe | | EXPIRED to ACTIVE | Treat as a new purchase, new token, link it to the prior user identity |
Access Decision
Use the same rule across every handler.
fun shouldGrantAccess(
state: String,
expiryTimeMillis: Long
): Boolean = when (state) {
"SUBSCRIPTION_STATE_ACTIVE",
"SUBSCRIPTION_STATE_IN_GRACE_PERIOD" -> true
"SUBSCRIPTION_STATE_CANCELED" ->
System.currentTimeMillis() false
}
Token Lifecycle
| Event | Token Behavior | |-------|----------------| | New purchase | New token | | Renewal | Same token, new Order ID | | Upgrade or downgrade | New token, old token linked via linkedPurchaseToken | | Restore before expiry | Same token | | Resubscribe after expiry | New token | | Pause and resume | Same token | | Grace period recovery | Same token | | Account hold recovery | Same token |
References
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: RevenueCat
- Source: RevenueCat/play-billing-skills
- License: Apache-2.0
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.