To get started in generating a subscription offer signature head over to Apple’s hosted library on GitHub. I was pointed to this library from the developer forums after attempting to generate a signature using Apple’s sample code from WWDC 2019.
Our goal is to generate a signature on a server and retrieve this signature along with its timestamp and nonce in order to start making promotional offer purchases from our iOS app.
Promotional offers can be effective in winning back lapsed subscribers or retaining current subscribers. You can provide lapsed or current subscribers a limited-time offer of a discounted or free period of service for auto-renewable subscriptions
Prerequisites
- A private key must be generated on App Store Connect and downloaded. Note: this key can only be downloaded once.
- This library code assumes you’re running in a node environment.
- Current or lapsed subscribers are eligible for promotional offer purchasing.
Generating a signature for use in promotional offer purchasing
Code here would be hosted on your server.
Create a file in the server library project e.g. “promo_tests.ts” and add the following code to it. Run the following commands:
tsc promo_test.ts– this will build and convert the TypeScript file to JavaScript to be executed in your Node environment.node promo_test.js– this will run the JavaScript code and print the results of the signature to your Terminal window.- When using StoreKit 2’s `purchase(options: options)` to make the promotional offer purchase you will need the following from the generated server code: the
timestamp,nonce, andsignature.
import { PromotionalOfferSignatureCreator } from "@apple/app-store-server-library"
import { readFile } from "fs"
const filePath = "/Users/alexpaul/Desktop/SubscriptionKey_1234567.p8";
const keyId = "1234567"
const bundleId = "com.app.name"
const productId = "your.product.identifier"
const subscriptionOfferId = "promo.offer.id"
const applicationUsername = "3dd16e4d-f692-4286-8d23-b2a09c83b95f"
const nonce = crypto.randomUUID()
const timestamp = Date.now()
readFile(filePath, "utf8", (err, data) => {
if (err) {
console.error(err);
return;
}
const encodedKey = data;
const signatureCreator = new PromotionalOfferSignatureCreator(encodedKey, keyId, bundleId)
const signature = signatureCreator.createSignature(productId, subscriptionOfferId, applicationUsername, nonce, timestamp)
console.log("timestamp: ", timestamp)
console.log("nonce: ", nonce)
console.log("signature: ", signature)
});
Using the generated signature from the server code above to make a promotional offer purchase from your Xcode project
- offerID: The `id` property of the `SubscriptionOffer` to apply.
- keyID: The key ID of the private key used to generate the `signature`. The private key and key ID can be generated on App Store Connect.
- nonce: The nonce used in `signature`.
- signature: The cryptographic signature of the offer parameters, generated on your server.
- timestamp: The time the signature was generated in milliseconds since 1970.
- appAccountToken: Sets a UUID to associate the purchase with an account in your system.
// Purchasing logic
let options = Set(
[
Product.PurchaseOption.appAccountToken(appAccountToken),
Product.PurchaseOption.promotionalOffer(
offerID: offerID,
keyID: keyID,
nonce: nonce,
signature: signature,
timestamp: timestamp
)
]
)
let result = try await subscription.product.purchase(options: options)
// Continue with purchasing logic

Resources
- Subscription Offers Best Practices – WWDC19
- Implementing promotional offers.
- Apple App Store Server Node.js Library
- Generate keys for in-app purchases.
promotionalOffer(offerID:keyID:nonce:signature:timestamp:)Applies a promotional offer for an auto-renewable subscription.- purchase(options:) Initiates a purchase for the product with the App Store and displays the confirmation sheet.
