> ## Documentation Index
> Fetch the complete documentation index at: https://documentation.qonversion.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Apple Promotional Offers

> Learn how to work with Apple Promotional Offers using Qonversion SDKs

<Info>
  ### This section is about [Apple Promotional Offers](https://developer.apple.com/documentation/storekit/in-app_purchase/original_api_for_in-app_purchase/subscriptions_and_offers/implementing_promotional_offers_in_your_app)

  Please do not confuse them with [Apple Introductory Offers](https://developer.apple.com/documentation/storekit/in-app_purchase/original_api_for_in-app_purchase/subscriptions_and_offers/implementing_introductory_offers_in_your_app) and [App Store Promoted Purchases](app-store-promoted-purchases), which are used for new users and for promoting your products through the App Store, respectively.
</Info>

Promotional offers are useful for re-engaging former subscribers or keeping current ones on board. Consider offering a limited-time discount or a free trial period for auto-renewable subscriptions on macOS, iOS, and tvOS. This can encourage lapsed users to return and help retain your existing subscriber base.

To use promotional offers in your app, you will need to complete a few steps:

1. Create a promotional offer in App Store Connect.
2. Connect your In-App Purchase API key in Qonversion. If you haven't set it up yet, follow the [In-App Purchase API Key](in-app-purchase-api-key) guide — it covers when, how, and where.
3. Use the new features of our SDK to obtain the promo offer and make a purchase with it.

### Create a promotional offer

Add your Promotional Offer in App Store Connect. You can find the instructions in the [official documentation](https://developer.apple.com/help/app-store-connect/manage-subscriptions/set-up-promotional-offers-for-auto-renewable-subscriptions).

### Generate a Private Key

Promotional offers are signed with your **In-App Purchase API key** — the same key you upload on **Step 3 · Server API access** of the iOS configuration wizard. If you haven't set it up yet, follow the [In-App Purchase API Key](in-app-purchase-api-key) guide — it covers when, how, and where.

### Get a promotional offer and make a purchase

The promotional offers you create in App Store Connect can be accessed within our SDK by calling `Qonversion.Product -> skProduct -> discounts`.

You can determine whether the user is eligible for a promotional offer based on your product’s business logic. Once you decide to grant the promotional offer to a user, you need to call the following function:

<CodeGroup>
  ```swift Swift theme={null}
  // You can obtain the product and discount in any other way. This approach is used here as an example.
  let mainProduct: Qonversion.Product = products["main"]
  let discount: SKProductDiscount? = mainProduct.skProduct?.discounts.first(where: { $0.identifier == "main_promo_offer" })
  Qonversion.shared().getPromotionalOffer(for: mainProduct, discount: discount) { promoOffer, error in
      // show paywall with promo offer
  }
  ```

  ```objectivec Objective-C theme={null}
  // You can obtain the product and discount in any other way. This approach is used here as an example.
  QONProduct *product = products[@"main"];
  NSArray *discounts = [product.skProduct.discounts filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(SKProductDiscount *object, NSDictionary *bindings) {
    return [object.identifier isEqualToString:@"main_promo_offer"];
  }]];
  [[Qonversion sharedInstance] getPromotionalOfferForProduct:product discount:discounts.firstObject completion:^(QONPromotionalOffer * _Nullable promotionalOffer, NSError * _Nullable error) {
    // show paywall with promo offer
  }];
  ```

  ```dart Flutter theme={null}
  try {
    // You can obtain the product and discount in any other way. This approach is used here as an example.
    var promo = subscriptionProduct.skProduct?.discounts?.firstWhereOrNull(
      (discount) => discount.identifier == 'my_promo_offer_id'
    );

    if (promo != null) {
      var promoOffer = await Qonversion.getSharedInstance().getPromotionalOffer(subscriptionProduct, promo);
      // handle promo offer here
    }
  } on Exception catch (e) {
    // handle error here
  }
  ```

  ```typescript React Native theme={null}
  try {
    // You can obtain the product and discount in any other way. This approach is used here as an example.
    const promo = subscriptionProduct.skProduct?.discounts?.find(discount =>
        discount.identifier === 'my_promo_offer_id'
    );
    
    if (promo) {
      const promoOffer = await Qonversion.getSharedInstance().getPromotionalOffer(subscriptionProduct, promo);
    }
    // handle promo offer here
  } catch (e) {
      // handle error here
  }
  ```

  ```csharp Unity theme={null}
  var promo = subscriptionProduct.SkProduct?.Discounts?.Find(
    discount => discount.Identifier == "my_promo_offer_id"
  );

  if (promo != null) {
    Qonversion.GetSharedInstance().GetPromotionalOffer(subscriptionProduct, promo, (promoOffer, error) => {
      // Handle result here
    });
  }
  ```

  ```typescript Cordova theme={null}
  try {
    // You can obtain the product and discount in any other way. This approach is used here as an example.
    const promo = subscriptionProduct.skProduct?.discounts?.find(discount =>
        discount.identifier === 'my_promo_offer_id'
    );
    
    if (promo) {
      const promoOffer = await Qonversion.getSharedInstance().getPromotionalOffer(subscriptionProduct, promo);
    }
    // handle promo offer here
  } catch (e) {
      // handle error here
  }
  ```

  ```typescript Capacitor theme={null}
  try {
    // You can obtain the product and discount in any other way. This approach is used here as an example.
    const promo = subscriptionProduct.skProduct?.discounts?.find(discount =>
        discount.identifier === 'my_promo_offer_id'
    );
    
    if (promo) {
      const promoOffer = await Qonversion.getSharedInstance().getPromotionalOffer(subscriptionProduct, promo);
    }
    // handle promo offer here
  } catch (e) {
      // handle error here
  }
  ```
</CodeGroup>

After that, we will check on our server whether the user is eligible for this promotional offer. If they are, we will generate a signature for the purchase and return a `Qonversion.PromotionalOffer` object, which you will need to pass to the purchase function.

#### Determine eligibility

What availability conditions do we check for promotional offers? Those described in the [official documentation](https://developer.apple.com/documentation/storekit/in-app_purchase/original_api_for_in-app_purchase/subscriptions_and_offers/implementing_promotional_offers_in_your_app#3150971). In the future, these options may be expanded.

We consider a user eligible for an offer if they have any active or expired subscription from any subscription group.

#### Make a purchase

To make a purchase with a promotional offer, take the object you received from the previous function, pass it into the purchase options object, and pass it to the `purchaseProduct` function.

<CodeGroup>
  ```swift Swift theme={null}
  let purchaseOptions = Qonversion.PurchaseOptions(promoOffer: promoOffer)
  Qonversion.shared().purchase(product, options: purchaseOptions) { (result) in
      // handle purchase result here
  }
  ```

  ```objectivec Objective-C theme={null}
  QONPurchaseOptions *purchaseOptions = [[QONPurchaseOptions alloc] initWithPromoOffer:promotionalOffer];
  [[Qonversion sharedInstance] purchaseWithResult:product
                                          options:purchaseOptions
                                       completion:^(QONPurchaseResult * _Nonnull result) {
    // handle purchase result here
  }];
  ```

  ```dart Flutter theme={null}
  var purchaseOptions = QPurchaseOptionsBuilder()
  		.setPromotionalOffer(promoOffer)
  		.build();

  var entitlements = await Qonversion.getSharedInstance().purchaseProduct(
    	subscriptionProduct,
    	purchaseOptions: purchaseOptions
  );
  ```

  ```typescript React Native theme={null}
  const purchaseOptions = new PurchaseOptionsBuilder()
    .setPromotionalOffer(promoOffer))
    .build();
  const entitlements = await Qonversion.getSharedInstance().purchaseProduct(
    subscriptionProduct,
    purchaseOptions
  );
  ```

  ```csharp Unity theme={null}
  var purchaseOptions = new PurchaseOptionsBuilder()
    	.SetPromotionalOffer(promoOffer)
    	.Build();
  Qonversion.GetSharedInstance().PurchaseProduct(
    subscriptionProduct,
    purchaseOptions,
    (entitlements, error, isCancelled) =>
    {
      ...
    });
  ```

  ```typescript Cordova theme={null}
  const purchaseOptions = new Qonversion.PurchaseOptionsBuilder()
    .setPromotionalOffer(promoOffer))
    .build();
  const entitlements = await Qonversion.getSharedInstance().purchaseProduct(
    subscriptionProduct,
    purchaseOptions
  );
  ```

  ```typescript Capacitor theme={null}
  const purchaseOptions = new PurchaseOptionsBuilder()
    .setPromotionalOffer(promoOffer))
    .build();
  const entitlements = await Qonversion.getSharedInstance().purchaseProduct(
    subscriptionProduct,
    purchaseOptions
  );
  ```
</CodeGroup>

***

[Migrate from SwiftyStoreKit](swiftystorekit-alternative)

[Google Play Store](google-play)
