Wire Apple App Store Server Notifications v2 to LinkJolt. Offer-code attribution. No SDK.
15 min read
DID_RENEWis_test=trueApp Store Server Notifications v2 (ASSN v2) is Apple's server-to-server event stream for subscription lifecycle events. Each notification arrives at your configured URL as a JSON body containing a single signedPayload field — a JWS signed with Apple's certificate chain rooted at Apple Root CA - G3.
LinkJolt runs a dedicated endpoint per merchant. You never implement the verification yourself — paste the URL into App Store Connect and we handle the JWS chain check, event mapping, and conversion insertion.
Go to Integration Hub → Other Platforms → Apple In-App Purchases and enter:
com.example.app). Required. Used to validate bundleId inside Apple's signed payload.1234567890). Required for Production notification verification. Optional if you're only testing in Sandbox.Both values appear in App Store Connect → My Apps → [your app] → App Information.
From your LinkJolt Apple IAP setup screen, copy the Production and Sandbox URLs. The shape is:
# Production
https://linkjolt.io/api/webhooks/apple-iap/<your-merchant-user-id>
# Sandbox
https://linkjolt.io/api/webhooks/apple-iap/<your-merchant-user-id>/sandboxIn App Store Connect: General → App Information → scroll to App Store Server Notifications. For each URL field:
Offer codes are Apple's officially-supported attribution mechanism for “influencer partnerships with exclusive codes” and “co-marketing partnerships” (Apple's own words).
In App Store Connect:
Limits: up to 25,000 codes per batch; up to 1,000,000 redemptions per app per quarter.
For each offer code, register it against a campaign and affiliate via the LinkJolt dashboard or the Developer API:
curl https://linkjolt.io/api/coupons \
-H "Content-Type: application/json" \
-d '{
"provider": "apple",
"code": "PARTNER_JEN",
"campaignId": "cmp_...",
"affiliateId": "aff_..."
}'Apple offer identifiers are case-sensitive — register them exactly as you configured them in App Store Connect.
LinkJolt automatically handles all subscription lifecycle events:
SUBSCRIBED (INITIAL_BUY / RESUBSCRIBE) — inserts a new conversion, attributes to the affiliate matching offerIdentifier.DID_RENEW — inserts a recurring conversion linked to the parent via originalTransactionId. Requires recurring commissions enabled on the campaign.REFUND / REVOKE — marks the matching conversion as rejected.REFUND_REVERSED — reverts rejection back to pending so you can re-approve.EXPIRED, DID_FAIL_TO_RENEW, PRICE_INCREASE, RENEWAL_EXTENDED, DID_CHANGE_RENEWAL_PREF, DID_CHANGE_RENEWAL_STATUS, GRACE_PERIOD_EXPIRED, OFFER_REDEEMED — logged, no commission side-effects.End-to-end sandbox flow:
SUBSCRIBED notification to your Sandbox URLis_test=true, and shows it in your dashboard under “Test data”To exercise the webhook without a real purchase, Apple's POST /inApps/v1/notifications/test endpoint fires a signed TEST notification. Requires a signed JWT with your App Store Connect API key — see Apple's Request a Test Notification docs.
Apple retries failed deliveries 5 times over 72 hours (at 1h, 12h, 24h, 48h, 72h). LinkJolt always returns HTTP 200 for handled or intentionally-ignored events, and 500 only on transient database errors — Apple retries those legitimately. Idempotency is enforced by a unique index on conversions.order_id (= Apple's transactionId), so duplicate deliveries are safe. Sandbox notifications are not retried.
Offer-code attribution is deterministic and 100% accurate on redemption. It does not attempt ambient click-to-install-to-purchase attribution — that requires an MMP and is probabilistic post-ATT on iOS. For indie subscription apps, offer codes are the more honest and higher-quality signal. If a user buys your subscription without redeeming an affiliate code, that conversion is recorded but unattributed.