Skip to main content

One post tagged with "storekit2"

View All Tags

v3.4.3 - Win-Back Offers & Advanced Billing Features

· 3 min read
Hyo
Expo IAP Maintainer

This release syncs with OpenIAP v1.3.14, introducing iOS 18+ win-back offers, JWS promotional offers, Android 8.0+ product status codes, and important type cleanup.

New Features

Win-Back Offers (iOS 18+)

Win-back offers allow you to re-engage churned subscribers with special discounts or free trials.

import {requestPurchase} from 'expo-iap';

// Apply a win-back offer during subscription purchase
await requestPurchase({
request: {
apple: {
sku: 'premium_monthly',
winBackOffer: {
offerId: 'winback_50_off', // iOS 18+
},
},
},
type: 'subs',
});

Win-back offers are automatically presented via StoreKit Message when eligible, or can be applied programmatically.

JWS Promotional Offers (iOS 15+)

A new simplified format for promotional offers using compact JWS strings, back-deployed to iOS 15.

await requestPurchase({
request: {
apple: {
sku: 'premium_yearly',
promotionalOfferJWS: {
offerId: 'promo_20_off',
jws: 'eyJhbGciOiJFUzI1NiI...', // Server-signed JWS
},
},
},
type: 'subs',
});

Introductory Offer Eligibility Override (iOS 15+)

Override system-determined introductory offer eligibility.

await requestPurchase({
request: {
apple: {
sku: 'premium_monthly',
introductoryOfferEligibility: true, // Force eligible
},
},
type: 'subs',
});

Product Status Codes (Android 8.0+)

Get detailed feedback on why products couldn't be fetched.

import {fetchProducts} from 'expo-iap';
import type {ProductAndroid} from 'expo-iap';

const result = await fetchProducts({
skus: ['product_1', 'product_2'],
type: 'in-app',
});

result.forEach((product) => {
const androidProduct = product as ProductAndroid;
if (androidProduct.productStatusAndroid) {
switch (androidProduct.productStatusAndroid) {
case 'ok':
// Product available
break;
case 'not-found':
// SKU doesn't exist in Play Console
break;
case 'no-offers-available':
// User not eligible for any offers
break;
}
}
});

Suspended Subscriptions Support (Android 8.1+)

Include suspended subscriptions when fetching available purchases. This feature required native code updates to pass the option through to the OpenIAP SDK.

import {getAvailablePurchases} from 'expo-iap';

const purchases = await getAvailablePurchases({
includeSuspendedAndroid: true, // Include suspended subs
});

// Check if subscription is suspended
purchases.forEach((purchase) => {
if (purchase.isSuspendedAndroid) {
// Direct user to resolve payment issues
// Do NOT grant entitlements for suspended subscriptions
}
});

Important: Suspended subscriptions should NOT be granted entitlements. Users should be directed to the Play Store subscription center to resolve payment issues.

Sub-Response Codes (Android 8.0+)

More granular error information for purchase failures.

// SubResponseCodeAndroid provides additional context:
// - 'no-applicable-sub-response-code'
// - 'payment-declined-due-to-insufficient-funds'
// - 'user-ineligible'

Type Cleanup

Subscription-Only Fields Removed from RequestPurchaseIosProps

The following fields have been removed from RequestPurchaseIosProps because they only apply to subscription purchases:

  • winBackOffer - Win-back offers are subscription-only (iOS 18+)
  • promotionalOfferJWS - JWS promotional offers are subscription-only
  • introductoryOfferEligibility - Introductory eligibility is subscription-only

These fields remain available in RequestSubscriptionIosProps where they belong.

Migration: If you were incorrectly using these fields with one-time purchases, move them to subscription purchases with type: 'subs'.

New Types

TypePlatformDescription
WinBackOfferInputIOSiOS 18+Win-back offer configuration
PromotionalOfferJwsInputIOSiOS 15+JWS promotional offer input
ProductStatusAndroidAndroid 8.0+Product fetch status codes
SubResponseCodeAndroidAndroid 8.0+Granular purchase error codes
BillingResultAndroidAndroid 8.0+Extended billing result with sub-response

Updated Types

  • SubscriptionOfferTypeIOS now includes 'win-back' type
  • RequestSubscriptionIosProps now supports:
    • winBackOffer
    • promotionalOfferJWS
    • introductoryOfferEligibility
    • withOffer (promotional offer)
  • PurchaseOptions now supports includeSuspendedAndroid
  • ProductAndroid and ProductSubscriptionAndroid now include productStatusAndroid

OpenIAP Versions

PackageVersion
openiap-gql1.3.14
openiap-google1.3.25
openiap-apple1.3.13

For detailed changes, see the OpenIAP Release Notes.