---
title: "What does Product.PurchaseError.invalidOfferSignature mean?"
description: "Product.PurchaseError.invalidOfferSignature means the App Store rejected the signature of a promotional offer. Rebuild the signed text, use a fresh nonce and sign it with the right key."
url: https://revenuedot.app/docs/errors/storekit-purchase-error-invalid-offer-signature
---

# What does Product.PurchaseError.invalidOfferSignature mean?

Product.PurchaseError.invalidOfferSignature means the App Store could not validate the signature of the promotional offer.

## Quick facts

| | |
|---|---|
| Error | `Product.PurchaseError.invalidOfferSignature` |
| 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 offer signature is not valid. |

## Cause

- Apple says the signature is made from the product and offer parameters plus a nonce and timestamp your server generates, joined in a fixed order with the invisible separator U+2063, and signed with your PKCS #8 private key using ECDSA with SHA-256 ([Generating a signature](https://developer.apple.com/documentation/storekit/generating-a-signature-for-promotional-offers)).
- Apple also says each payload, signature and nonce is valid for one buy request only, even if the buy fails, so reusing a signature after a failed attempt fails.
- If you pass an app account token, Apple says it must be part of the signed text, and the UUID strings of the token and the nonce must be lowercase ([promotionalOffer option](https://developer.apple.com/documentation/storekit/product/purchaseoption/promotionaloffer%28offerid:keyid:nonce:signature:timestamp:%29)).

## Fix

1. Rebuild the signed string in the exact order Apple lists, with the separator between the parts.
2. Create a new nonce and timestamp for every attempt, and sign again after any failed purchase.
3. Sign with the private key whose key ID you send as `keyID`, and Base64-encode the DER signature.
4. Use lowercase UUID strings for the nonce and the app account token, and sign the same values you send.
5. Check the signature locally with the public key before you send it, as Apple suggests.

## Example

```swift
import StoreKit

// A signature works once. After a failed purchase, ask your server for a new nonce, timestamp and signature.
func buy(_ product: Product, offerID: String, keyID: String, nonce: UUID, signature: Data, timestamp: Int) async {
    let offer = Product.PurchaseOption.promotionalOffer(offerID: offerID, keyID: keyID, nonce: nonce, signature: signature, timestamp: timestamp)
    do {
        _ = try await product.purchase(options: [offer])
    } catch Product.PurchaseError.invalidOfferSignature {
        print("The App Store rejected the signature; request a fresh one from the server")
    } 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 `Product.PurchaseError.invalidOfferSignature` to `ErrorCode.invalidPromotionalOfferError` (code 34). The SDK builds and signs the offer for you when you use its promotional offer API, so this error mostly appears when you sign offers yourself.

## Related

- [What does Product.PurchaseError.invalidOfferIdentifier mean?](https://revenuedot.app/docs/errors/storekit-purchase-error-invalid-offer-identifier.md)
- [What does Product.PurchaseError.ineligibleForOffer mean?](https://revenuedot.app/docs/errors/storekit-purchase-error-ineligible-for-offer.md)
- [What does VerificationError.invalidSignature mean in StoreKit 2?](https://revenuedot.app/docs/errors/storekit-verification-error-invalid-signature.md)

## Source

- [Apple: Generating a signature for promotional offers](https://developer.apple.com/documentation/storekit/generating-a-signature-for-promotional-offers)
- [Apple: promotionalOffer purchase option](https://developer.apple.com/documentation/storekit/product/purchaseoption/promotionaloffer%28offerid:keyid:nonce:signature:timestamp:%29)
- [Apple: Product.PurchaseError.invalidOfferSignature](https://developer.apple.com/documentation/storekit/product/purchaseerror/invalidoffersignature)
- [Apple: Product.PurchaseError](https://developer.apple.com/documentation/storekit/product/purchaseerror)
- [RevenueDot purchases-ios: StoreKitError+Extensions.swift (how the SDK maps StoreKit 2 errors)](https://github.com/revenuedot/purchases-ios/blob/revenuedot/main-patches/Sources/Error%20Handling/StoreKitError%2BExtensions.swift)

Checked: 2026-10-03
