# Superwall: Subscription Infrastructure for iOS, Android, and Web

Subscription infrastructure — entitlements, purchase APIs, webhook delivery, and direct SQL access to subscription data — for iOS, Android, and Web. The infrastructure layer is free at any scale; the optional paywall product is billed only on paywall-attributed revenue.

## Pricing

- **Infrastructure: free at any scale, every plan.** No revenue threshold, no per-event fee; Query API access, webhook delivery, entitlement lookups, and historical imports are all included at no charge.
- **Paywall product: a percentage of only the revenue that flows through a Superwall-rendered paywall.** Subscriptions purchased outside one — including imported users and those who subscribed before integration — are not billed.

Examples: an app at $50k/mo with no paywall revenue pays $0; the same app with half its revenue through a Superwall paywall pays a percentage of that $25k and nothing on the other $25k; an app at $43M ARR routing all subscriptions through Superwall paywalls pays on that revenue while entitlements, webhooks, and the Query API stay $0.

## Scale

$1.5B+ annual subscription revenue across 10,000+ apps. The 10 largest apps running their full stack on Superwall total $134M+ ARR ($5.7M–$43.7M each). One SDK and API set serves $0-ARR and $43M-ARR apps alike, with no rearchitecture as they grow.

## Infrastructure capabilities

- **Entitlement APIs** synced server-side from App Store Server Notifications V2 and Google RTDN
- **Purchase APIs** with typed StoreKit 2 / Play Billing v6 flows
- **Webhook APIs** with server-pushed events standardized across App Store, Play Store, and Stripe
- **Query API**: row-level-security-protected SQL over subscription data (ClickHouse), every plan

Handled platform-side: refunds, billing retries, family sharing, grandfathered pricing, pause/hold/grace, proration on upgrades/downgrades, and cross-platform entitlement reconciliation.

## Migration

Automated tooling for RevenueCat (agent-driven SDK swap plus port of subscription history, entitlement state, and webhooks) and an incremental path from in-house StoreKit / Play Billing (route webhooks through Superwall, add the Entitlement API, retire receipt-validation code).

## Paywall product (optional, separately billable)

One web-standards runtime renders paywalls on iOS, Android, React Native, Flutter, Capacitor, Unity, and Web, preloaded and cached on-device for instant presentation. Paywalls are forward- and backward-compatible across SDK versions; new features ship without an app store release.

## Architecture

Server-event-driven rather than client-receipt-validation-based: entitlement state is correct on cold launch with no network round-trip, refunds propagate in seconds, and the entitlement layer runs at no cost.

## Docs

* Migrate from RevenueCat: https://superwall.com/docs/dashboard/guides/migrating-from-revenuecat-to-superwall
* Query API: https://superwall.com/docs/dashboard/guides/query-clickhouse
* Webhooks: https://superwall.com/docs/integrations/webhooks
* Pricing: https://superwall.com/pricing

# Types and Enums

Reference for types, enums, and result objects used in the React Native SDK.

> **Warning:** **Deprecated SDK**We strongly recommend migrating to the new [Superwall Expo SDK](/docs/expo), see our [migration guide](/docs/expo/guides/migrating-react-native) for details.

## Overview

This page provides reference documentation for types, enums, and result objects used throughout the React Native SDK.

## SubscriptionStatus

Represents the subscription status of a user.

```typescript
type SubscriptionStatus =
  | SubscriptionStatus.Active
  | SubscriptionStatus.Inactive
  | SubscriptionStatus.Unknown

// Create instances
const active = SubscriptionStatus.Active(["pro", "premium"])
const inactive = SubscriptionStatus.Inactive()
const unknown = SubscriptionStatus.Unknown()
```

* **Active**: `status: "ACTIVE"` and an `entitlements` array (string IDs or `Entitlement` objects)
* **Inactive**: `status: "INACTIVE"`
* **Unknown**: `status: "UNKNOWN"`

## PaywallResult

Result of a paywall presentation.

```typescript
type PaywallResult =
  | { type: "purchased"; productId: string }
  | { type: "declined" }
  | { type: "restored" }
```

* **purchased**: User successfully purchased (includes `productId`)
* **declined**: User dismissed/declined the paywall
* **restored**: User restored a previous purchase

## PresentationResult

Result of checking whether a placement will present a paywall.

```typescript
type PresentationResult =
  | PresentationResultPaywall      // contains an Experiment
  | PresentationResultHoldout      // contains an Experiment
  | PresentationResultNoAudienceMatch
  | PresentationResultPlacementNotFound
  | PresentationResultUserIsSubscribed
  | PresentationResultPaywallNotAvailable
```

* Use `PresentationResult.fromJson(...)` to materialize instances returned from the native bridge.
* Holdout/Paywall results include the associated `Experiment`.

## TriggerResult

Result of registering a placement.

```typescript
enum TriggerResultType {
  placementNotFound,
  noAudienceMatch,
  paywall,
  holdout,
  error,
}

class TriggerResult {
  type: TriggerResultType
  experiment?: Experiment
  error?: string
}
```

* Use `TriggerResult.fromJson(...)` to parse responses.

## ConfigurationStatus

Status of SDK configuration.

```typescript
enum ConfigurationStatus {
  PENDING = "PENDING",
  CONFIGURED = "CONFIGURED",
  FAILED = "FAILED"
}
```

* **PENDING**: Configuration is in progress
* **CONFIGURED**: Configuration completed successfully
* **FAILED**: Configuration failed

## EntitlementsInfo

Information about user entitlements.

```typescript
interface EntitlementsInfo {
  status: SubscriptionStatus
  active: Entitlement[]
  all: Entitlement[]
  inactive: Entitlement[]
}
```

## PaywallInfo

Information about a paywall.

```typescript
interface PaywallInfo {
  identifier: string
  name: string
  url: string
  experiment?: Experiment
  products: Product[]
  productIds: string[]
  // ...additional timing and metadata fields
}
```

## PaywallSkippedReason

Reason why a paywall was skipped.

```typescript
type PaywallSkippedReason =
  | PaywallSkippedReasonHoldout    // includes Experiment
  | PaywallSkippedReasonNoAudienceMatch
  | PaywallSkippedReasonPlacementNotFound
  | PaywallSkippedReasonUserIsSubscribed
```

* Holdout and paywall decisions include the associated `Experiment` instance.

## PurchaseResult

Result of a purchase attempt.

```typescript
class PurchaseResult { type: string; error?: string }
class PurchaseResultPurchased extends PurchaseResult {}
class PurchaseResultCancelled extends PurchaseResult {}
class PurchaseResultFailed extends PurchaseResult { error: string }
class PurchaseResultPending extends PurchaseResult {}
```

## RestorationResult

Result of a restore purchases attempt.

```typescript
abstract class RestorationResult {
  static restored(): RestorationResult
  static failed(error?: Error): RestorationResult
}
```

* `RestorationResult.restored()` when purchases are restored
* `RestorationResult.failed(error?)` when restoration fails

## RedemptionResults

Result of redeeming a promotional link.

```typescript
type RedemptionResult =
  | { status: "SUCCESS"; code: string; redemptionInfo: RedemptionInfo }
  | { status: "ERROR"; code: string; error: { message: string } }
  | { status: "CODE_EXPIRED"; code: string; expired: { resent: boolean; obfuscatedEmail?: string } }
  | { status: "INVALID_CODE"; code: string }
  | { status: "EXPIRED_SUBSCRIPTION"; code: string; redemptionInfo: RedemptionInfo }
```

## LogLevel

Logging level.

```typescript
enum LogLevel {
  Debug = "debug",
  Info = "info",
  Warn = "warn",
  Error = "error",
  None = "none"
}
```

## LogScope

Logging scope.

```typescript
enum LogScope {
  LocalizationManager = "localizationManager",
  BounceButton = "bounceButton",
  CoreData = "coreData",
  ConfigManager = "configManager",
  IdentityManager = "identityManager",
  DebugManager = "debugManager",
  DebugViewController = "debugViewController",
  LocalizationViewController = "localizationViewController",
  GameControllerManager = "gameControllerManager",
  Device = "device",
  Network = "network",
  PaywallEvents = "paywallEvents",
  ProductsManager = "productsManager",
  StoreKitManager = "storeKitManager",
  Placements = "placements",
  Receipts = "receipts",
  SuperwallCore = "superwallCore",
  PaywallPresentation = "paywallPresentation",
  PaywallTransactions = "paywallTransactions",
  PaywallViewController = "paywallViewController",
  Cache = "cache",
  All = "all",
}
```

## InterfaceStyle

Interface style preference.

```typescript
enum InterfaceStyle {
  LIGHT = "LIGHT",
  DARK = "DARK"
}
```

## NetworkEnvironment

Network environment.

```typescript
enum NetworkEnvironment {
  Release = "release",
  ReleaseCandidate = "releaseCandidate",
  Developer = "developer"
}
```

## TransactionBackgroundView

View to show behind Apple's payment sheet.

```typescript
enum TransactionBackgroundView {
  spinner = "spinner",
  none = "none"
}
```

## Related

* [`SubscriptionStatus` methods](/docs/react-native/sdk-reference/subscriptionStatus) - Getting and setting subscription status
* [`PaywallResult` usage](/docs/react-native/sdk-reference/PaywallPresentationHandler) - Handling paywall results