subscribed

Learn about the SUBSCRIBED App Store Server Notification V2. Fired when a customer subscribes for the first time or re-subscribes after expiration.

App Store Server Notifications V2Subscriptions
subscribed

The SUBSCRIBED notification fires when a customer subscribes to an auto-renewable subscription for the first time, or re-subscribes after their subscription has expired. This is the starting point of the subscription lifecycle.


When does it fire?


This notification triggers in two scenarios:


  • Initial subscription — a customer purchases an auto-renewable subscription for the first time
  • Resubscription — a customer whose subscription has expired subscribes again (distinct from a renewal)

The notification includes a subtype that differentiates between INITIAL_BUY and RESUBSCRIBE.


Payload highlights


The signed transaction info includes the product ID, the subscription group ID, the purchase date, the expiration date, the offer type (if any), and the storefront (country). The signed renewal info shows the auto-renew status and the expected next renewal date.


How Yeethook helps


Yeethook parses the signed JWT payloads (JWS transactions) and formats them into readable Slack or Discord messages. Instead of decoding Base64-encoded JWTs, you see the product name, price, country, and subscription period at a glance.


Common use cases


  • Track new subscriber acquisition in real-time
  • Monitor re-subscription rates for win-back campaign effectiveness
  • Alert your revenue team when high-value subscriptions are purchased
  • Segment new vs. returning subscribers for analytics

Example payload

Apple POSTs `{ "signedPayload": "<JWS>" }`; this is the decoded body. The product, price and trial details are not here — they sit one level deeper, inside the signedTransactionInfo JWS, which has to be decoded separately.

{
  "notificationType": "SUBSCRIBED",
  "subtype": "INITIAL_BUY",
  "notificationUUID": "6b4f2c81-7d3a-4e59-9c0f-13a8b5d72e04",
  "version": "2.0",
  "signedDate": 1789198453000,
  "data": {
    "appAppleId": 1234567890,
    "bundleId": "com.example.app",
    "bundleVersion": "142",
    "environment": "Production",
    "signedTransactionInfo": "eyJhbGciOiJFUzI1NiIsIng1YyI6...",
    "signedRenewalInfo": "eyJhbGciOiJFUzI1NiIsIng1YyI6...",
    "status": 1
  }
}

What it looks like in Slack

Success

New subscription

Product
com.example.app.pro.monthly
Price
9.99 USD
Transaction
2000000712345678
Offer type
Introductory
Expires
2026-10-12T09:34:13.000Z
Auto-renew
On
Subscription status
Active
Environment
Production

The same event arrives with different values depending on what changed. Yeethook rewrites the headline to match:

  • RESUBSCRIBE→ Re-subscription

Questions about subscribed

Does SUBSCRIBED fire again when the subscription renews?

No. SUBSCRIBED only carries the subtypes INITIAL_BUY and RESUBSCRIBE, so it marks the start of a subscription rather than the continuation of one. Every subsequent billing period arrives as DID_RENEW instead.

How do I tell a free trial apart from a paid first period?

Check offerType in the decoded transaction: 1 means an introductory offer, which covers free trials, pay-as-you-go and pay-up-front. Yeethook renders that as an Offer type row reading Introductory, and the row is simply absent when the customer paid full price.

Why does the decoded payload not contain the product ID?

The data object only carries app-level identifiers and a status code. productId, price, currency and expiresDate live inside data.signedTransactionInfo, which is itself a JWS, so reading them needs a second base64 decode of that string.

Do Sandbox subscriptions send the same notification?

Yes, with environment set to Sandbox instead of Production. Sandbox billing periods are compressed — a one-month subscription renews every five minutes and a one-year subscription every hour — so a single test purchase produces a fast stream of DID_RENEW events after this one.

Get this event in Slack or Discord

Connect Yeethook to receive subscribed notifications in your team's Slack or Discord channels.

Get Started Free