External Purchase

Overview

External purchase allows you to redirect users to external payment systems instead of using platform-native billing (StoreKit on iOS, Google Play Billing on Android). This enables alternative payment methods and can reduce platform fees.

Platform Support

PlatformFeature NameMinimum OS VersionNative Framework
iOSExternal Purchase URLiOS 17.4+ (Notice Sheet)
iOS 18.2+ (New APIs)
StoreKit 2
AndroidAlternative Billing / Billing ProgramsAndroid 6.0+ (API 23)Google Play Billing 6.2+ (legacy), 8.2.0+ (External Content Links), 8.2.1+ (External Offers), 8.3.0+ (External Payments)

Common Requirements#

Both platforms require the following infrastructure to support external purchases:

Backend Verification System

  • Payment gateway integration
  • Purchase verification endpoint
  • Entitlement management system
  • Transaction logging and auditing

Platform-Specific Implementation#

iOS - External Purchase

iOS supports external purchase through StoreKit's External Purchase API. The notice sheet presents within the app and returns results immediately - no browser redirect required.

Basic Usage (iOS 18.2+)

iOS 18.2+ provides dedicated APIs for external purchase flow with notice sheet and link presentation:

swift
import OpenIAP

@available(iOS 18.2, *)
func handleExternalPurchaseFlow() async {
    let externalUrl = "https://your-payment-site.com/checkout"

    do {
        // Step 1: Check if notice sheet can be presented
        let canPresent = try await OpenIapModule.shared
            .canPresentExternalPurchaseNoticeIOS()

        guard canPresent else {
            print("External purchase notice sheet not available")
            return
        }

        // Step 2: Present notice sheet (Apple's info sheet)
        let noticeResult = try await OpenIapModule.shared
            .presentExternalPurchaseNoticeSheetIOS()

        if noticeResult.result == .continue {
            // Step 3: Present external purchase link
            let linkResult = try await OpenIapModule.shared
                .presentExternalPurchaseLinkIOS(externalUrl)

            if linkResult.success {
                print("User acknowledged external purchase")
                // User approved external purchase
                // Call your backend API to initiate purchase
                // await yourBackend.createPurchase(productId, userId)
            } else {
                print("External purchase link failed: \(linkResult.error ?? "")")
            }
        } else {
            print("User dismissed notice sheet")
        }
    } catch {
        print("External purchase error: \(error)")
    }
}

Requirements

  • iOS 17.4+ - Minimum version for External Purchase API
  • iOS 18.2+ - Recommended for dedicated external purchase APIs (canPresentExternalPurchaseNoticeIOS, presentExternalPurchaseNoticeSheetIOS, presentExternalPurchaseLinkIOS)
  • StoreKit 2 - Uses StoreKit 2 framework
  • Entitlement required - com.apple.developer.storekit.external-purchase entitlement must be configured in App Store Connect
  • Country code configuration - Must specify supported country codes in SKExternalPurchase array in Info.plist. Only available in EU countries and South Korea. See Apple Documentation
  • No deep linking required - Notice sheet presents within the app and returns results immediately

Configuration (iOS)

Add entitlement and country codes in Info.plist. Use lowercase ISO 3166-1 alpha-2 country codes:

1. SKExternalPurchase (Required)

Specify countries where your app supports external purchases:

xml
<key>SKExternalPurchase</key>
<array>
  <!-- South Korea -->
  <string>kr</string>

  <!-- Netherlands -->
  <string>nl</string>

  <!-- EU Countries (examples) -->
  <string>de</string>  <!-- Germany -->
  <string>fr</string>  <!-- France -->
  <string>it</string>  <!-- Italy -->
  <string>es</string>  <!-- Spain -->
  <!-- Add other EU country codes as needed -->
</array>

<!-- Entitlement required -->
<!-- com.apple.developer.storekit.external-purchase: true -->
2. SKExternalPurchaseLink (Optional - iOS 15.4+)

Provide destination URLs for each country. Required if using com.apple.developer.storekit.external-purchase-link entitlement:

xml
<key>SKExternalPurchaseLink</key>
<dict>
  <key>nl</key>
  <string>https://your-site.com/checkout</string>

  <key>de</key>
  <string>https://your-site.com/de/checkout</string>

  <key>kr</key>
  <string>https://your-site.com/kr/checkout</string>
</dict>
3. SKExternalPurchaseMultiLink (iOS 17.5+)

Provide multiple URLs (up to 5) for each country. Use this instead of SKExternalPurchaseLink for iOS 17.5+:

xml
<key>SKExternalPurchaseMultiLink</key>
<dict>
  <key>es</key>
  <array>
    <string>https://your-site.com/es1</string>
    <string>https://your-site.com/new-user-es</string>
    <string>https://your-site.com/seasonal-sale-es</string>
  </array>

  <key>fr</key>
  <array>
    <string>https://your-site.com/fr</string>
    <string>https://your-site.com/global-sale</string>
  </array>

  <key>it</key>
  <array>
    <string>https://your-site.com/global-sale</string>
  </array>
</dict>
4. SKExternalPurchaseCustomLinkRegions (iOS 18.1+)

For custom links to communicate and promote offers. Required if using com.apple.developer.storekit.external-purchase-link entitlement and ExternalPurchaseCustomLink API:

xml
<key>SKExternalPurchaseCustomLinkRegions</key>
<array>
  <string>de</string>  <!-- Germany -->
  <string>fr</string>  <!-- France -->
  <string>nl</string>  <!-- Netherlands -->
  <!-- Add other EU country codes -->
</array>
5. SKExternalPurchaseLinkStreamingRegions (iOS 18.2+)

For music streaming apps only. Required if using com.apple.developer.storekit.external-purchase-link-streaming entitlement:

xml
<key>SKExternalPurchaseLinkStreamingRegions</key>
<array>
  <string>at</string>  <!-- Austria -->
  <string>de</string>  <!-- Germany -->
  <string>fr</string>  <!-- France -->
  <string>nl</string>  <!-- Netherlands -->
  <string>is</string>  <!-- Iceland -->
  <string>no</string>  <!-- Norway -->
  <!-- Add other EU country codes -->
</array>

Common Issues (iOS)

IssueCauseSolution
Notice Sheet Not ShowingMissing entitlement or country codeAdd com.apple.developer.storekit.external-purchase entitlement and configure SKExternalPurchase array
canPresent Returns FalseDevice region not supportedCheck device is in supported country (EU, NL, KR)
FeatureNotSupported ErroriOS version too oldRequires iOS 17.4+ (notice sheet), iOS 18.2+ (new APIs)

Implementation Flow#

The complete external purchase flow involves coordination between your app, external website, and backend. The flow differs between iOS and Android:

iOS Flow (iOS 18.2+)

StepAPI / ActionDescription
1canPresentExternalPurchaseNoticeIOS()Check if device supports external purchase notice sheet
2presentExternalPurchaseNoticeSheetIOS()Show Apple's notice sheet informing user about external purchase
3User ActionUser taps "Continue" or dismisses the notice sheet
4presentExternalPurchaseLinkIOS(url)If user continued, present external purchase link (user acknowledges external purchase)
5Backend Payment ProcessingApp calls backend API to process payment with payment gateway (Stripe, PayPal, etc.) and grant entitlements
6Unlock ContentApp unlocks purchased content after backend confirmation

Complete Examples#

For complete, production-ready examples with full UI implementation, please refer to the native example apps:

iOS (SwiftUI)

This example demonstrates:

  • Complete UI implementation with state management
  • Notice sheet presentation (iOS 18.2+)
  • Deep link handling and verification flow
  • Error handling and user feedback
  • Production-ready code patterns

Native References#