Migration

One section per coordinated major train. Each train lists the versions that drop the previously deprecated, OpenIAP-owned compatibility surface and the canonical call to use instead.

2.x → 3.0#

The coordinated major train removes the previously deprecated, OpenIAP-owned compatibility surface. Use this catalog to update calls before upgrading.

Removal boundaries#

OpenIAP specification and native packages

PackageLast compatible majorRemoved in
OpenIAP Spec2.x3.0.0
openiap-apple2.x3.0.0
openiap-google2.x3.0.0

Framework libraries

LibraryLast compatible majorRemoved in
expo-iap4.x5.0.0
react-native-iap15.x16.0.0
flutter_inapp_purchase9.x10.0.0
kmp-iap2.x3.0.0
maui-iap1.x2.0.0
godot-iap2.x3.0.0

IAPKit is a hosted service rather than a versioned framework library. Its scoped keys, client payloads, verification, and staged data migrations are unchanged by this SDK-only major train.

Generated Swift, Kotlin, TypeScript, Dart, GDScript, and C# contracts now expose only the canonical schema. The former declarations remain listed below solely as migration reference.

Raw JavaScript objects, plugin configuration, custom MethodChannel payloads, and direct Godot dictionaries must also use canonical keys. Removed aliases are rejected or ignored; they never override missing canonical input.

Flutter purchase payload compatibility#

PurchaseAndroid.dataAndroid is the only public, schema-defined field for Google Play's raw signed purchase JSON.originalJsonAndroid is not a public Purchase field and is never the preferred output key.

Flutter 9.x accepted the following legacy native or custom MethodChannel payload shapes. Flutter 10 accepts only the canonical forms in the middle column.

Legacy Flutter 9.x inputEmit insteadPlatform
originalJsonAndroiddataAndroidAndroid
purchaseStateAndroidpurchaseStateAndroid
transactionStateIOSpurchaseStateiOS
transactionReceiptpurchaseTokeniOS
id used as a transactionId fallbackan explicit transactionId; keep id as the purchase identityAndroid and iOS
top-level { sku } for verifyPurchase / validateReceiptIOS{ apple: { sku } }iOS and macOS

The canonical id purchase identity is not deprecated. Flutter 10 requires an explicit transactionId.

Issue #248 and Android raw purchase JSON

  • Before Flutter 9.6.1, issue #248 caused canonical dataAndroid input to be lost by the Dart compatibility converter.
  • The patch in PR #251 read dataAndroid first and accepted originalJsonAndroid only as a temporary Flutter 9.x input fallback. If both keys exist, dataAndroid wins.
  • Flutter 10 removes that fallback. Custom native adapters, MethodChannel fixtures, and mocks must emit dataAndroid.

See the canonical field reference in PurchaseAndroid.

Flutter 10 package-specific migrations#

In addition to the generated OpenIAP schema surfaces below,flutter_inapp_purchase 10.0.0 removes these Flutter-only compatibility APIs:

Deprecated Flutter surfaceMigrate to
ReplacementMode / ReplaceModeAndroidReplacementMode
TypeInAppProductQueryType
builder replacementModesubscriptionProductReplacementParams
builder useAlternativeBillingInitConnectionConfig.enableBillingProgramAndroid
purchaseUpdatedpurchaseUpdatedListener
PurchaseResult / purchaseErrorPurchaseError / purchaseErrorListener
ConnectionResult / connectionUpdatedthe initConnection result
requestPurchaseOnPromotedProductIOSpurchasePromoted, then requestPurchase

Custom MethodChannel integrations

Applications normally use the Dart API and never call these internal channel names. Flutter 10 custom integrations must use the replacements:

Legacy channel methodMigrate to
getAvailableItemsByTypegetAvailablePurchases
getPurchaseHistoryByTypegetAvailablePurchases for active purchases
buyItemByTyperequestPurchase
acknowledgePurchasefinishTransaction or acknowledgePurchaseAndroid
consumeProduct / consumePurchasefinishTransaction with isConsumable
showInAppMessagesshowInAppMessagesAndroid
getAppTransactiongetAppTransactionIOS
getSubscriptionStatussubscriptionStatusIOS

Custom MethodChannel payloads

The official Dart API emits the canonical forms below. Flutter 10 no longer normalizes the historical custom-channel inputs.

Legacy payload shapeEmit instead
product type 'inapp''in-app'
requestPurchase.request.ios / requestSubscription.request.iosapple
requestPurchase.request.android / requestSubscription.request.androidgoogle
productId / sku used as a product idid
discounts / subscription product metadatadiscountOffers or subscriptionOffers, plus subscriptionGroupIdIOS when applicable
subResponseCodesubResponseCodeAndroid
fetchProducts skuArr / productIdsskus
offerTokenArrofferToken for one-time products or subscriptionOffers for subscriptions
obfuscatedAccountIdAndroid / obfuscatedProfileIdAndroidobfuscatedAccountId / obfuscatedProfileId
purchaseTokenAndroid / tokenpurchaseToken
finishTransaction transactionIdentifiertransactionId
replacementModeAndroid / replacementModesubscriptionProductReplacementParams
unsuffixed deep-link sku / packageNameskuAndroid / packageNameAndroid
numeric-indexed iOS SKU maps{ skus: [...] }

Removed schema migration catalog#

The following OpenIAP-owned schema surfaces were removed by the package versions above.

Validation and storefront APIs

Deprecated surfaceMigrate to
validateReceiptverifyPurchase
validateReceiptIOSverifyPurchase
getStorefrontIOSgetStorefront
requestPurchaseOnPromotedProductIOSthe SDK's promoted-product listener or callback, then requestPurchase
checkAlternativeBillingAvailabilityAndroidisBillingProgramAvailableAndroid with the BillingProgramAndroid value your app is enrolled in
showAlternativeBillingDialogAndroidshowBillingProgramInformationDialogAndroid (the in-app Billing Programs dialog); launchExternalLinkAndroid covers the external-link flows (External Offer, External Content Link, Billing Choice external links)
createAlternativeBillingTokenAndroidcreateBillingProgramReportingDetailsAndroid with the BillingProgramAndroid value your app is enrolled in

Purchase and connection inputs

Deprecated surfaceMigrate to
RequestPurchasePropsByPlatforms.ios / RequestSubscriptionPropsByPlatforms.iosapple
RequestPurchasePropsByPlatforms.android / RequestSubscriptionPropsByPlatforms.androidgoogle
useAlternativeBillingenableBillingProgramAndroid in InitConnectionConfig
alternativeBillingModeAndroidenableBillingProgramAndroid
RequestSubscriptionAndroidProps.replacementModesubscriptionProductReplacementParams for item-level replacement (Play Billing 8.1+)

Shared fields and errors

Deprecated surfaceMigrate to
PurchaseCommon.platform / PurchaseInput.platform / PurchaseIOS.platform / PurchaseAndroid.platformstore
willExpireSoondaysUntilExpirationIOS
presentCodeRedemptionSheetIOS Boolean resultnullable PurchaseIOS result: verified on Apple 27+ with Xcode 27+; null after the system sheet on iOS 15–26 and visionOS 1–26; Catalyst 16–26 throws StoreKitError.unknown and Catalyst 15 has no effect
receipt-failedpurchase-verification-failed
receipt-finishedpurchase-verification-finished
receipt-finished-failedpurchase-verification-finish-failed

Offer and billing-program models

Deprecated surfaceMigrate to
SubscriptionOfferIOSSubscriptionOffer
DiscountIOS / DiscountOfferIOSSubscriptionOffer
ProductAndroidOneTimePurchaseOfferDetailDiscountOffer
ProductSubscriptionAndroidOfferDetailsSubscriptionOffer
ProductAndroid.oneTimePurchaseOfferDetailsAndroidProductAndroid.discountOffers
ProductSubscriptionAndroid.oneTimePurchaseOfferDetailsAndroidsubscriptionOffers; one-time offer fields do not apply to subscriptions
ProductSubscriptionAndroid.discountOfferssubscriptionOffers; one-time offer fields do not apply to subscriptions
ProductAndroid.subscriptionOfferDetailsAndroid / ProductSubscriptionAndroid.subscriptionOfferDetailsAndroidsubscriptionOffers
ProductIOS.subscriptionInfoIOS / ProductSubscriptionIOS.discountsIOSsubscriptionOffers
ProductSubscriptionIOS.subscriptionInfoIOSsubscriptionOffers for offers and subscriptionGroupIdIOS for the group identifier
AlternativeBillingModeAndroidBillingProgramAndroid
AlternativeBillingModeAndroid value 'user-choice'BillingProgramAndroid value 'user-choice-billing'
AlternativeBillingModeAndroid value 'alternative-only'BillingProgramAndroid value 'external-offer'
ExternalOfferAvailabilityResultAndroidBillingProgramAvailabilityResultAndroid from isBillingProgramAvailableAndroid
ExternalOfferReportingDetailsAndroidBillingProgramReportingDetailsAndroid from createBillingProgramReportingDetailsAndroid

Removed package-specific compatibility shims#

These public aliases and wrappers were package-local rather than GraphQL schema members. They are absent from the major versions named in each heading.

openiap-apple (OpenIAP 3.0)

Deprecated package surfaceMigrate to
ReceiptValidationProps / ReceiptValidationResult / ReceiptValidationResultIOSVerifyPurchaseProps / VerifyPurchaseResult / VerifyPurchaseResultIOS
OpenIapErrorCode / OpenIapEvent / OpenIapPlatformErrorCode / IapEvent / IapPlatform
getStorefrontIOSWithCompletiongetStorefrontWithCompletion
requestPurchaseOnPromotedProductIOSWithCompletionpromotedProductListenerIOS followed by requestPurchase
short requestSubscriptionWithSku(_:offer:completion:) overloadthe extended overload with compactJWS, promotionalOfferJWS, winBackOfferId, and billingPlanType
raw/custom purchase id used as a transactionId fallbackan explicit transactionId; keep id as the canonical purchase identity
OpenIapStore.deepLinkToSubscriptionsIOSdeepLinkToSubscriptions
OpenIapVersion.gqlVersion / OpenIapVersionInfo.gqlVersionOpenIapVersion.specVersion

openiap-google (OpenIAP 3.0)

Deprecated package surfaceMigrate to
ReceiptValidationProps / ReceiptValidationResult / ReceiptValidationResultIOSVerifyPurchaseProps / VerifyPurchaseResult / VerifyPurchaseResultIOS
AlternativeBillingModeBillingProgramAndroid through InitConnectionConfig.enableBillingProgramAndroid
Play OpenIapModule(context, AlternativeBillingMode, legacy listeners)OpenIapModule(context), then register listeners and pass InitConnectionConfig.enableBillingProgramAndroid to initConnection
Play OpenIapModule(context, enableAlternativeBilling) / OpenIapStore(context, enableAlternativeBilling)construct normally, then pass InitConnectionConfig.enableBillingProgramAndroid to initConnection
Play OpenIapStore(context, AlternativeBillingMode, userChoiceBillingListener)OpenIapStore(context), then register listeners and pass InitConnectionConfig.enableBillingProgramAndroid to initConnection
Amazon OpenIapModule(context, enableAlternativeBilling)OpenIapModule(context); Amazon ignores the legacy option
Amazon OpenIapModule(context, AlternativeBillingMode, legacy listeners)OpenIapModule(context); Amazon ignores the legacy options, then register listeners with add/remove APIs
Amazon OpenIapStore(context, AlternativeBillingMode, userChoiceBillingListener)OpenIapStore(context); Amazon ignores the legacy options
Horizon OpenIapModule / OpenIapStore constructors with AlternativeBillingMode or legacy listenersOpenIapModule(context) / OpenIapStore(context); Horizon ignores the legacy options
Horizon manifest keys com.meta.horizon.platform.ovr.OCULUS_APP_ID / com.meta.horizon.platform.ovr.HORIZON_APP_ID / com.oculus.vr.APP_IDcom.meta.horizon.platform.HORIZON_APP_ID
setUserChoiceBillingListener / setDeveloperProvidedBillingListenerthe corresponding add/remove listener APIs
UserChoiceDetails / UserChoiceBillingListenerUserChoiceBillingDetails / OpenIapUserChoiceBillingListener
DeveloperProvidedBillingDetails / DeveloperProvidedBillingListenerDeveloperProvidedBillingDetailsAndroid / OpenIapDeveloperProvidedBillingListener
OpenIapStore.connectionStatusOpenIapStore.isConnected
OpenIapError.InvalidReceiptOpenIapError.InvalidPurchaseVerification
checkAlternativeBillingAvailabilityisBillingProgramAvailable with BillingProgramAndroid.ExternalOffer
showAlternativeBillingInformationDialoglaunchExternalLink
createAlternativeBillingReportingTokencreateBillingProgramReportingDetails with BillingProgramAndroid.ExternalOffer
OpenIapLog.d / i / w / edebug / info / warn / error

react-native-iap 16.0.0

Deprecated package surfaceMigrate to
ProductTypeInput 'inapp''in-app'
request.ios / request.androidrequest.apple / request.google
replacementModesubscriptionProductReplacementParams
useIAP().alternativeBillingModeAndroidenableBillingProgramAndroid
acknowledgePurchaseacknowledgePurchaseAndroid
consumePurchaseconsumePurchaseAndroid
requestPromotedProductIOSgetPromotedProductIOS
getReceiptIOSgetReceiptDataIOS
requestPurchaseOnPromotedProductIOSpromotedProductListenerIOS, then requestPurchase
useIAP().requestPurchaseOnPromotedProductIOSonPromotedProductIOS, then requestPurchase

expo-iap 5.0.0

Deprecated package surfaceMigrate to
ProductTypeInput 'inapp''in-app'
request.ios / request.androidrequest.apple / request.google
Android custom-channel skuArrskus
Android custom-channel offerTokenArrsubscriptionOffers for subscriptions
replacementModesubscriptionProductReplacementParams
useIAP().alternativeBillingModeAndroidenableBillingProgramAndroid
acknowledgePurchaseacknowledgePurchaseAndroid
consumePurchaseconsumePurchaseAndroid
getReceiptIOSgetReceiptDataIOS
validateReceiptAndroidverifyPurchase
Android deep-link sku / packageNameskuAndroid / packageNameAndroid
requestPurchaseOnPromotedProductIOSpromotedProductListenerIOS, then requestPurchase
useIAP().requestPurchaseOnPromotedProductIOSonPromotedProductIOS, then requestPurchase
config.iosAlternativeBillingconfig.ios.alternativeBilling
config.horizonAppId / config.android.horizonAppIdconfig.android.horizon.appId
config.android.amazon.fireOS / boolean config.android.amazon.vegaOSconfig.modules.amazon.fireOS / config.modules.amazon.vegaOS

godot-iap 3.0.0

Deprecated package surfaceMigrate to
godot-iap get_storefront_iosget_storefront
godot-iap validate_receipt_ios / validate_receiptverify_purchase
godot-iap request_purchase_on_promoted_product_iospromoted_product_ios, then request_purchase
godot-iap check_alternative_billing_availability_androidis_billing_program_available_android with BillingProgramAndroid.EXTERNAL_OFFER
godot-iap show_alternative_billing_dialog_androidlaunch_external_link_android
godot-iap create_alternative_billing_token_androidcreate_billing_program_reporting_details_android with BillingProgramAndroid.EXTERNAL_OFFER
flattened verify_purchase_with_provider IAPKit keyskeep provider at the top level and nest apiKey, baseUrl, includeClientPayload, apple, google, and amazon under iapkit
ProductQueryType 'inapp' / 'in_app''in-app'
ProductQueryType 'subscription''subs'
raw request selector and ios / android purchase envelopesrequestPurchase or requestSubscription with apple / google
raw offer_tokenofferToken
raw obfuscatedAccountIdAndroid / obfuscatedProfileIdAndroid / purchaseTokenAndroidthe corresponding unsuffixed Google request keys
raw replacementModeAndroid / replacementModesubscriptionProductReplacementParams
raw skuArr / numeric-indexed iOS SKU mapsskus
raw offerTokenArrofferToken for a one-time product or subscriptionOffers for a subscription
Android native requestPurchaseJsonrequestPurchase
iOS simple requestPurchase(sku:) / top-level sku requestrequestPurchaseWithPayload using an apple request envelope

kmp-iap 3.0.0

Deprecated package surfaceMigrate to
kmp-iap requestPurchaseOnPromotedProductIOSpromotedProductListener, then requestPurchase
kmp-iap getStorefrontIOSgetStorefront
kmp-iap validateReceiptIOS / validateReceiptverifyPurchase
PurchaseRequestBuilder.ios / PurchaseRequestBuilder.androidPurchaseRequestBuilder.apple / PurchaseRequestBuilder.google
AndroidOptionsBuilder.replacementModesubscriptionProductReplacementParams
generated RequestPurchasePropsByPlatforms.ios / .android and RequestSubscriptionPropsByPlatforms.ios / .androidapple / google
generated RequestPurchaseProps.useAlternativeBilling / InitConnectionConfig.alternativeBillingModeAndroidInitConnectionConfig.enableBillingProgramAndroid
generated RequestSubscriptionAndroidProps.replacementModesubscriptionProductReplacementParams

OpenIap.Maui 2.0.0

Deprecated package surfaceMigrate to
OpenIap.Maui Iap facadeOpenIapClient
net9.0, net9.0-android, net9.0-ios, and net9.0-maccatalyst targetsthe matching net10.0 target frameworks with the .NET 10 MAUI workload
RequestPurchaseOnPromotedProductIOSAsyncPromotedProductIOS, then RequestPurchaseAsync

What this schedule does not remove#

The schedule applies to OpenIAP-owned deprecated schema members and explicit compatibility shims. It does not automatically remove:

  • redirects kept so existing documentation links continue to work;
  • documentation that describes an upstream StoreKit or Play Billing legacy technology still supported by the stores; or
  • StoreKit, Play Billing, Amazon, or Horizon response-shape normalization, including upstream names such as productIdentifier, localizedPrice, and historical receipt payload labels;
  • internal React Native, Expo, KMP, or Godot recovery of native response fields that applications do not author;
  • input normalization that accepts historical error-code spellings;
  • safe fallbacks used when an operating-system version does not support a newer store API; or
  • staged IAPKit storage migrations with their own retention and rollback requirements.

Check the release notes before every major upgrade for the final removal list and package-specific migration steps.