iOS 27 enables developers to sell auto-renewable subscriptions to multiple people at once via in-app group purchases or volume purchasing through Apple Business/School Manager. Purchasers buy a set number of seats and share an invite link; StoreKit 2 handles the full seat-assignment lifecycle.
• Unlocks B2B and team-plan revenue without building a custom backend — Apple's seat management handles invites, assignment, and cancellations by default
• Volume pricing lets you configure up to 5 tiered price bands to incentivize bulk purchases and increase average order value
• Organizations can distribute seats through MDM the same way they distribute apps, making enterprise adoption nearly frictionless
Demonstrates how to initiate a multi-seat group purchase using StoreKit 2 by passing a quantity into the purchase options, then handling the resulting transaction to grant access to the purchaser.
import SwiftUI
import StoreKit
struct TeamSubscriptionView: View {
let productID = "com.example.app.pro.monthly"
@State private var product: Product?
@State private var seatCount: Int = 5
@State private var purchaseStatus: String = "Ready"
@State private var isPurchasing = false
var body: some View {
VStack(spacing: 24) {
Text("Team Plan")
.font(.largeTitle.bold())
if let product {
VStack(spacing: 8) {
Text(product.displayName)
.font(.headline)
Text("\(product.displayPrice) / seat / month")
.foregroundStyle(.secondary)
}
Stepper("Seats: \(seatCount)", value: $seatCount, in: 2...100)
.padding(.horizontal)
Text("Estimated total: \(estimatedTotal(product: product))")
.font(.subheadline)
.foregroundStyle(.secondary)
Button {
Task { await purchaseGroupSubscription(product: product) }
} label: {
Label("Buy \(seatCount) Seats", systemImage: "person.3.fill")
.frame(maxWidth: .infinity)
}
.buttonStyle(.borderedProminent)
.disabled(isPurchasing)
.padding(.horizontal)
} else {
ProgressView("Loading subscription…")
}
Text(purchaseStatus)
.foregroundStyle(.secondary)
.font(.footnote)
}
.padding()
.task { await loadProduct() }
}
private func loadProduct() async {
do {
let products = try await Product.products(for: [productID])
product = products.first
} catch {
purchaseStatus = "Failed to load: \(error.localizedDescription)"
}
}
private func purchaseGroupSubscription(product: Product) async {
isPurchasing = true
defer { isPurchasing = false }
do {
// Pass quantity to request multiple seats in a single group purchase
let result = try await product.purchase(
options: [.quantity(seatCount)]
)
switch result {
case .success(let verification):
let transaction = try verification.payloadValue
// transaction.quantity reflects the purchased seat count
purchaseStatus = "\(transaction.quantity) seat(s) purchased! Share invite link with your team."
await transaction.finish()
case .pending:
purchaseStatus = "Purchase pending approval."
case .userCancelled:
purchaseStatus = "Purchase cancelled."
@unknown default:
purchaseStatus = "Unknown result."
}
} catch {
purchaseStatus = "Purchase failed: \(error.localizedDescription)"
}
}
private func estimatedTotal(product: Product) -> String {
// Display raw price * seats as a rough preview; App Store applies volume pricing server-side
let total = product.price * Decimal(seatCount)
return product.priceFormatStyle.format(total)
}
}
#Preview {
TeamSubscriptionView()
}Retention Messaging lets developers configure custom messages, images, and promotional offers that appear on the App Store cancellation page when a subscriber is about to cancel. It supports both static configuration via App Store Connect and real-time server-driven responses through the Retention Messaging API.
iOS 27 introduces a Product Page Header on the App Store — a dedicated visual area above screenshots where developers can place custom marketing images or videos. A new Asset Library in App Store Connect centralizes all creative assets and allows real-time updates to Product Page Headers and Search Result visuals without a new app submission.
StoreKit 2 is required; SKPayment/StoreKit 1 subscriptions are not supported. If Family Sharing is enabled on a subscription, group/org selling is opted-out by default and must be explicitly enabled in App Store Connect. Volume pricing and availability settings are configured entirely in App Store Connect, not in code.
None — available on all devices that support StoreKit 2