The shared Checkout instance. Use this singleton to configure the SDK and manage purchases.
Report incorrect code
Copy
Ask AI
static let shared: Checkout
Example:
Report incorrect code
Copy
Ask AI
import WhopCheckout// Configure at app startuptry await Checkout.shared.configure(...)// Pass through SwiftUI environmentContentView() .environment(Checkout.shared)// Access in views@Environment(Checkout.self) var checkout
Returns: The refreshed plans with current pricing.Throws:WhopCheckoutError if the refresh fails.Call this to update pricing or plan availability after initialization. The plans property will also be updated with the latest data.Example:
Report incorrect code
Copy
Ask AI
// Refresh and use the return valuelet plans = try await Checkout.shared.refreshPlans()// Or just refresh (plans property updates automatically)try await Checkout.shared.refreshPlans()
Override the payment method. Defaults based on region.
Returns:CheckoutPurchaseResult containing the receipt ID and membership informationThrows:
WhopCheckoutError.cancelled if the user dismisses the checkout
WhopCheckoutError.notConfigured if the SDK is not configured
WhopCheckoutError.paymentFailed(String) if the payment fails
Example:
Report incorrect code
Copy
Ask AI
do { // Use default payment method (Whop in US, StoreKit elsewhere) let result = try await checkout.purchase("plan_xxxxxxxxxxxxxx") print("Success! Receipt: \(result.receiptId)")} catch WhopCheckoutError.cancelled { // User cancelled} catch { // Handle error}// Or explicitly choose a payment methodlet result = try await checkout.purchase("plan_xxx", method: .apple)
struct CheckoutPurchaseResult { let receiptId: String let membership: CheckoutMembership?}
Property
Type
Description
receiptId
String
The unique receipt ID for this purchase
membership
CheckoutMembership?
The membership created by this purchase
When is membership nil?
The membership property depends on the payment method used:
Payment Method
Region
membership value
Whop web checkout
US
Populated immediately
StoreKit
Outside US
nil initially
Why StoreKit purchases return nil:
StoreKit transactions are processed asynchronously by Apple. When the purchase completes, the SDK may not yet have the Whop membership synced. The SDK tracks StoreKit entitlements separately, so checkout.isSubscribed will still return true.How to handle both cases:
Report incorrect code
Copy
Ask AI
do { let result = try await checkout.purchase("plan_xxx") // Always check isSubscribed - works for both payment methods if checkout.isSubscribed { // Grant access } // Optionally use membership details if available if let membership = result.membership { print("Membership ID: \(membership.id)") print("Expires: \(membership.expiresAt?.formatted() ?? "N/A")") }} catch WhopCheckoutError.cancelled { // User cancelled}
Key point: Don’t rely on membership being non-nil to grant access. Always use checkout.isSubscribed or checkout.hasAccess(to:) to check subscription status.
A mapping between a Whop plan and an Apple StoreKit product, used during SDK configuration. This tells the SDK which Apple product to use for StoreKit purchases outside the US.
PlanMapping vs CheckoutPlan:PlanMapping is for SDK configuration (mapping IDs). CheckoutPlan is what you display in your UI (has pricing, titles, etc.). You create PlanMapping objects in configure(), then access CheckoutPlan objects via checkout.plans.
Report incorrect code
Copy
Ask AI
struct PlanMapping: Sendable { let whopId: String let appleId: String init(whopId: String, appleId: String)}
Property
Type
Description
whopId
String
The Whop plan ID (e.g., plan_xxx)
appleId
String
The Apple product ID from App Store Connect (e.g., com.yourapp.monthly)
Example:
Report incorrect code
Copy
Ask AI
// Used in configure() - just maps IDstry await Checkout.shared.configure( companyId: "biz_xxx", apiKey: "your_key", planMappings: [ .init(whopId: "plan_monthly", appleId: "com.app.monthly"), .init(whopId: "plan_yearly", appleId: "com.app.yearly") ])// After configuration, use checkout.plans (CheckoutPlan array) for UIForEach(checkout.plans) { plan in // These are CheckoutPlan objects Text(plan.title ?? "Plan") Text(plan.whopDisplayPrice)}
Your Whop plans and Apple products should have matching pricing and billing periods. See Setup → Plan Mappings for details.
A subscription plan available for purchase, accessed via checkout.plans. Use this for displaying plan information in your UI and for making purchases.
CheckoutPlan vs Plan:CheckoutPlan contains full plan details (pricing, titles, trial info) for your UI. Plan is just an ID mapping used during SDK configuration. You never create CheckoutPlan objects—they come from checkout.plans after configuration.
Report incorrect code
Copy
Ask AI
struct CheckoutPlan: Identifiable { let id: String let productId: String? let title: String? let description: String? let planType: PlanType let billingPeriodDays: Int? let baseCurrency: String let initialPrice: Double let renewalPrice: Double let trialPeriodDays: Int? var renewalPeriod: RenewalPeriod? { get } var whopDisplayPrice: String { get } var appleDisplayPrice: String? { get }}enum PlanType: String { case oneTime = "one_time" case renewal case unknown}enum RenewalPeriod: Equatable { case weekly // 7 days case monthly // 30 days case quarterly // 90 days case semiAnnual // 180 days case yearly // 365 days case custom(Int) // Custom period in days}
Property
Type
Description
id
String
The plan ID
productId
String?
The product this plan belongs to
title
String?
Display name of the plan
description
String?
Description text for the plan
planType
PlanType
Whether this is a one-time or recurring plan
billingPeriodDays
Int?
Number of days in billing cycle (30 = monthly, 365 = yearly)
baseCurrency
String
Currency code (e.g., “usd”)
initialPrice
Double
Initial price of the plan
renewalPrice
Double
Price for renewals
trialPeriodDays
Int?
Number of days in trial period
renewalPeriod
RenewalPeriod?
Computed renewal period (.monthly, .yearly, etc.)
whopDisplayPrice
String
Formatted Whop price (e.g., “$9.99”)
appleDisplayPrice
String?
Localized StoreKit price, if a plan mapping exists
struct CheckoutMembership: Identifiable { let id: String let productId: String let planId: String let status: Status let isClaimed: Bool let createdAt: Date let expiresAt: Date? let renewalPeriodEnd: Date? let cancelAtPeriodEnd: Bool let receiptId: String? var isActive: Bool { get }}enum Status: String { case active case canceled case canceling case completed case drafted case expired case pastDue = "past_due" case trialing case unresolved case unknown}
Property
Type
Description
id
String
The membership ID
productId
String
The product this membership belongs to
planId
String
The plan this membership is for
status
Status
Current status of the membership
isActive
Bool
Whether the membership grants access (true for active, trialing, canceling, pastDue, completed)