Apple App Store

Connect App Store Connect so StoreKit 2 purchases and subscriptions are verified server-side and resolve to CashSDK entitlements.

The App Store (through StoreKit 2) is the billing rail for in-app purchases and subscriptions on iOS, iPadOS, and macOS. CashSDK verifies every StoreKit transaction and every App Store Server Notification against Apple on your server, so an entitlement is only ever granted from a signed, authentic purchase and never trusted on the device alone.

How it works#

1
StoreKit runs the purchase

The iOS SDK presents the offering and drives Apple's native purchase sheet. StoreKit returns a signed Transaction.

2
CashSDK verifies it server-side

The SDK forwards the transaction to CashSDK, which validates Apple's signature with the App Store Server API before granting anything.

3
Notifications keep it current

Apple sends App Store Server Notifications V2 to CashSDK for every renewal, refund, grace period, and cancellation, so entitlements stay accurate for the whole subscription lifecycle, even when your app is closed.

Prerequisites#

  • A paid Apple Developer Program membership.
  • An app record in App Store Connect with a bundle ID.
  • The Account Holder or an Admin role, so you can create an App Store Connect API key and edit agreements.
  • A signed Paid Applications Agreement (App Store Connect → Business). In-app purchases will not load until it is active.

Connect App Store Connect#

Use Quickstart → iOS for the one-input-at-a-time illustrated walkthrough.

CashSDK talks to Apple with an App Store Connect API key, a .p8 private key plus its issuer ID and key ID. This lets CashSDK verify transactions and read the subscription status of your customers.

1
Create a team App Store Connect API key

In App Store Connect, go to Users and Access → Integrations → App Store Connect API → Team Keys and create a key with App Manager access. Download the AuthKey_XXXXXXXXXX.p8 file now. Apple only lets you download it once.

2
Add it to CashSDK

In your CashSDK dashboard, open Quickstart → iOS (or Store Connect). Select the .p8 file, then enter your Issuer ID and Key ID on separate pages. Next on Validate your App Store connection uploads it. It is stored encrypted at rest and is never exposed to your app.

3
Point App Store Server Notifications at CashSDK

Copy the notification URL from Quickstart → iOS → Set the Sandbox notification URL (or Store Connect) in your dashboard. In App Store Connect, open your app → App Information → App Store Server Notifications and paste it into both the Production Server URL and the Sandbox Server URL, selecting Version 2 notifications.

For one-click notification tests, an Account Holder or Admin can separately create an In-App Purchase key under Users and Access → Integrations → In-App Purchase. Upload its SubscriptionKey_XXXXXXXXXX.p8 and its own Key ID in the optional Quickstart substeps. This is a separate key type, not an “In-App Purchase” role on the team API key. Without it, notification checks can pass when real signed store notifications arrive.

Create your products#

Create your in-app purchases and subscriptions in App Store Connect, then map them to CashSDK.

1
Create products in App Store Connect

Under Monetization → Subscriptions (or In-App Purchases), create each product and give it a Product ID, for example pro_monthly. Fill in the price and localizations, and submit them for review with your next build.

2
Map them to entitlements in CashSDK

In CashSDK, create a product with the same identifier and attach the entitlement it unlocks (for example pro). You can sync the catalog automatically:

bash
sync_catalog_from_app_store(store="app-store", dryRun=true)

Run it without dryRun to import your App Store products as CashSDK products in one step.

Integrate the SDK#

Once the catalog is mapped, the iOS SDK does the rest: purchase, verification, and entitlements, with no App Store plumbing in your app code.

swift
import CashSDK

CashSDK.configure(publishableKey: "csk_pk_…")

switch try await CashSDK.shared.purchase("pro_monthly") {
case .success(let entitlements):
  if entitlements.isActive("pro") { unlockPro() }
case .pending, .userCancelled, .localStoreKit:
  break
}

Under the hood the SDK verifies the StoreKit transaction server-side before the entitlements in that result are returned. See Receipt validation for what happens on the server.

Mac App Store#

The same App Store Connect connection covers your Mac app. What else you set up depends on how the Mac app is listed in App Store Connect:

  • Universal purchase (the Mac build shares the iOS bundle ID and record): tick macOS as a platform in the dashboard. Nothing else changes.
  • A separate Mac record (a native Mac app with its own bundle ID, or a Mac Catalyst build with Xcode's default maccatalyst.<iOS bundle ID>): enter the Mac bundle ID and the Mac Apple App ID, paste the same notification URL into the Mac record, and map the Mac products, which sync under the store Mac App Store, to the same entitlements. Keep the API key you already uploaded. It covers both records.

Production purchases from a separate Mac record need the Mac Apple App ID. See macOS / Catalyst for the step-by-step setup.

Test in the sandbox#

1
Create a sandbox tester

In App Store Connect, go to Users and Access → Sandbox → Testers and add a sandbox Apple ID. On the device, sign in under Settings → Developer → Sandbox Apple Account.

2
Run a purchase from a development build

Configure the SDK with your csk_pk_… key, the same key you ship. A build run from Xcode or TestFlight transacts against Apple's sandbox automatically, so purchases complete without a real charge, and renewals run on Apple's accelerated sandbox clock (a month renews in minutes), the fastest way to watch the whole lifecycle.

3
Confirm entitlements and notifications

Verify the purchase grants pro, then check Events in your dashboard for the incoming purchase.completed and, on renewal, subscription.renewed events driven by the sandbox App Store Server Notifications.

Sandbox and production notifications use separate URLs in App Store Connect. Set both. CashSDK records the true environment on each transaction, so sandbox purchases never mix into your production revenue. See Testing.

Go live#

Before you ship:

  • The Paid Applications Agreement is active.
  • Products are Approved (or submitted with your build).
  • The Production App Store Server Notification URL is set to V2.
  • The app's numeric App Store App ID (appleAppId) is set: Apple rejects every Production purchase without it.
  • With a separate Mac App Store record: the Mac Apple App ID is set, and the Mac record's Production notification URL is set to V2.

The dashboard's setup checklist (get_setup_checklist) turns green when each of these is satisfied.

Next steps#