Skip to main content

Subscription Status

AppActor supports two subscription-state models:

  • Payment mode (server-authoritative): use customerInfo(forceRefresh:)
  • Local mode (StoreKit-only): use getCustomerInfo(forceRefresh:)

Subscription Lifecycleโ€‹

Payment Mode Status Checksโ€‹

// Server-authoritative state (payment mode)
let info = try await AppActor.shared.customerInfo(forceRefresh: true)

print("Active entitlement keys: \(info.activeEntitlementKeys)")

if info.hasActiveEntitlement("premium") {
print("Premium access is active")
}

for entitlement in info.entitlements {
print("id=\(entitlement.id) active=\(entitlement.isActive)")
print("product=\(entitlement.productIdentifier ?? "none")")
print("expires=\(entitlement.expiresDate ?? "never")")
}

for subscription in info.subscriptions where subscription.isActive {
print("active subscription: \(subscription.productIdentifier)")
print("periodType: \(subscription.periodType ?? "n/a")")
}

Local Mode Detailed Fieldsโ€‹

Use local mode when you need direct on-device entitlement fields such as grace-period and ownership flags.

let info = await AppActor.shared.getCustomerInfo(forceRefresh: true)

if let premium = info.entitlements["premium"] {
print("Active: \(premium.isActive)")
print("Will renew: \(premium.willRenew)")
print("Expires: \(premium.expirationDate?.description ?? "never")")
print("In grace period: \(premium.isInGracePeriod)")
print("In billing retry: \(premium.isInBillingRetry)")
print("Revoked: \(premium.isRevoked)")
print("Period: \(premium.periodType)")
print("Ownership: \(premium.ownershipType)")
}

Grace Period and Billing Retryโ€‹

When a renewal fails, Apple may enter grace period and billing retry windows.

Local Modeโ€‹

AppActor.configure(
projectKey: "myapp",
grantAccessDuringGracePeriod: true, // Default: true
grantAccessDuringBillingRetry: false, // Default: false
offerings: { /* ... */ },
entitlements: { /* ... */ }
)

Payment Modeโ€‹

Grace period and billing retry access behavior is controlled server-side in your AppActor settings.

Family Sharing (Local Mode)โ€‹

let info = await AppActor.shared.getCustomerInfo()

if let premium = info.entitlements["premium"],
premium.ownershipType == .familyShared {
print("This entitlement is shared via Family Sharing")
}

Active Subscriptions and Purchases (Local Mode)โ€‹

let info = await AppActor.shared.getCustomerInfo()

print("Active subscriptions: \(info.activeSubscriptions)")
print("Active purchases: \(info.activeNonConsumables)")
print("Coin balance: \(info.consumableBalances["com.myapp.coins"] ?? 0)")

Next Stepsโ€‹