Highlight
Apple adds monthly payment plans with a 12-month commitment for annual subscriptions. Users pay monthly, lowering the decision barrier, while developers secure long-term subscription revenue. StoreKit adds
PricingTermsandbillingPlanTypeAPIs for display and purchase, server-side JWSTransaction adds acommitmentInfofield to track fulfillment progress, and App Store Connect now supports bundling IAPs with other review items in a single review submission flow.
Core Content
The pricing dilemma for annual subscriptions
Every developer running a subscription business has faced this problem: push annual subscriptions and users abandon when they see the full upfront charge; push monthly subscriptions and users can cancel at any time, making LTV hard to protect. Both options have tradeoffs, but there has been no middle ground.
Apple provides an official solution in iOS 26.5: monthly subscriptions with a 12-month commitment. Users pay a smaller amount each month, but the contract is locked for 12 months. Developers get a predictable long-term revenue expectation, while users face a lower decision barrier.
This plan is configured directly in App Store Connect. Select a one-year auto-renewable subscription, set availability under “monthly with a 12-month commitment availability,” and follow the steps to finish configuration. Each billing plan can configure subscription offers independently, such as offering a free trial only to commitment-plan users.
(01:53)
Showing the new billing plan with StoreKit
After configuration, StoreKit exposes billing plan information through the new PricingTerms property. SubscriptionInfo.pricingTerms returns an array containing every available billing plan for the product. The default annual prepaid plan type is .upFront; if monthly commitment is configured, the array includes an additional .monthly object.
When using SubscriptionStoreView in SwiftUI, you can filter and prioritize the monthly commitment plan with the .preferredSubscriptionPricingTerms modifier.
(03:29)
Tracking commitment progress on the server
After a user subscribes, the server needs to know which month of the commitment period the user is in and how many periods remain. JWSTransaction and JWSRenewalInfo add a commitmentInfo field with data such as billingPeriodNumber for the current period, totalBillingPeriods for the total number of periods, and commitmentExpiresDate for the commitment end date.
Key point: if billingPeriodNumber is less than totalBillingPeriods, the user is still within the commitment period. Even if the user turns off auto-renewal in system settings, Apple will continue monthly billing until the commitment period ends. The server must not remove user entitlement early.
(07:45)
Offer Code Redemption API upgrade
The offer code redemption API now returns VerificationResult. On success, you directly receive the transaction object; on failure, you receive a specific error. There is no longer any need to depend on Transaction.updates and guess the redemption result.
Use the .offerCodeRedemption modifier in SwiftUI and presentOfferCodeRedeemSheet in UIKit. StoreKit Testing in Xcode 27 supports testing the new redemption API.
(09:58)
Unified App Store Connect review submission flow
IAP review submissions can now be packaged into one Submission with other review items, such as In-App Events, custom product pages, and product page optimizations. After submission, you can view the status of every review item in a centralized view.
The reviewSubmissions endpoint in the App Store Connect API expands support for IAP, subscription, and subscription group resources. The old IAP-specific submission APIs will be deprecated, and Apple recommends migrating to the new reviewSubmission and reviewSubmissionItems resources.
(10:42)
Details
Displaying a monthly commitment plan in StoreKit views
(03:29)
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
}
}
}
}
Key points:
SubscriptionStoreViewautomatically loads product metadata from the App Store and adapts its layout across platforms.preferredSubscriptionPricingTermsis a modifier added in iOS 26.5 for filtering the billing plan to display firstsubscriptionInfo.pricingTermsreturns all available billing plans..upFrontis always present, while.monthlyappears only when a commitment plan is configured- Without filtering, the system defaults to
.upFront, so the lower monthly price advantage of monthly commitment is not visible
Getting pricing information and purchasing in a custom store UI
(04:02)
import StoreKit
var product: Product?
// Fetch and assign product
let pricingTerms = product?.subscription?.pricingTerms
.first(where: { $0.billingPlanType == .monthly })
if let pricingTerms {
let monthlyPrice = pricingTerms.billingDisplayPrice
let totalCommitmentPrice = pricingTerms.commitmentInfo.price
// Display both monthly and total commitment price to the customer
}
let result = try? await product?.purchase(options: [.billingPlanType(.monthly)])
switch result {
// Verify the transaction, give the customer access to
// the purchased content, and then finish the transaction
}
Key points:
billingDisplayPriceis the monthly installment amount displayed to the usercommitmentInfo.priceis the total price across the 12 months; the UI should show both the monthly payment and total price- Pass the
.billingPlanType(.monthly)option when purchasing to specify the monthly commitment plan - Billing plan metadata is returned only when the plan is available in the user’s storefront
Manage Subscriptions sheet
(05:05)
import SwiftUI
import StoreKit
struct ManageSubscriptionsButton: View {
let subscriptionGroupID: String
@State var presentingManageSubscriptionsSheet: Bool = false
var body: some View {
Button("Manage Subscriptions") {
presentingManageSubscriptionsSheet = true
}
.manageSubscriptionsSheet(
isPresented: $presentingManageSubscriptionsSheet,
subscriptionGroupID: subscriptionGroupID
)
}
}
Key points:
.manageSubscriptionsSheetis the SwiftUI way to show the subscription management interface- The UIKit equivalent is the
showManageSubscriptionsAPI - Users can view remaining payment periods and the commitment renewal date in the management interface
- The App Store automatically provides the new management UI for commitment subscriptions
Commitment information in server-side JWSTransaction
(07:45)
{
"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
}
}
Key points:
billingPlanTypeset to"MONTHLY"indicates this is a monthly commitment subscriptioncommitmentInfo.billingPeriodNumberindicates the current billing cycle numbercommitmentInfo.totalBillingPeriodsis fixed at 12commitmentInfo.commitmentExpiresDateis the end time of the full commitment period- For
.upFronttransactions,commitmentInfoisnil
Commitment renewal information in server-side JWSRenewalInfo
(07:59)
{
"renewalBillingPlanType": "MONTHLY",
"commitmentInfo": {
"commitmentAutoRenewProductId": "plus.standard.annual",
"commitmentAutoRenewStatus": 0,
"commitmentRenewalDate": 1812447660000,
"commitmentRenewalPrice": 10990,
"commitmentRenewalBillingPlanType": "BILLED_UPFRONT"
}
}
Key points:
commitmentAutoRenewStatusset to 0 means the user has chosen not to renew after the commitment period endscommitmentRenewalBillingPlanTypeindicates the renewal plan type after the commitment period- In this example, the user chose to switch to an upfront annual subscription after the commitment period
commitmentInfoappears in renewal info only while the current subscription is in a commitment period
Offer Code Redemption sheet
(09:58)
struct OfferCodeRedemption: View {
@State var presentingOfferCodeSheet: Bool = 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, give the customer access to
// the purchased content, and then finish the transaction
}
case .failure(let error):
// Handle error
}
}
}
}
Key points:
.offerCodeRedemptionnow returnsVerificationResult, making redemption results explicitly trackable- The
optionsparameter accepts an array ofRedeemOptionvalues for configuring redemption behavior - On successful redemption,
verificationResultcontains the transaction object - Use
presentOfferCodeRedeemSheetin UIKit to implement the same functionality
Key Takeaways
Add monthly commitment plans to subscription products
What to do: Configure a 12-month commitment monthly payment option for existing annual subscription products, and prioritize it in the app.
Why it is worth doing: It lowers the first-payment barrier while locking in 12 months of subscription revenue. For price-sensitive users, a monthly installment amount is easier to accept than the annual total.
How to start: Find the existing one-year auto-renewable subscription in App Store Connect and set “monthly with a 12-month commitment” availability. In code, use .preferredSubscriptionPricingTerms to filter the .monthly plan and display it first.
Build commitment progress UI
What to do: In the app’s account or subscription management page, show which month of the commitment period the user is in and how many periods remain.
Why it is worth doing: Transparency increases user trust and reduces support complaints like “I didn’t know I signed up for 12 months.” It can also help users make renewal decisions before the commitment period ends.
How to start: Get the latest transaction from Transaction.currentEntitlements, read the commitmentInfo field, and calculate progress from billingPeriodNumber and totalBillingPeriods.
Upgrade offer code redemption logic
What to do: Migrate existing offer code redemption call sites to the new API and get explicit redemption result callbacks.
Why it is worth doing: The old API did not provide a direct result after redemption, requiring asynchronous listening through Transaction.updates, which was complex and error-prone. The new API returns success or failure directly.
How to start: Search for presentOfferCodeRedeemSheet calls in your code and replace them with the new version that includes a VerificationResult callback. Test the redemption flow in StoreKit Testing in Xcode 27.
Unify the review submission workflow
What to do: Move IAP review submissions into the unified reviewSubmissions workflow and package them together with the app binary and In-App Events.
Why it is worth doing: It avoids the awkward situation where the app is live but the IAP is still under review. A unified submission means all review items pass or are rejected together, with fully synchronized status.
How to start: Check existing CI/CD scripts and migrate old IAP-specific submission API calls to the reviewSubmissions and reviewSubmissionItems resources.
Prepare subscription Bundles and Suites
What to do: If you have multiple apps or multiple subscription products, plan the product structure for subscription Bundles or Suites ahead of time.
Why it is worth doing: A Bundle packages multiple separately purchasable subscriptions at a discounted price, while a Suite provides a subscription group that exists only as a whole for a set of related apps. Both can increase subscription revenue.
How to start: Test the Bundles and Suites APIs in Xcode 27, and watch for the commercialization details Apple will announce in the second half of the year.
Related Sessions
- What’s new in StoreKit 2 and StoreKit Testing in Xcode — New StoreKit 2 features and testing best practices in Xcode
- Explore Retention Messaging in App Store Connect — Server-to-server Retention Messaging API for precise retention flows around 12-month commitment subscriptions
- What’s New in App Store Connect — A deeper look at review submission workflows
- Implement App Store Offers — Configuration and implementation of offer codes and subscription offers
Comments
GitHub Issues · utterances