Built on StoreKit 2, so this rail covers iOS 15+, iPadOS 15+, and macOS 14+ (Mac Catalyst builds follow the iOS deployment target). Older StoreKit 1 receipts are not required. CashSDK works directly with the signed transactions StoreKit 2 issues.
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#
The iOS SDK presents the offering and drives Apple's native
purchase sheet. StoreKit returns a signed Transaction.
The SDK forwards the transaction to CashSDK, which validates Apple's signature with the App Store Server API before granting anything.
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.
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.
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.
Also set your Bundle ID and, for App Store Server Notifications, your
Apple App ID (the numeric 1234567890 from the App Information page).
The dashboard's setup checklist confirms each field is valid before you go
live.
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.
The MCP server can help with integration after you upload
the credentials. You must create the Apple keys and set notification URLs in
App Store Connect yourself. With an In-App Purchase key, the
request_apple_test_notification tool even asks Apple to send a test
notification so you can confirm the connection before shipping.
Create your products#
Create your in-app purchases and subscriptions in App Store Connect, then map them to CashSDK.
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.
In CashSDK, create a product with the same
identifier and attach the entitlement it unlocks
(for example pro). You can sync the catalog automatically:
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.
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#
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.
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.
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.