Built on StoreKit 2 and requires iOS 15+. Purchases are validated server-side, so entitlements stay trustworthy even if a device is compromised.
iOS SDK
Add in-app purchases and paywalls to your iOS app with Swift and StoreKit 2.
The CashSDK iOS SDK wraps StoreKit 2 in a small, async/await-first API.
Fetch offerings, run purchases, and read entitlements without touching
SKProduct, transactions, or receipt plumbing directly.
Install#
In Xcode, choose File → Add Packages… and enter the repository URL:
https://github.com/cashsdk/cashsdk-ios
Or add it to your Package.swift:
dependencies: [
.package(url: "https://github.com/cashsdk/cashsdk-ios", from: "1.0.0")
]
Add the pod to your Podfile and run pod install:
pod 'CashSDK'
Configure#
Initialize CashSDK once, as early as possible — typically in your App init or
AppDelegate. Use your publishable key.
import CashSDK
@main
struct MyApp: App {
init() {
CashSDK.configure(apiKey: "pk_live_...")
}
var body: some Scene {
WindowGroup { RootView() }
}
}
Only ship publishable keys (pk_live_… / pk_test_…) in your app. Secret keys
(csk_sk_…) belong on your backend.
Fetch offerings#
An offering is the set of packages you show on a paywall. Fetch the current
offering and read its packages, such as monthly and annual.
let offering = try await CashSDK.offerings()
let monthly = offering.monthly
let annual = offering.annual
Purchase#
Pass a package to purchase. CashSDK drives the StoreKit 2 flow, validates the
receipt, and returns the customer's updated entitlements.
let result = try await CashSDK.purchase(offering.monthly)
if result.entitlements["pro"]?.isActive == true {
unlockPro()
}
Check entitlements#
Read entitlements from any purchase or restore result to gate access.
if result.entitlements["pro"]?.isActive == true {
// Show premium content
} else {
// Show the paywall
}
Restore purchases#
Give customers a way to recover access on a new device or after a reinstall.
let result = try await CashSDK.restorePurchases()
if result.entitlements["pro"]?.isActive == true {
unlockPro()
}
Identify the customer#
Link the SDK to your own user ID so entitlements follow the customer across
devices and platforms. Call identify after the user signs in.
CashSDK.identify("u_812")
SwiftUI paywall#
A minimal paywall driven by offerings. Present it whenever the pro entitlement
is inactive.
import SwiftUI
import CashSDK
struct PaywallView: View {
@State private var offering: Offering?
@State private var isPurchasing = false
var body: some View {
VStack(spacing: 16) {
Text("Unlock Pro").font(.title).bold()
if let offering {
ForEach(offering.packages) { package in
Button {
Task { await buy(package) }
} label: {
HStack {
Text(package.title)
Spacer()
Text(package.localizedPrice)
}
}
.disabled(isPurchasing)
}
} else {
ProgressView()
}
Button("Restore purchases") {
Task { try? await CashSDK.restorePurchases() }
}
.font(.footnote)
}
.padding()
.task { offering = try? await CashSDK.offerings() }
}
func buy(_ package: Package) async {
isPurchasing = true
defer { isPurchasing = false }
guard let result = try? await CashSDK.purchase(package) else { return }
if result.entitlements["pro"]?.isActive == true {
// Dismiss and unlock
}
}
}
Prefer to design paywalls remotely and ship changes without an App Store review? See Paywalls.