Documentation
Revenue

Connect Apple (native)

Connect native Apple purchases to FounderHQ.

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.

Before you start

You need a FounderHQ brand, the FounderHQ SDK in your app (iOS or React Native), and an App Store Connect account with the Admin or Account Holder role.

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:

ValueWhere it comes fromExample
Bundle IDYour app's bundle identifiercom.acme.afteryou
Apple app IDThe numeric app ID in App Store Connect1234567890
Issuer IDAbove the key list on the In-App Purchase pagea UUID
Key IDBeside the In-App Purchase key you createdABC123DEFG

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:

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

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.

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:

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.

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.

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:

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.

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.

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.

AI agent or LLM? Read this page as markdown

On this page