This guide connects one iOS app to SubKit. When finished, the app can load Apple products from a SubKit offering, reconcile StoreKit transactions through Apple’s server APIs, and read the resulting entitlements from SubKit.
Trust boundary
- The mobile app receives one public, app-bound SDK key (
sk_sdk_…). - App Store Connect credentials remain encrypted in SubKit and never ship in the app.
- App code does not select
productionorsandbox. Apple-signed transaction evidence determines the environment. - A StoreKit callback alone never unlocks access. The entitlement must be active
in the
CustomerInforeturned by SubKit.
Prerequisites
Before starting, make sure:
- the app exists in App Store Connect with its final bundle ID;
- the app has the In-App Purchase capability;
- the required Apple agreements, tax details, and banking details are active for paid products;
- you can manage App Store Connect API keys, subscriptions, and app information;
- the iOS app has the native IAP dependency described in Expo installation;
- SubKit is reachable through HTTPS from the device and, for notifications, from Apple.
For a local SubKit instance, use a stable HTTPS tunnel or another device-reachable
HTTPS origin. localhost on an iPhone is the iPhone itself, and Apple cannot
send Server Notifications to your development machine without a public route.
Apple credential types
Apple exposes two related but distinct key families:
| Apple key | Primary purpose |
|---|---|
| App Store Connect API key | App discovery, catalog import, prices, builds, reviews, provisioning metadata, and reports |
| In-App Purchase key | App Store Server API requests and promotional-offer signing |
SubKit stores these key families in separate encrypted slots. The App Store Connect API key is used only for app discovery, catalog sync, monitoring, and reports. The In-App Purchase key is used only for App Store Server API transaction lookups. Runtime purchase verification fails closed when the separate In-App Purchase key is missing or invalid; the catalog key is never a silent fallback.
Before a production launch, validate both operations independently:
- App Store Connect catalog validation succeeds with the catalog key.
- A real Apple Sandbox transaction is verified through the App Store Server API with the In-App Purchase key and activates the expected entitlement.
If either operation fails, do not substitute a broader key or bypass verification. Rotate the affected key family and repeat its validation.
Values you will need
| Value | Where to find it | Used for |
|---|---|---|
| Key ID | App Store Connect → Users and Access → Integrations | Signing short-lived Apple API tokens |
| Issuer ID | App Store Connect → Users and Access → Integrations | Identifying the App Store Connect team |
Private .p8 key |
One-time download when the API key is created | Server-side Apple API authentication |
| Vendor Number | Payments and Financial Reports | Optional Sales and Trends report imports |
| Apple App ID | App Store Connect → App Information | Mapping the exact Apple app to SubKit |
| Bundle ID | App Store Connect and the native app | Transaction and app identity validation |
| Notification URL | Your public SubKit origin | https://<subkit-host>/api/stores/apple/notifications |
1. Create an App Store Connect API key
- Open Users and Access → Integrations → App Store Connect API.
- If API access is not enabled yet, the Account Holder must request it first.
- Create a team key or an individual API key.
- Grant the smallest role that covers the SubKit features you intend to use. Begin with read access for catalog sync and monitoring. Broader permissions are only needed when you intentionally enable confirmed store writes.
- Record the Key ID and Issuer ID.
- Download the
.p8file and store the original securely. Apple allows the private key to be downloaded only once.
Team keys apply across the App Store Connect team. If you need narrower app access, use an individual key for a user whose app access is already restricted.
2. Connect App Store Connect to the SubKit workspace
App Store Connect credentials belong to the workspace because one credential can discover and import multiple apps in that Apple team.
- Open Workspace settings in the SubKit Console.
- Open the App Store Connect connection.
- Enter the Key ID and Issuer ID.
- Upload the private
.p8file. - Enter the Vendor Number only if you want Sales and Trends report imports.
- Save and validate the connection.
- In the separate App Store Server API section, enter the Key ID and Issuer
ID of an Apple In-App Purchase key and upload its
.p8file. - Review the capability results. App listing and the subscription/IAP catalog must be available for the setup in this guide. The IAP server-key status must also be configured before native purchases can reconcile.
SubKit encrypts both private keys independently and never displays them again.
To rotate a key, upload a new .p8 file in the matching slot, validate it, then
revoke only the replaced key in App Store Connect.
3. Create or select the SubKit app
- In the SubKit Console, choose New app.
- Select the app returned by App Store Connect.
- Confirm the numeric Apple App ID and bundle ID.
- Create the SubKit app.
If the app is missing, check the App Store Connect user’s app access and the workspace capability results. Do not create a second Apple app or change the bundle ID as a workaround.
4. Configure subscriptions in App Store Connect
For auto-renewable subscriptions:
- Open the app in App Store Connect.
- Under Monetization → Subscriptions, create a subscription group.
- Create one subscription product for each purchasable duration or tier.
- For every subscription, configure:
- a stable Product ID;
- subscription duration;
- price;
- country and region availability;
- localization;
- review notes and a review screenshot.
- Put products that grant the same service at the appropriate subscription level.
- Save all metadata.
Apple-specific rules to account for:
- The first auto-renewable subscription and first subscription group must be submitted with a new app version. Add them to the version under In-App Purchases and Subscriptions.
- Product metadata changes can take up to one hour to appear in Sandbox.
- Do not reuse an existing Product ID for commercially different terms.
5. Model the Apple catalog in SubKit
SubKit owns the catalog and the resulting access rules. Apple hosts the native purchase product.
- Create the entitlement the app checks, for example
pro. - Create the product and its plan.
- Create an immutable plan version with its term, prices, entitlement rules, and pool/capacity rules.
- Enable the Apple sales channel on that plan version.
- Add Apple store bindings for both Production and Sandbox using the matching Apple Product ID.
- Publish the plan version.
- Add it to a published offering.
- In App settings, create or rotate the single public SDK key used by the app.
Production and Sandbox are separate bindings even when their Apple Product ID is identical. SubKit serves the Apple identifier only when the visible bindings are consistent. The app must not carry a fallback Product ID or price.
See Catalog for the Product → Plan → Plan Version → Offering → Store Binding model.
6. Configure App Store Server Notifications V2
In App Store Connect, open App Information → App Store Server Notifications and configure:
Production Server URL:
https://<subkit-host>/api/stores/apple/notifications
Sandbox Server URL:
https://<subkit-host>/api/stores/apple/notifications
Version: 2Use a public HTTPS URL with a valid certificate. Configure both environments explicitly, even when they use the same SubKit endpoint.
Do not add a shared secret in a query string. SubKit verifies Apple’s signed V2 payload, certificate chain, bundle ID, environment, and embedded transaction before it changes access.
The initial in-app reconcile can verify a purchase before a Server Notification arrives. Notifications are still required for the complete lifecycle: renewal, cancellation, expiration, refund, and revocation.
7. Prepare Apple Sandbox testing
- Open Users and Access → Sandbox in App Store Connect.
- Create a Sandbox Apple Account with an email address that has never been used as a regular Apple Account.
- Choose the storefront you want to test.
- Enable Developer Mode on the test device when using a development-signed build.
- Install a development build or TestFlight build with:
- the expected bundle ID;
- a device-reachable SubKit API URL;
- the public app-bound SDK key.
- Sign in through the device’s Sandbox purchase-account setting. You do not need to sign out of the device’s personal Apple Account for IAP testing.
Current device navigation varies by iOS version. On current releases, look under Settings → Developer → Sandbox Apple Account. If the option is not visible, start a purchase in a development build and Apple will prompt for the Sandbox credentials.
Apple Sandbox can be slow; a purchase sheet or completed purchase may take 15 seconds or longer. TestFlight also uses Sandbox purchases even though the tester signs in with a regular Apple Account, and its renewal timing can differ from a development-build Sandbox test.
Xcode StoreKit Testing is useful for early client and UI tests. It does not replace an Apple Sandbox transaction when you need evidence from Apple’s server API and App Store Server Notifications. Local StoreKit testing also cannot prove that Apple lifecycle notifications reach SubKit.
8. Verify the full flow
Run the purchase through the normal app UI:
- Identify an app user.
- Load the offering.
- Confirm the package has a native Apple
storeProductand localized price. - Purchase the package through the Apple Sandbox sheet.
- Wait for SubKit to verify and persist the transaction.
- Unlock only when the expected entitlement is active.
- Confirm the verified transaction and active entitlement appear in the SubKit Console before treating the test as successful.
- Restart the app and test Restore purchases.
- Exercise renewal, cancellation, and expiration and confirm notifications update the same access chain.
Deleting an App User or local app data does not delete the purchase from Apple. Use a new Sandbox account when you need a genuinely clean purchase history.
A successful purchase produces the store-agnostic chain:
Verified Store Subscription
→ Access Source
→ Access Pool
→ Access Allocation
→ derived Entitlement GrantThe app checks the entitlement — never the Apple Product ID, subscription group, or local StoreKit transaction state.
Verification checklist
- App Store Connect catalog credentials validate in SubKit.
- A real Sandbox transaction proves the uploaded Apple credential can call the App Store Server API; otherwise production remains blocked.
- Apple App ID and bundle ID match in Apple, the app build, and SubKit.
- Every subscription has price, availability, localization, and review metadata.
- The first subscription is attached to a new app version when required.
- Production and Sandbox bindings use the intended Product IDs.
- The plan version and offering are published.
- The app contains only the public SubKit SDK key.
- Production and Sandbox notification URLs use V2 over public HTTPS.
- A Sandbox purchase activates access only after SubKit verification.
- Restore and notification retries do not create duplicate sources or grants.
Failure modes
| Symptom | Check first |
|---|---|
| App is missing in SubKit | API-key user app access and workspace capability results |
| Offering has no Apple store product | Published plan version, Apple sales channel, both bindings, and offering membership |
SKU not found |
Product metadata, availability, first-subscription version attachment, and propagation delay |
| Purchase sheet succeeds but access stays locked | Apple credential type, App Store Server API access, Bundle/Product match, app-user identity, and entitlement rule |
| Product fails only for one tester/device | Sandbox account, storefront, build bundle ID, and device purchase-account sign-in |
| Cancellation or expiry never reaches SubKit | Public notification URLs, V2 selection, HTTPS certificate, and Store Event delivery |
| Notification returns HTTP 400 | Signed payload, bundle/app mapping, environment, and embedded transaction validation |
Never bypass failed verification or grant access manually to make a Store test pass. Correct the provider or catalog mapping and repeat the test.