Grace period for failed subscription billing

NOVASOLUTIONS.TECHNOLOGY is engaged in the development, support and maintenance of iOS, Android, PWA mobile applications. We have extensive experience and expertise in publishing mobile applications in popular markets like Google Play, App Store, Amazon, AppGallery and others.
Development and support of all types of mobile applications:
Information and entertainment mobile applications
News apps, games, reference guides, online catalogs, weather apps, fitness and health apps, travel apps, educational apps, social networks and messengers, quizzes, blogs and podcasts, forums, aggregators
E-commerce mobile applications
Online stores, B2B apps, marketplaces, online exchanges, cashback services, exchanges, dropshipping platforms, loyalty programs, food and goods delivery, payment systems.
Business process management mobile applications
CRM systems, ERP systems, project management, sales team tools, financial management, production management, logistics and delivery management, HR management, data monitoring systems
Electronic services mobile applications
Classified ads platforms, online schools, online cinemas, electronic service platforms, cashback platforms, video hosting, thematic portals, online booking and scheduling platforms, online trading platforms

These are just some of the types of mobile applications we work with, and each of them may have its own specific features and functionality, tailored to the specific needs and goals of the client.

Showing 1 of 1 servicesAll 1735 services
Grace period for failed subscription billing
Medium
~2-3 business days
FAQ
Our competencies:
Development stages
Latest works
  • image_mobile-applications_feedme_467_0.webp
    Development of a mobile application for FEEDME
    756
  • image_mobile-applications_xoomer_471_0.webp
    Development of a mobile application for XOOMER
    624
  • image_mobile-applications_rhl_428_0.webp
    Development of a mobile application for RHL
    1052
  • image_mobile-applications_zippy_411_0.webp
    Development of a mobile application for ZIPPY
    947
  • image_mobile-applications_affhome_429_0.webp
    Development of a mobile application for Affhome
    862
  • image_mobile-applications_flavors_409_0.webp
    Development of a mobile application for the FLAVORS company
    445

Implementing Grace Period for Failed Subscription Billing

Grace Period is a temporary window that Apple and Google give users after failed billing: expired card, insufficient funds, temporary bank error. During grace period, the subscription remains active. The developer's task is to correctly read this status and not cut off users from content prematurely.

Without grace period implementation, the app blocks access immediately after failed billing. The user updates their card but has already left — direct loss in retention.

Grace Period on iOS (StoreKit 2)

Apple automatically activates grace period if it's enabled in App Store Connect → Subscriptions → [Subscription Group] → Grace Period. Duration options: 3, 6, or 16 days.

To read the status, we use Product.SubscriptionInfo.Status:

import StoreKit

func checkSubscriptionStatus(productId: String) async -> SubscriptionAccessLevel {
    guard let product = try? await Product.products(for: [productId]).first,
          let statuses = try? await product.subscription?.status else {
        return .notSubscribed
    }

    for status in statuses {
        switch status.state {
        case .subscribed:
            return .active

        case .inGracePeriod:
            // Billing failed, but grace period is active
            // Show soft warning, don't block content
            return .gracePeriod

        case .inBillingRetryPeriod:
            // Grace period expired, Apple continues billing attempts (up to 60 days)
            // Content is NOT accessible
            return .billingRetry

        case .expired, .revoked:
            return .notSubscribed

        default:
            continue
        }
    }
    return .notSubscribed
}

enum SubscriptionAccessLevel {
    case active, gracePeriod, billingRetry, notSubscribed
}

What to Show the User in Grace Period

Key principle: don't block content, but show a soft banner encouraging payment data update. Aggressive paywall in grace period is poor UX and violates Apple guidelines.

// SwiftUI banner
if subscriptionStatus == .gracePeriod {
    GracePeriodWarningBanner(
        message: "Failed to process payment. Update your card details to retain access.",
        actionTitle: "Manage Subscription",
        action: { openManageSubscriptions() }
    )
}

// Open system subscription management screen
func openManageSubscriptions() {
    Task {
        try? await AppStore.showManageSubscriptions(in: windowScene)
    }
}

Grace Period on Android (Google Play Billing)

In Google Play Billing, grace period is implemented through purchaseState and isAutoRenewing:

// Via RTDN (Real-Time Developer Notifications) or PurchasesUpdatedListener
// Google sends SubscriptionNotification.SUBSCRIPTION_IN_GRACE_PERIOD

fun handleSubscriptionNotification(notification: SubscriptionNotification) {
    when (notification.notificationType) {
        SubscriptionNotification.SUBSCRIPTION_IN_GRACE_PERIOD -> {
            // Content is accessible, show warning
            showGracePeriodWarning()
        }
        SubscriptionNotification.SUBSCRIPTION_EXPIRED -> {
            // Grace period expired
            revokeAccess()
        }
    }
}

Server-side handling is preferable: RTDN arrives on backend via Pub/Sub, backend updates user status, mobile client receives current status on next request.

Server-Side Validation — More Reliable Than Client-Side

Client-side check via StoreKit is convenient for UI but shouldn't be the only source of truth. Correct architecture:

  1. Server receives transactions via App Store Server Notifications V2 (types DID_FAIL_TO_RENEW, GRACE_PERIOD_EXPIRED)
  2. Updates the subscription_status field in database
  3. Mobile client on /me/subscription request receives current status

This is the only reliable way if the user opens the app days later — StoreKit cache may not have updated.

What's Included in the Work

  • Enabling grace period in App Store Connect / Google Play Console
  • Client-side reading of inGracePeriod / inBillingRetryPeriod (StoreKit 2)
  • UI banner with warning and link to manage subscription
  • Content access logic: grace = allowed, billingRetry = blocked
  • Optional: server-side handling of App Store Server Notifications

Timeline

2–3 days — client-side part with UI logic. With server-side notification handling: 4–5 days. Pricing is calculated individually.