Skip to main content
The iOS WhopIAP SDK is coming soon. This documentation is a preview.
Whop in-app purchases (IAP) allow you to integrate in-app purchases and membership management directly into your iOS app.

Overview

The WhopIAP SDK allows you to add in-app purchases to your iOS app. By using Whop’s payment processing instead of Apple’s In-App Purchase system, you can avoid App Store fees (typically 15-30% commission) and benefit from Whop’s low fees (2.7% + $0.30 for card payments). See details. The SDK requires minimal setup and integrates seamlessly with your existing SwiftUI views. Here’s a minimal example to get started:
import SwiftUI
import WhopIAP

@main
struct MyApp: App {
    @State private var whop = WhopIAP.shared

    var body: some Scene {
        WindowGroup {
            ContentView()
                .environment(whop)
                .task {
                    try? await whop.configure(
                        companyId: "biz_xxxxxxxxxxxxxx",
                        productIds: ["prod_xxxxxxxxxxxxxx"],
                        accessTokenProvider: { try await fetchToken() }
                    )
                }
        }
    }
}

struct ContentView: View {
    @Environment(WhopIAP.self) var whop

    var body: some View {
        if whop.isSubscribed() {
            Text("Premium content")
        } else {
            Button("Upgrade") {
                Task {
                    try? await whop.purchase("plan_xxxxxxxxxxxxxx")
                }
            }
        }
    }
}

Backend Setup

Your backend needs to provide an endpoint that returns a Whop access token with the iap:client scope for your company.

Example: Next.js API Route

import { NextRequest } from "next/server";
import Whop from "@whop/sdk";

const whop = new Whop({
  appID: process.env.WHOP_APP_ID!,
  apiKey: process.env.WHOP_API_KEY!,
});

export async function GET(request: NextRequest) {
  const token = await whop.accessTokens.create({
    company_id: "biz_xxxxxxxxxxxxxx",
    scoped_actions: ["iap:client"],
  });

  return Response.json({ token: token.access_token });
}

Configuration

The SDK requires three parameters:
  • companyId: Your Whop company ID (starts with biz_). You can find your company ID in the URL of the Whop Dashboard.
Company ID location
  • productIds: Array of product IDs (starts with prod_). You can find your product IDs in the Products tab of the Whop Dashboard.
Product ID location
  • accessTokenProvider: A closure that fetches Whop tokens from your backend. The access token must have the iap:client scope.
try await whop.configure(
    companyId: "biz_xxxxxxxxxxxxxx",
    productIds: ["prod_xxxxxxxxxxxxxx"],
    accessTokenProvider: {
        return try await fetchWhopToken()
    }
)

Checking Membership Status

Check access to any product:

if whop.isSubscribed() {
    // Show premium content
} else {
    // Show upgrade prompt
}

Check access to a specific product:

if whop.hasAccess(to: "prod_xxxxxxxxxxxxxx") {
    // Show premium content
} else {
    // Show upgrade prompt
}
In order to check access to a product, the product ID must be included in the productIds argument when configuring the SDK.

Displaying Plans

List(whop.plans) { plan in
    VStack(alignment: .leading) {
        Text(plan.title ?? "Plan")
        Text(plan.initialPrice, format: .currency(code: plan.currency))
    }
}

Purchasing a Plan

Call purchase when the user taps a purchase button. The SDK automatically presents a checkout sheet, handles the payment flow, and dismisses the sheet when complete.
Button("Purchase") {
    Task {
        do {
            let result = try await whop.purchase("plan_xxxxxxxxxxxxxx")
            // Purchase successful, user now has access
        } catch WhopIAPError.cancelled {
            // User dismissed the checkout
        } catch {
            // Handle other errors
        }
    }
}
The purchase method:
  1. Presents a checkout sheet with the Whop payment flow
  2. Waits for the user to complete or cancel the purchase
  3. Automatically dismisses the sheet
  4. Returns the result or throws an error

User Login/Logout

User IDs should be provided by your app, and they should not change. Memberships belonging to this user will be available across devices. Memberships can be purchased even when a user is not logged in. When the user does log in, the SDK automatically:
  • Claims any unclaimed memberships associated with the device
  • Reloads memberships for the logged-in user
Views are automatically updated when the user logs in or out.

Log in a user

try await whop.logIn(appUserId: "user_xxxxxxxxxxxxxx")

Log out a user

whop.logOut()

Get the current user’s ID

let appUserId = whop.appUserId

Device ID Management

The SDK automatically manages device IDs using the iOS Keychain. Each device gets a unique ID that persists across app launches. This allows purchases to be tracked even when users aren’t logged in. You can access the device ID using whop.deviceId.
let deviceId = whop.deviceId

Error Handling

do {
    let result = try await whop.purchase("plan_xxxxxxxxxxxxxx")
} catch WhopIAPError.cancelled {
    // User dismissed the checkout sheet
} catch WhopIAPError.tokenUnavailable {
    // Access token is unavailable, check your token provider
} catch WhopIAPError.paymentFailed(let message) {
    // Payment failed, show error to user
} catch {
    // Handle other errors
}

Complete Reference

class WhopIAP

Allows you to manage in-app purchases in your iOS app. An @Observable class that can be used with SwiftUI’s environment system or accessed via the shared singleton instance.

static var shared

The shared singleton instance of the SDK.
static var shared: WhopIAP

func configure(companyId:productIds:accessTokenProvider:)

Configures and initializes the SDK. Call this once at app startup.
func configure(
    companyId: String,
    productIds: [String],
    accessTokenProvider: WhopTokenProvider
) async throws
Parameters:
  • companyId: Your Whop company ID (starts with biz_)
  • productIds: Array of product IDs to manage (starts with prod_)
  • accessTokenProvider: Closure that fetches Whop access tokens from your backend
Throws: WhopIAPError.tokenUnavailable if the access token is unavailable

Properties

var isInitialized

Indicates whether the SDK has finished initializing.
var isInitialized: Bool { get }

var deviceId

The unique device identifier managed by the SDK.
var deviceId: String { get }

var appUserId

The current logged-in user ID, or nil if no user is logged in.
var appUserId: String? { get }

var plans

Array of available subscription plans.
var plans: [Plan] { get }

var memberships

Array of active memberships for the current user or device.
var memberships: [Membership] { get }

Methods

func isSubscribed()

Checks if the user has an active subscription to any of the configured products.
func isSubscribed() -> Bool
Returns: true if the user has at least one active membership, false otherwise

func hasAccess(to:)

Checks if the user has access to a specific product.
func hasAccess(to productId: String) -> Bool
Parameters:
  • productId: The product ID to check (starts with prod_)
Returns: true if the user has an active membership for the product, false otherwise

func purchase(_:)

Initiates a purchase flow for a plan. Presents a checkout sheet, handles the payment, and returns when complete.
func purchase(_ planId: String) async throws -> PurchaseResult
Parameters:
  • planId: The plan ID to purchase (starts with plan_)
Returns: PurchaseResult containing the receipt ID and membership information Throws:
  • WhopIAPError.cancelled if the user dismisses the checkout
  • WhopIAPError.tokenUnavailable if the access token is unavailable
  • WhopIAPError.paymentFailed if the payment fails

func logIn(appUserId:)

Logs in a user and claims any unclaimed memberships associated with the device.
func logIn(appUserId: String) async throws
Parameters:
  • appUserId: Your app’s user ID (should not change for the same user)
Throws: WhopIAPError.tokenUnavailable if the access token is unavailable

func logOut()

Logs out the current user.
func logOut()

Types

struct PurchaseResult

The result of a successful purchase.
struct PurchaseResult {
    let receiptId: String
    let membership: Membership
}

enum WhopIAPError

Errors thrown by the SDK when operations fail.
enum WhopIAPError: Error {
    case cancelled
    case tokenUnavailable
    case paymentFailed(String)
}
Cases:
  • cancelled: The user dismissed the checkout sheet without completing the purchase
  • tokenUnavailable: The access token is unavailable. Ensure your token provider is working correctly.
  • paymentFailed: The payment failed. The associated string contains the error message.

Requirements

  • iOS 17.0+
  • Xcode 15.0+
  • Swift 5.9+