- Published on
- 9 min read
> What's New in StoreKit for Xcode 27: Commitment Plans, Offer Codes, and More
WWDC 2026 and Xcode 27 brought a handful of changes to StoreKit and In-App Purchases that are worth a look if you sell subscriptions or digital goods. The headline is a new way to price annual subscriptions, but there are also welcome updates to offer code redemption, a new Bundles and Suites program, and a cleaner App Review submission flow. I'll walk through each one and what it means for your code.
Monthly Subscriptions With a 12-Month Commitment
This is the big one. You can now offer customers an annual subscription that they pay for monthly instead of all at once. The customer still commits to a full year, but the cost is spread across twelve monthly payments. For a lot of apps this lowers the barrier to entry without giving up the retention benefits of an annual plan.
You set this up in App Store Connect as a new billing plan on an existing one-year auto-renewable subscription. Pick the product, choose "Set Up Availability" under the monthly with a 12-month commitment option, and configure pricing. You can even attach offers that apply only to the commitment plan, like a free trial that's exclusive to customers who choose monthly billing. The feature is available at runtime on iOS, iPadOS, macOS, tvOS, and visionOS 26.4, once you build against the 26.5 SDK.
Reading Pricing Terms
On the code side, the entry point is a new pricingTerms property on a product's subscription info. It returns an array of every billing plan available for that product. Every auto-renewable subscription has at least one entry with a billingPlanType of .upFront, which is the classic pay-now annual plan. If you've configured a commitment plan, a second entry shows up with a billingPlanType of .monthly.
The simplest way to merchandise this is with StoreKit views, which already handle loading metadata and adapting layout across platforms. There's a new view modifier, preferredSubscriptionPricingTerms, that you attach to a SubscriptionStoreView and use to pick which billing plan to show:
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
}
}
}
}
That's all it takes for the store to present the monthly commitment option. If you've customized your SubscriptionStoreView with icons or backgrounds in the past, none of that changes.
Building Custom Store UI
If you render your own purchase screen, fetch the product with the Product API and read the pricing terms directly. The monthly plan exposes both its per-period price and the total commitment price, so you can show customers exactly what they're signing up for:
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
}
Billing plan metadata is only returned when the plan is available in the customer's storefront, so always guard against a missing entry rather than assuming the monthly option exists everywhere.
To make the purchase, pass the new billing plan type as a purchase option:
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
}
Before a customer subscribes to a commitment plan for the first time, the App Store automatically presents a disclosure sheet. It explains how many payments are required to fulfill the commitment and how cancellation works, and it shows once per Apple Account. You don't build or trigger this yourself, it's handled for you.
Managing an Active Commitment
Once a subscription is active, the App Store provides built-in management UI where customers can see their available plans, how many payments remain, and when the commitment renews. You can surface it from inside your app with the manageSubscriptionsSheet modifier in SwiftUI, or showManageSubscriptions in UIKit:
import SwiftUI
import StoreKit
struct ManageSubscriptionsButton: View {
let subscriptionGroupID: String
@State private var presentingManageSubscriptionsSheet = false
var body: some View {
Button("Manage Subscriptions") {
presentingManageSubscriptionsSheet = true
}
.manageSubscriptionsSheet(
isPresented: $presentingManageSubscriptionsSheet,
subscriptionGroupID: subscriptionGroupID
)
}
}
To check entitlements or build your own progress indicator, Transaction carries new billing plan metadata. For an .upFront transaction, commitmentInfo is nil. For a .monthly transaction it returns the progress, price, and expiration for the twelve-month commitment. There's matching information on RenewalInfo through renewalBillingPlanType and its own commitmentInfo, which describes what happens when the current commitment ends. These fields are available starting with OS 26.4. One important detail: always read from the latest transaction to get an accurate expirationDate, since earlier transactions reflect older billing periods.
Server-Side Fields
If you rely on the App Store Server API or App Store Server Notifications V2, the signed transaction and renewal info payloads gained equivalents to the client-side fields. A single billing period of a commitment plan decodes to something like this:
{
"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
}
}
The commitmentInfo block tells you where a given billing period sits in the overall commitment, which is handy for reconciling monthly renewal notifications against the full year. The signed renewal info carries similar fields, but only while the subscription is inside a commitment, and they reflect the customer's preferences for what happens after it completes. Apple's guide on managing the life cycle of monthly subscriptions with a 12-month commitment covers the full set of lifecycle events.
Testing in Xcode
You can test all of this locally without sandbox. Open your StoreKit configuration file in Xcode 26.5 or later, select a one-year auto-renewable subscription, and use the new Billing Plan picker to add a monthly with a 12-month commitment plan. That gives you fields to configure the monthly pricing, and just like App Store Connect you can attach offers per billing plan. Run your purchase flow through the transaction manager and confirm commitmentInfo shows up correctly in the Transaction inspector.
A Reworked Offer Code Redemption API
Offer codes let you hand out free or discounted access to consumables, non-consumables, and both kinds of subscriptions for a set duration. The redemption sheet you present from inside your app got a meaningful upgrade. It now behaves like a purchase: when redemption completes you get a verificationResult back, and the API accepts a set of RedeemOption values to configure the flow.
struct OfferCodeRedemption: View {
@State private 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, give the customer access
// to the content, and then finish the transaction
}
case .failure(let error):
// Handle the redemption error
print("Redemption failed: \(error)")
}
}
}
}
On success you receive a transaction object you can verify and act on, and on failure you get an error describing what went wrong, which is a big improvement over the old fire-and-forget sheet. UIKit gets the same treatment through presentOfferCodeRedeemSheet. Starting in Xcode 27, you can test redeeming offer codes locally for every applicable product type.
Bundles and Suites
Xcode 27 also introduces the API for two new ways to package subscriptions. A Bundle is a group of subscriptions that customers can still buy individually, but that you also sell together in a single purchase at a better price than buying each one separately. A Suite is a group of subscriptions that only exist inside the Suite, can't be purchased on their own, and typically provide service across a related set of apps.
You can start experimenting with the API in Xcode 27 today. Apple has said more details on the program are coming later in 2026, so for now this is something to prototype against rather than ship.
A Unified App Review Submission Flow
The last change is on the App Store Connect side. In-App Purchase products can now be grouped as review items into a single App Review submission, alongside other item types like in-app events, custom product pages, and product page optimizations. Instead of submitting each product in isolation, you select the ones you want reviewed together, add them to an in-draft submission, and track the status of everything from one centralized view.
This extends to automation too. The reviewSubmissions collection in the App Store Connect API now supports In-App Purchase, subscription, and subscription group resources through a single interface. The older per-resource submission endpoints are being deprecated in favor of reviewSubmissions and reviewSubmissionItems, so if you've built tooling around the old ones, it's worth starting that migration now rather than waiting.
Sample Project
Want to see this code in action? Check out the complete sample project on GitHub:
The repository includes a working Xcode project with all the examples from this article, plus unit tests you can run to verify the behavior.
Wrapping Up
The commitment billing plan is the change most likely to move the needle, since giving customers a lower monthly entry point to an annual plan tends to widen the funnel without hurting retention. The offer code redemption rework is a smaller but genuinely nicer API to use, and the unified submission flow quietly removes a lot of busywork. Everything here is testable in Xcode 27 and sandbox today, so you can wire up the new billing plan type and offer code result handling before your next submission. If you're new to StoreKit 2, the in-app purchases and subscriptions guide is a good place to start before layering these on top.
// Continue_Learning
StoreKit 2 for In-App Purchases and Subscriptions
A practical guide to implementing in-app purchases and subscriptions with StoreKit 2, covering products, transactions, subscription status, and SwiftUI integration.
Reading Your App's Age Rating with StoreKit's ageRatingCode
Learn how to use AppStore.ageRatingCode to read your app's current age rating and react to rating changes for parental consent compliance.
App Tracking Transparency in SwiftUI
A practical guide to App Tracking Transparency in iOS, covering the Info.plist usage description, the ATTrackingManager API, authorization statuses, and when to actually prompt the user from SwiftUI.
// Stay Updated
Get notified when I publish new tutorials on Swift, SwiftUI, and iOS development. No spam, unsubscribe anytime.