Attribution & revenue setup

Connect ASAPilot to your app

Real per-keyword ROAS needs three independent signals joined server-side: Apple Ads spend (already connected via OAuth), AdServices attribution (this guide, step 1) and revenue events (step 2). Ten minutes, one app build.

How it works

Your iOS app sends us the Apple AdServices token after install. We resolve it against Apple and learn that user X arrived from campaign C / keyword K. Independently, your revenue source (RevenueCat or any custom webhook) tells us user X paid €9.99. We join the two by appUserId — so the only contract that matters is that the same appUserId is used on both sides.

1

Send the AdServices attribution token

From your iOS / Flutter app, POST the AdServices token to ASAPilot whenever the app enters the foreground. Grab the endpoint and publicWriteKey from the ASAPilot app, under Settings → Revenue & attribution → Step 1.

AI agent shortcut Recommended

Skip the manual code. Copy the prompt below and paste it into Claude, Cursor, ChatGPT, or any coding agent — it will wire the full integration into your codebase using the right pattern (lifecycle retry, per-appUserId dedup, status-code handling).

Give this prompt to your agent to configure your application. It already includes the endpoint and key placeholders — replace them with the real values from the ASAPilot app before pasting the code.

Prefer to do it by hand? — minimal snippet

Bare-bones HTTP contract — not production-ready (no retry, no dedup). Use only as a reference; ship the AI-generated version above.

POST <endpoint>
Authorization: Bearer <publicWriteKey>
Content-Type: application/json

{
  "appUserId": "",
  "platform": "ios",
  "attributionToken": "",
  "sentAt": ""
}

Reply 202 → queued for resolution. ASAPilot calls Apple in the background, retries 404s for ~22s, then stores the resolved attribution under your user tree.

Best practices, in 3 lines:

Fire on every foreground, not only at cold launch — Apple's AdServices API can return 404 for ~30s post-install.

Use Purchases.appUserID verbatim (anonymous or post-login). ASAPilot links anonymous → logged-in via RevenueCat aliases.

Mark "sent" only after HTTP 2xx, with a key scoped to that appUserId. Anything else retries on next foreground.

The most important rule: the appUserId you send here MUST match the user id you use in your revenue source (RevenueCat's app_user_id or your backend's user id). The join is by string equality — if they don't match, attribution lands in the unattributed bucket and per-campaign ROAS stays empty.
2

Send revenue events

We need a notification whenever a user pays. RevenueCat is zero-code — if you already use it, you're 90% done. If not, post canonical events to the same webhook URL from any backend.

Option A — RevenueCat
Recommended
  1. In RevenueCat go to Project → Integrations → Webhooks → Add new configuration.
  2. Paste the URL and Authorization header shown in the ASAPilot app under Settings → Revenue & attribution → Step 2.
  3. Enable both Production and Sandbox.

Make sure RevenueCat's app_user_id matches the appUserId from Step 1.

Option B — your own backend

POST canonical events to the same webhook URL with the same Bearer header. Useful when you bill via Stripe, App Store Server Notifications, custom subscription server, etc.

POST <your-webhook-url>
Authorization: Bearer <your-token>
Content-Type: application/json

{
  "type": "PURCHASE",
  "amount": 4.99,
  "currency": "EUR",
  "occurredAt": "2026-05-31T10:00:00Z",
  "appUserId": "user_123",
  "externalId": "order_abc"
}

Accepted type: PURCHASE, RENEWAL, REFUND, TEST. The externalId is used for idempotency — safe to retry. The appUserId must match Step 1.

3

Verify it's working

Open the ASAPilot app on a real device (the iOS Simulator can't mint AdServices tokens) and run your client app at least once with the snippet from Step 1. Then in ASAPilot go to Settings → Revenue & attribution → Step 3:

  • Last attribution received turns green within a couple of minutes of the first install.
  • Last revenue event turns green as soon as RevenueCat fires its test ping (or your backend posts its first event).
Troubleshooting
  • Token nil on simulator. Expected. AdServices only works on real iOS 14.3+ devices.
  • 404 from Apple for ~30s after install. Apple's attribution graph is still indexing. We retry server-side with backoff — you don't need to do anything.
  • ROAS stays 0 even though revenue is coming in. Check that appUserId in Step 1 matches the user id your revenue source uses. Most setup mistakes are here.
  • App Tracking Transparency. Not required for standard attribution. If you want clickDate / impressionDate you'll need to ask for ATT consent and pass it through.