WWDC.ai

What's new in Apple In-App Purchase

Learn the new StoreKit and App Store Connect workflows for monthly annual-commitment subscriptions, offer code redemption, and IAP review submissions.

Watch on Apple Developer

TL;DR

  • Monthly subscriptions with a 12-month commitment let customers pay monthly for a one-year auto-renewable subscription; configure them in App Store Connect for new or existing annual products.
  • StoreKit adds pricing terms and billing-plan purchase options so apps can merchandise monthly commitment plans, display commitment pricing, and purchase a specific billing plan.
  • Transaction, RenewalInfo, App Store Server API, and App Store Server Notifications V2 payloads expose billing-plan and commitment metadata for entitlement and lifecycle handling.
  • Offer code redemption now returns a VerificationResult and accepts RedeemOption values, and App Store Connect is moving IAP review submissions into the unified reviewSubmissions workflow.

Monthly subscriptions with a 12-month commitment

iOS 26.5 introduces a new pricing option for one-year auto-renewable subscriptions: customers can pay monthly while committing to a 12-month subscription. Developers can add this billing plan to new or existing annual subscriptions in App Store Connect.

After compiling against the 26.5 SDK, eligible customers in available markets can subscribe to the new billing plan in apps running on iOS, iPadOS, macOS, tvOS, or visionOS 26.4. Each auto-renewable subscription has at least one pricing term with the default .upFront billing plan type; products configured with the new option also return a .monthly pricing term.

  • Configure availability for "monthly with a 12-month commitment" on a one-year subscription in App Store Connect.
  • Offers can be configured separately per billing plan type, such as a free trial only for the commitment plan.
  • Billing plan metadata is returned only when available for the customer's storefront.

Merchandising and purchasing with StoreKit

StoreKit adds PricingTerms on SubscriptionInfo for presenting available billing plans. StoreKit views can prefer a specific pricing term, while custom UI can fetch products with the Product API, read pricing terms, and display both monthly price and total commitment price.

To purchase a monthly commitment plan from custom UI, pass the new .billingPlanType(.monthly) purchase option. As with other StoreKit flows, verify the transaction, unlock the entitlement, and finish the transaction.

  • Use SubscriptionStoreView with .preferredSubscriptionPricingTerms for StoreKit-managed subscription UI.
  • Use product.subscription?.pricingTerms for custom merchandising.
  • Display both billingDisplayPrice and commitmentInfo.price when presenting commitment pricing.
  • Use .billingPlanType(.monthly) when initiating purchase for the monthly commitment plan.

Prefer monthly commitment pricing in a StoreKit subscription view

Filters the subscription store to merchandise the monthly billing plan when the product has monthly commitment pricing available.

import StoreKit
import SwiftUI

struct SubscriptionStore: View {
    var body: some View {
        SubscriptionStoreView(groupID: "3F19ED53") {
            // Custom marketing content
        }
        .preferredSubscriptionPricingTerms { _, subscriptionInfo in
            subscriptionInfo.pricingTerms.first {
                $0.billingPlanType == .monthly
            }
        }
    }
}

Read pricing terms and purchase a monthly billing plan

Custom UI can select the monthly pricing term, present required pricing context, and purchase that billing plan explicitly.

import StoreKit

var product: Product? // Fetch and assign product

let pricingTerms = product?.subscription?.pricingTerms
    .first { $0.billingPlanType == .monthly }

if let pricingTerms {
    let monthlyPrice = pricingTerms.billingDisplayPrice
    let totalCommitmentPrice = pricingTerms.commitmentInfo.price
    // Display both prices to the customer
}

let result = try? await product?.purchase(options: [.billingPlanType(.monthly)])

switch result {
    // Verify the transaction, grant access, and finish the transaction
}

Subscription management, entitlements, and testing

The App Store automatically presents a one-time disclosure sheet before a customer first subscribes to a commitment plan. It explains the number of payments required and includes cancellation guidance. Apple's subscription management UI also shows available plans, remaining payments, and the commitment renewal date.

Apps can present subscription management directly with SwiftUI's .manageSubscriptionsSheet or UIKit's showManageSubscriptions API. For app-side entitlement and progress UI, use the latest transaction: upfront billing plans have commitmentInfo == nil, while monthly commitment plans provide progress, price, and commitment expiration metadata.

StoreKit Testing in Xcode 26.5 supports creating a monthly-with-12-month-commitment billing plan for a one-year auto-renewable subscription in a StoreKit configuration file. Developers can configure commitment pricing, create offers per billing plan type, test purchases with the transaction manager, and inspect commitmentInfo in the Transaction inspector.

  • Always use the latest transaction for an accurate expiration date.
  • Transaction exposes billing-plan-specific metadata for the current billing period.
  • RenewalInfo exposes renewalBillingPlanType and commitment renewal information for the overall commitment.
  • Commitment-related StoreKit fields are available starting with OS 26.4.

Present Apple's subscription management sheet

Lets customers manage subscriptions from inside the app, including monthly commitment plan status.

import SwiftUI
import StoreKit

struct ManageSubscriptionsButton: View {
    let subscriptionGroupID: String
    @State var presentingManageSubscriptionsSheet = false

    var body: some View {
        Button("Manage Subscriptions") {
            presentingManageSubscriptionsSheet = true
        }
        .manageSubscriptionsSheet(
            isPresented: $presentingManageSubscriptionsSheet,
            subscriptionGroupID: subscriptionGroupID
        )
    }
}

Server-side monitoring and subscription lifecycle

App Store Server APIs and App Store Server Notifications V2 add fields to signed transaction and renewal info objects for monthly subscriptions with a 12-month commitment. Notifications continue to report lifecycle events, including monthly renewals, during the commitment.

Decoded JWSTransaction payloads can include billingPlanType and commitmentInfo so servers can identify billing-period purchases and relate them to the total commitment. Decoded JWSRenewalInfo payloads can include renewal preferences after the commitment ends, and these commitment fields are present only while the subscription is currently in a commitment.

  • Use server fields to track the current billing period number, total billing periods, commitment expiration, and commitment price.
  • Use renewal info to detect the customer's post-commitment renewal product, status, price, and billing plan type.
  • The Retention Messaging API also supports this payment option for auto-renewable subscriptions.

Decoded signed transaction fields for a monthly commitment plan

Shows the billing-period transaction in the context of the full 12-month commitment.

{
  "expiresDate": 1783503660000,
  "price": 10990,
  "productId": "plus.pro.annual",
  "purchaseDate": 1780911660000,
  "type": "Auto-Renewable Subscription",
  "billingPlanType": "MONTHLY",
  "commitmentInfo": {
    "billingPeriodNumber": 1,
    "totalBillingPeriods": 12,
    "commitmentExpiresDate": 1812447660000,
    "commitmentPrice": 131880
  }
}

Decoded renewal info fields for post-commitment renewal

Shows renewal preferences that apply when the current commitment completes.

{
  "renewalBillingPlanType": "MONTHLY",
  "commitmentInfo": {
    "commitmentAutoRenewProductId": "plus.standard.annual",
    "commitmentAutoRenewStatus": 0,
    "commitmentRenewalDate": 1812447660000,
    "commitmentRenewalPrice": 10990,
    "commitmentRenewalBillingPlanType": "BILLED_UPFRONT"
  }
}

Offer codes, Bundles and Suites, and App Review submission

The OfferCodeRedemption API now accepts a set of RedeemOption values and returns a VerificationResult when redemption completes. On success, the app receives a transaction in the verification result; on failure, the app receives an error describing why redemption failed. A UIKit variant is available through presentOfferCodeRedeemSheet, and Xcode 27 can test offer code redemption for applicable product types.

Bundles and Suites are a new subscription offering model. A Bundle groups individually purchasable subscriptions into a single purchase, typically at a better combined price. A Suite groups subscriptions that only exist together in the suite and usually provide service across related apps. API testing for Bundles and Suites starts in Xcode 27, with more program details coming later in 2026.

App Store Connect's enhanced submission experience lets developers group multiple In-App Purchase products as review items in a single App Review submission. IAPs can be submitted alongside other review item types such as in-app events, custom product pages, and product page optimizations. The App Store Connect API's reviewSubmissions collection is expanding to support In-App Purchase, subscription, and subscription group resources, replacing older IAP/subscription submission resources over time.

  • Update offer code redemption call sites to handle VerificationResult.
  • Use the enhanced App Store Connect review workflow to keep related review items together.
  • Start migrating App Store Connect API automation toward reviewSubmission and reviewSubmissionItems resources.

Redeem an offer code and handle VerificationResult

Uses the updated SwiftUI offer code redemption API, which returns a verification result instead of only presenting the sheet.

import SwiftUI
import StoreKit

struct OfferCodeRedemption: View {
    @State var presentingOfferCodeSheet = false

    var body: some View {
        Button("Redeem Offer Code") {
            presentingOfferCodeSheet = true
        }
        .offerCodeRedemption(options: [], isPresented: $presentingOfferCodeSheet) { result in
            switch result {
            case .success(let verificationResult):
                switch verificationResult {
                    // Verify the transaction, grant access, and finish it
                }
            case .failure(let error):
                // Handle error
            }
        }
    }
}

Resources

Unofficial, not associated with Apple. BySuperwall

On this page

Ask AI