# Connect Apple (native) (https://www.getfounderhq.com/docs/analytics/revenue/connect-apple)

Connect the App Store directly, with no aggregator in between. FounderHQ then
reads Apple's own notifications and Apple's own transaction records. Allow
about fifteen minutes.

<Callout title="Before you start">
  You need a [FounderHQ brand](/analytics/getting-started), the FounderHQ SDK in
  your app ([iOS](/analytics/sdks/ios) or [React
  Native](/analytics/sdks/react-native)), and an App Store Connect account with
  the Admin or Account Holder role.
</Callout>

## 1. Create an In-App Purchase key

In App Store Connect, open **Users and Access → Integrations → In-App
Purchase**. Create a key there — not an App Store Connect API team key — and
download the `.p8` file. Apple lets you download it once.

Collect these values while you are on that page and in your app's settings:

| Value        | Where it comes from                              | Example             |
| ------------ | ------------------------------------------------ | ------------------- |
| Bundle ID    | Your app's bundle identifier                     | `com.acme.afteryou` |
| Apple app ID | The numeric app ID in App Store Connect          | `1234567890`        |
| Issuer ID    | Above the key list on the In-App Purchase page   | a UUID              |
| Key ID       | Beside the In-App Purchase key you created       | `ABC123DEFG`        |

## 2. Create the connection in FounderHQ

In FounderHQ, open **Settings → Integrations → Revenue**. Choose the brand,
then Apple App Store. Enter the four values above, and paste the contents of
the `.p8` file. FounderHQ encrypts the key and signs its App Store Server API
calls with it, so it can fetch the authoritative transaction behind every
notification.

FounderHQ then gives you a notification URL:

```text
https://app.getfounderhq.com/api/hooks/payments/apple_native/CONNECTION_ID
```

## 3. Set the notification URL in App Store Connect

Open your app's **App Information** page and find **App Store Server
Notifications**. Paste the FounderHQ URL as the Production Server URL.

New apps get **Version 2** automatically — Apple no longer offers Version 1 to
them. If Apple shows a version choice on an older app, pick Version 2.

## 4. Ask Apple for a test notification

Back in FounderHQ, click **Ask Apple to send a test**. App Store Connect has
no button for this — FounderHQ signs the request with your key and Apple
delivers a signed test notification, usually within a minute. The connection
shows **Connected** the moment it arrives. No payment is needed.

FounderHQ verifies Apple's signature chain, the bundle ID, and the environment
on every notification. It handles these notification types:

```text
SUBSCRIBED                DID_RENEW                 ONE_TIME_CHARGE
REFUND                    REFUND_REVERSED           REFUND_DECLINED
DID_CHANGE_RENEWAL_PREF   DID_CHANGE_RENEWAL_STATUS DID_FAIL_TO_RENEW
GRACE_PERIOD_EXPIRED      EXPIRED                   REVOKE
OFFER_REDEEMED            PRICE_INCREASE            CONSUMPTION_REQUEST
RENEWAL_EXTENDED          RENEWAL_EXTENSION
```

Purchases, renewals, and refunds move money. Renewal-preference changes, grace
periods, and price increases update state only.

## Notification history: the safety net

Apple keeps a record of every notification it tried to deliver for your app.
FounderHQ reads that record on a schedule with the same key you already
pasted, and checks every signature again.

Two things follow:

- **A short outage costs you nothing.** If a notification never reached
  FounderHQ, the next read picks it up. Apple's own dates are kept, so a
  purchase lands on the day it happened, not the day we read it.
- **You do not have to move your notification URL.** App Store Connect holds
  one URL. If RevenueCat, Superwall, or another tool already has it, leave it
  there — Apple's history records what it sent to them, and FounderHQ reads
  the same stream. Skip step 3 and connect with the key alone.

You can also read now instead of waiting: open the connection's menu and
choose **Sync now**.

<Callout title="Your other tool keeps working">
  Nothing changes for the tool that holds the URL. FounderHQ never asks Apple
  to send anywhere else, and never touches your subscription setup.
</Callout>

## 5. Pass the FounderHQ token on every purchase

Apple carries one UUID through the purchase and returns it on the notification.
FounderHQ uses it to find the buyer. Ask the SDK for it, then hand it to
StoreKit as `appAccountToken`:

```ts
const prepared = await founderhq.preparePurchase({ source: "app_store" });
// Pass prepared.appAccountToken to your StoreKit purchase as appAccountToken.
await founderhq.observePurchase({
  prepared,
  purchase: {
    source: "app_store",
    transactionId: transaction.id,
    originalTransactionId: transaction.originalID,
  },
});
```

On iOS, `purchase(_:options:)` adds the token for you. See
[mobile purchase claims](/analytics/revenue/mobile-purchase-claims).

## Already reporting this app through RevenueCat or Superwall?

Connect Apple anyway. FounderHQ allows it, and from that moment Apple's
amounts, taxes, and dates own the money for this app. The other connection
stays where it is: its events are kept as evidence and add nothing to your
totals, so nothing counts twice during the switch, and everything already
recorded stays in your reports. See
[multiple providers](/analytics/revenue/multiple-providers).

## Verify

1. The connection shows **Connected** after Apple's test notification (step 4)
   arrives.
2. When the next real purchase happens in your app, open Revenue in FounderHQ.
   The purchase shows the channel that brought the customer.

## Troubleshoot

### The connection stays on "Waiting for test"

Apple has not delivered a notification yet. Confirm the URL is saved in App
Store Connect, then click **Ask Apple to send a test** again. A new URL can
take a few minutes to register on Apple's side.

### FounderHQ rejects the notification

The bundle ID on the connection differs from the bundle ID inside Apple's
signed payload, or a Sandbox notification reached a live connection. Fix the
value that does not match.

### Purchases arrive without a channel

The app bought without a prepared token. Call `preparePurchase` before every
purchase, and pass the returned `appAccountToken` to StoreKit.
