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

# Create a Promotional Offer

> Create a promotional offer in App Store Connect and link it in Encore so churn-moment offers carry a discounted or free period.

## Overview

Promotional offers let you give existing or lapsed subscribers a discounted or free period when they accept an Encore offer at a churn moment. The offer is created in App Store Connect and linked through your [Encore dashboard](https://dashboard.encorekit.com). When Encore presents the offer, the `PurchaseRequest` includes the `promoOfferId` so the purchase can apply it.

<Info>
  Promotional offers differ from introductory offers. Introductory offers apply automatically to new subscribers, while promotional offers are targeted: your app decides when and to whom they're shown. Encore handles this targeting for you.
</Info>

***

## Prerequisites

* An auto-renewable subscription product configured in Encore (see [App Store Subscription Product](./subscription-product): connect your App Store Connect catalog and pick the product)
* Access to App Store Connect with the Admin or App Manager role

***

## Step 1: Create the promotional offer

<Steps>
  <Step title="Open your subscription">
    Go to [App Store Connect](https://appstoreconnect.apple.com) → **Apps** → your app → **Subscriptions**. Select the subscription product you want to add a promotional offer to.
  </Step>

  <Step title="Add a promotional offer">
    Scroll down to the **Subscription Prices** section and click the **"+"** button. Then click **Create Promotional Offer**
  </Step>

  <Step title="Configure the offer">
    Fill in the following fields:

    | Field                            | Description                                            | Example                     |
    | -------------------------------- | ------------------------------------------------------ | --------------------------- |
    | **Reference Name**               | Internal label (not shown to users)                    | `Encore 3 Month Free`       |
    | **Promotional Offer Identifier** | Unique identifier you'll enter in the Encore dashboard | `com.yourapp.promo.3m.free` |
    | **Offer Type**                   | Free, Pay As You Go, or Pay Up Front                   | `Free`                      |
    | **Duration**                     | How long the offer lasts                               | `2 Months`                  |

    <Tip>
      For churn moments, a **Free** period of a few months tends to perform best. This gives a churning user a compelling reason to stay without requiring immediate payment.
    </Tip>
  </Step>

  <Step title="Save">
    Click **Create** to save the promotional offer. The **Promotional Offer Identifier** you entered above is the value you'll enter as the **Promotional Offer ID** in the Encore dashboard.
  </Step>
</Steps>

***

## Step 2: Generate an In-App Purchase key

Promotional offers require server-side signature verification. If you're using **StoreKit** directly (not a third-party manager), Encore signs offers on your behalf using a separate **In-App Purchase key**.

<Warning>
  **This is a different key from the one you uploaded to connect your store catalog.** The App Store Connect API key from [App Store Subscription Product](./subscription-product) (Key ID + Issuer ID + .p8, **App Manager** role) is **read-only for product setup and pricing display**: Encore uses it to sync your subscription catalog and show your products. It does **not** sign promotional offers.

  Promotional-offer signing uses a dedicated **In-App Purchase key**, generated on a different App Store Connect page (below) and uploaded separately under **Entitlements → Promotional Offer Setup**. Keep the two distinct: the catalog-sync key never signs offers, and the In-App Purchase key is only needed when you sign offers with StoreKit directly.
</Warning>

<Steps>
  <Step title="Open the keys page">
    Go to [App Store Connect → Users and Access → Integrations → In-App Purchase](https://appstoreconnect.apple.com/access/integrations/api/subs).
  </Step>

  <Step title="Generate a key">
    Click **"Generate In-App Purchase Key"** and give it a descriptive name (e.g., `Encore Signing Key`).
  </Step>

  <Step title="Copy the Key ID">
    Copy the **Key ID** shown in the table (e.g., `WHJ3V7RXNW`). You'll need this in the Encore dashboard.
  </Step>

  <Step title="Download the .p8 file">
    Click **Download** to save the `.p8` private key file. You can only download this file once, so store it securely.
  </Step>
</Steps>

<Warning>
  The `.p8` key file can only be downloaded once. If you lose it, you'll need to generate a new key.
</Warning>

<Note>
  If you use a third-party subscription manager (RevenueCat, Adapty), it handles offer signing through its own SDK. You do **not** need to upload the `.p8` key to Encore, but you still need the promotional offer created in App Store Connect.
</Note>

***

## Step 3: Link in the Encore Dashboard

1. Go to your app in the [Encore Dashboard](https://dashboard.encorekit.com)
2. Navigate to **Entitlements** → **Promotional Offer Setup**
3. Enter the **Promotional Offer ID** (the Promotional Offer Identifier from Step 1)
4. If using StoreKit directly, also provide your **Key ID** and upload the **.p8 file**
5. Select your **Subscription Manager** and follow the integration instructions shown

***

## Naming convention

Use a consistent naming pattern for your promotional offer IDs:

```
{bundle_id}.promo.{duration}.{type}
```

| Example                           | Meaning                     |
| --------------------------------- | --------------------------- |
| `com.yourapp.promo.3m.free`       | 3 months free               |
| `com.yourapp.promo.1m.free`       | 1 month free                |
| `com.yourapp.promo.6m.payasyougo` | 6 months at a reduced price |

***

## Handling the offer in code

Once the promotional offer is created and linked, Encore includes the `promoOfferId` in the `PurchaseRequest` when presenting offers at churn moments. The `promoOfferId` is only present when Encore determines the user should receive a promotional offer; standard purchases have `promoOfferId` set to `nil`. How you apply it depends on your subscription manager:

<Tabs>
  <Tab title="StoreKit">
    When no `onPurchaseRequest` handler is set, Encore handles promotional offer signing and purchase automatically through native StoreKit. This is the recommended approach for apps using StoreKit directly. To enable automatic signing, provide your In-App Purchase key as described in [Step 2](#step-2-generate-an-in-app-purchase-key) above.

    <Warning>
      If you set a custom [`onPurchaseRequest`](../sdk-reference/on-purchase-request) handler, Encore will **not** sign offers automatically. You must handle promo offer signing yourself using StoreKit's `Product.SubscriptionOffer` APIs. Only set a custom handler if your app requires it (e.g., when routing purchases to a third-party manager).
    </Warning>
  </Tab>

  <Tab title="RevenueCat">
    Manually check for the promotional offer, sign it through RevenueCat, and fall back to a standard purchase if the user isn't eligible.

    ```swift theme={null}
    Encore.shared.onPurchaseRequest { purchaseRequest in
        guard let product = try await Purchases.shared.products([purchaseRequest.productId]).first else {
            return false
        }
        if let promoOfferId = purchaseRequest.promoOfferId,
            let promoDiscount = product.discounts.first(where: { $0.offerIdentifier == promoOfferId }) {
            do {
                let offer = try await Purchases.shared.promotionalOffer(
                    forProductDiscount: promoDiscount, product: product
                )
                let result = try await Purchases.shared.purchase(product: product, promotionalOffer: offer)
                return !result.userCancelled
            } catch {
                // Promo failed (ineligible, network error, etc.) — fall back to standard purchase
                let result = try await Purchases.shared.purchase(product: product)
                return !result.userCancelled
            }
        } else {
            let result = try await Purchases.shared.purchase(product: product)
            return !result.userCancelled
        }
    }
    ```

    <Warning>
      Your local StoreKit configuration file must be synced with App Store Connect. Promotional offers will not work if it is out of sync.
    </Warning>
  </Tab>

  <Tab title="Adapty">
    Adapty automatically presents the promotional offer if the user is eligible (when configured correctly in the Adapty dashboard). Falls back to a standard purchase with an introductory offer.

    ```swift theme={null}
    Encore.shared.onPurchaseRequest { purchaseRequest in
        let paywall = try await Adapty.getPaywall(placementId: "YOUR_PAYWALL_PLACEMENT_ID")
        let products = try await Adapty.getPaywallProducts(paywall: paywall)
        guard let product = products.first(where: {
            $0.vendorProductId == purchaseRequest.productId
        }) else {
            return false
        }
        let result = try await Adapty.makePurchase(product: product)
        return !result.isPurchaseCancelled
    }
    ```

    <Warning>
      Adapty does not fall back to StoreKit: products and offers must exist in Adapty. Sync products in the Adapty dashboard before use, and configure the promotional offer there (it does not sync from App Store Connect automatically).
    </Warning>
  </Tab>
</Tabs>

See [onPurchaseRequest](../sdk-reference/on-purchase-request) for the full handler contract.

***

## Next steps

* [App Store Subscription Product](./subscription-product): the base subscription product the offer discounts.
* [Reduce Churn](/publishers/use-cases/reduce-churn): the use case these offers serve.
