What does Product.PurchaseError.invalidOfferIdentifier mean?

Product.PurchaseError.invalidOfferIdentifier means the promotional offer identifier you passed in the purchase options is not valid.

Quick facts#

Error Product.PurchaseError.invalidOfferIdentifier
Where StoreKit 2, Swift (Product.purchase(options:))
Available since iOS 15.0, iPadOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, visionOS 1.0
What the vendor says The promotional offer identifier provided in the purchase options is invalid.

Cause#

  • The identifier in .promotionalOffer(offerID:keyID:nonce:signature:timestamp:) does not match a promotional offer the App Store knows for this product.
  • Apple says promotional offers must first be set up in App Store Connect, and the offers on a product appear in its subscription.promotionalOffers array (promotionalOffer option).
  • A typo, an offer attached to another product or an offer you never created all produce this error.

Fix#

  1. Read the offer ID from product.subscription?.promotionalOffers instead of typing it by hand.
  2. Compare the ID with the offer in App Store Connect, character by character.
  3. Make sure the offer belongs to the same subscription product you are buying.
  4. Sign the offer on your server only after you have picked a valid offer ID, because the ID is part of the signed text.

Example#

Swift
import StoreKit

// Take the offer ID from the product itself, so the identifier you sign and send always exists.
func offerID(for product: Product) -> String? {
    product.subscription?.promotionalOffers.first?.id
}

func buy(_ product: Product, options: Set<Product.PurchaseOption>) async {
    do {
        _ = try await product.purchase(options: options)
    } catch Product.PurchaseError.invalidOfferIdentifier {
        print("The offer ID is not one of \(product.id)'s promotional offers")
    } catch {
        print("Purchase failed: \(error)")
    }
}

Compile-checked: npm run check:snippets type-checks this snippet with swiftc against the Apple SDK (macOS target, checked 2026-10-03).

How the RevenueDot SDK reports it#

The RevenueDot purchases-ios fork maps invalidOfferIdentifier, invalidOfferPrice, invalidOfferSignature and missingOfferParameters to one code, ErrorCode.invalidPromotionalOfferError (code 34). Read the underlying error to see which of the four it was.

Source#

Checked: 2026-10-03

Edit this page on GitHub ↗ View as Markdown Last updated