Crossdeck University
Watch — keys once, apps in seconds, one line at purchase Film in production
0:00 / 0:00
Lesson 2 of 4 · Connect your revenue

Connect Apple App Store

Apple has more moving parts than Stripe, but the same shape: dashboard setup plus one line at purchase. Enter your keys once, connect each app in seconds, and add the StoreKit option that says who's buying.

6 min Dashboard · Swift

When you're done: an App Store purchase lands on the right Crossdeck customer and grants their entitlement.

1 What this is & why it matters

Your Apple keys are account-level — set them up once

Here's the part that saves you time: your Apple credentials — the issuer ID, two API key IDs, and two .p8 files — authenticate every app under your Apple Developer account. You enter them a single time. After that, connecting an app needs only its Bundle ID and App Store ID, and Crossdeck pre-fills both from onboarding. One app or ten, you set up keys once.

Two keys, two jobs: the App Store Server API key handles transactions and subscription status; the App Store Connect API key reads your product catalog. Apple splits these across two APIs, so your account holds one of each. And as with Stripe, the line of code at purchase time is the part that decides whether a sale finds the right person — that's the piece to get right.

2 How to connect it

Keys once, app in seconds, one option at purchase

Three steps, and only the last one is code:

1 · Set up your account (once). In the dashboard, enter the issuer ID, both API key IDs, and both .p8 files. Crossdeck verifies them live with Apple and stores them as your account. Keys live in Google Cloud Secret Manager — never in Firestore, never in a bundle.

2 · Connect an app (every time after). Confirm the app's Bundle ID and App Store ID, then paste that app's appleWebhook/{projectId} URL into App Store Connect as both the Production and Sandbox V2 URL. Each app has its own webhook URL.

3 · Tell Crossdeck who's buying. At purchase time, attach the current identity's token to the StoreKit purchase:

// the UUID bound to the user you identify()'d — never nil
let token = Crossdeck.appAccountTokenForCurrentIdentity()

let result = try await product.purchase(options: [
    .appAccountToken(token)
])
3 How the code works, piece by piece

One UUID, baked into the transaction

appAccountTokenForCurrentIdentity() returns the UUID bound to the user you passed to identify() — and it never returns nil. If someone buys before they've signed in, it mints a stable UUID, persists it on the device, and returns that; when they identify later, the purchase stitches onto them. StoreKit bakes the UUID into the transaction, Apple's server notification carries it back, and Crossdeck reads it to attach the subscription to that exact customer.

Leave the option off and the App Store purchase still arrives — but tokenless, so it orphans as a rail-only customer that has to be reconciled by hand later. And a worry this design removes: shared keys never leak revenue between your apps. Each app's webhook is its own URL, and Apple's SignedDataVerifier binds every transaction to that app's own Bundle ID — a transaction meant for another app is rejected outright.

4 The green result in your dashboard

The sandbox purchase lands on the right customer

Run a sandbox purchase. The subscription appears on the customer you identified, and the entitlement it grants is live — ready for your gate to read, the same way Stripe's did.

app.cross-deck.com · customer timeline
apple sub · attached

user_847's App Store subscription, matched by appAccountToken — entitlement live. No tokenless orphan.

Apple keys are account-level — enter them once, then each app connects with its Bundle ID, App Store ID, and its own V2 webhook URL. At purchase, attach appAccountTokenForCurrentIdentity() so the sale finds the right person. Shared keys never cross apps — SignedDataVerifier binds each transaction to its Bundle ID.