2026 App ServicesApp Store, Distribution & Marketing
WWDC26 · 13 min · App Services / App Store, Distribution & Marketing
What’s new in Apple In-App Purchase
Discover how monthly subscriptions with a 12-month commitment give people a more affordable option to pay for your subscription and secure a longer-term commitment. Explore how to configure and test this new payment option using App Store Connect, StoreKit APIs, Xcode testing, and more. Plus, learn about improvements to offer code redemption APIs, and enhancements to the App Review submission experience.
Watch at developer.apple.com ↗Chapters
- 0:01 — Introduction
- 0:51 — Overview of monthly subscriptions with a 12-month commitment
- 1:42 — Set up in App Store Connect
- 2:28 — Merchandise with StoreKit
- 6:55 — Monitor subscriptions with App Store Server APIs
- 8:50 — Bundles and Suites
- 9:26 — Offer code redemption
- 10:35 — Enhanced submission experience
- 12:38 — Next steps
Code shown on screen · 6 snippets
Merchandise pricing terms with StoreKit views
// Merchandise pricing terms with StoreKit views
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
}
}
}
} Get subscription pricing terms and make a purchase
// Get subscription pricing terms and make a purchase
import StoreKit
var product: Product?
// Fetch and assign product
// Get the monthly billing plan's pricing terms for merchandising
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
} Sheet to manage subscriptions by subscriptionGroupID
// Sheet to manage subscriptions by subscriptionGroupID
import SwiftUI
import StoreKit
struct ManageSubscriptionsButton: View {
let subscriptionGroupID: String
var presentingManageSubscriptionsSheet: Bool = false
var body: some View {
Button("Manage Subscriptions") {
presentingManageSubscriptionsSheet = true
}
.manageSubscriptionsSheet(
isPresented: $presentingManageSubscriptionsSheet,
subscriptionGroupID: subscriptionGroupID
)
}
} JWSTransaction (decoded) for a monthly subscription with a 12-month commitment
// JWSTransaction (decoded) for a monthly subscription with a 12-month commitment
{
// …
"expiresDate": 1783503660000, // for this billing period
"price": 10990, // for this billing period
"productId": "plus.pro.annual",
"purchaseDate": 1780911660000,
"type": "Auto-Renewable Subscription",
"billingPlanType": "MONTHLY",
"commitmentInfo": {
"billingPeriodNumber": 1,
"totalBillingPeriods": 12,
"commitmentExpiresDate": 1812447660000,
"commitmentPrice": 131880,
}
} JWSRenewalInfo (decoded) for a monthly subscription with a 12-month commitment
// JWSRenewalInfo (decoded) for a monthly subscription with a 12-month commitment
{
// …
"renewalBillingPlanType": "MONTHLY",
"commitmentInfo": {
"commitmentAutoRenewProductId": “plus.standard.annual”,
"commitmentAutoRenewStatus": 0,
"commitmentRenewalDate": 1812447660000,
"commitmentRenewalPrice": 10990,
"commitmentRenewalBillingPlanType": "BILLED_UPFRONT"
}
} Sheet to redeem an offer code
// Sheet to redeem an offer code
struct OfferCodeRedemption: View {
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
}
}
}
} Resources
Related sessions
-
9 min -
37 min -
24 min -
33 min -
15 min