---
name: ios-storekit2-pro
description: "In-app purchases, subscriptions, server-side receipt validation, restore flow — StoreKit 2 done correctly. Scaffolds StoreKit 2 IAP + subscriptions with proper transaction listeners, server-side notifications, and the restore-purchases flow Apple actually accepts in review."
license: MIT
---

# StoreKit 2 IAP & Subscriptions

A scaffolding skill for shipping in-app purchases and auto-renewable subscriptions with Apple's modern, async/await StoreKit 2 framework. It generates the parts developers most often get wrong: the detached transaction listener, `Transaction.currentEntitlements` checks, the restore flow, and the App Store Server Notifications V2 endpoint that keeps your backend in sync. Built for iOS engineers adding monetization who want a structure that survives App Review.

## When to use it

- You're adding a paid tier, consumable credits, or a subscription and starting from a blank `StoreKit` import.
- You're migrating off the legacy `SKPaymentQueue` / `SKProduct` APIs and want the `Product` / `Transaction` equivalents.
- App Review rejected you for a missing or broken "Restore Purchases" button.
- You need server-side validation but don't want to hand-roll JWS verification of signed transactions.

## What it does

The skill scaffolds a typed product catalog and a purchase manager built on real StoreKit 2 APIs:

- `Product.products(for:)` to load products from your IDs, and `product.purchase()` returning a `Product.PurchaseResult`.
- `VerificationResult<Transaction>` handling — it always checks `.verified` vs `.unverified` rather than trusting the payload, then calls `transaction.finish()`.
- A long-lived listener on `Transaction.updates` started at launch (in a `Task` that lives beyond the view) so you catch Ask-to-Buy approvals, renewals, and refunds.
- Entitlement resolution via `Transaction.currentEntitlements` and `Product.SubscriptionInfo.Status` for grace-period and billing-retry states.
- `AppStore.sync()` wired to the restore button (the call Apple expects, not a re-purchase).
- A server stub that verifies `signedTransactionInfo` JWS and parses App Store Server Notifications V2 (`DID_RENEW`, `EXPIRED`, `REFUND`, `GRACE_PERIOD_EXPIRED`).

## Usage

```
> scaffold storekit2 with subscriptions group "pro" and a consumable "coins_100"
```

It emits `StoreManager.swift`, a `Products.storekit` config file for Xcode testing, and an optional `notifications/` server handler.

```swift
for await result in Transaction.updates {
    guard case .verified(let txn) = result else { continue }
    await grantEntitlement(for: txn.productID)
    await txn.finish()
}
```

## Tips & gotchas

- Start `Transaction.updates` **before** the first UI appears, otherwise you silently drop transactions completed while the app was backgrounded.
- Always call `finish()` only after you've delivered the content; an unfinished transaction will be re-delivered on next launch.
- Test renewals fast with a `.storekit` file in Xcode — sandbox renews in compressed time, but only StoreKit testing gives you instant refund/revoke simulation.
- Never gate features on `purchase()`'s return alone; treat `currentEntitlements` as the source of truth.

## FAQ

**Do I still need server-side receipt validation?** Not the old receipt blob. StoreKit 2 transactions are signed JWS you can verify with Apple's public keys; the skill's server handler does exactly this plus consumes Server Notifications V2.

**Minimum iOS version?** StoreKit 2 requires iOS 15+. The scaffold targets 15 and uses `Product.SubscriptionInfo.Status` introduced there.

**Does it handle Ask to Buy and family sharing?** Yes — both surface through `Transaction.updates`, which the generated listener handles uniformly.
