WWDC Quick Look 💓 By SwiftGGTeam
Architecting for subscriptions

Architecting for subscriptions

Watch original video

Highlight

Apple recommends converging subscription permission judgment to the server-side entitlement engine, using receipts, server-to-server notifications and business context to calculate user status, and then safely returning the simplified entitlement payload to the client.

Core Content

Many subscription systems only ask one question at first: does this user have permissions now? Generally speaking, the implementationproduct_idandexpires_date. If the expiration date is in the future, it will be unlocked, and if the expiry date is in the past, it will be locked.

This model will soon become ineffective. The user may cancel the automatic renewal, but the current period of service has not ended; the deduction may also fail, and Apple continues to try to charge in the Billing Retry; if the app turns on the Grace Period, the user should still receive the service during the grace period. By only looking at active or inactive, you’ll miss opportunities for retention, payment fixes, and upgrade prompts.

The answer given in this session is the server-side entitlement engine. It organizes receipts, server-to-server notifications, subscription products, and business context into a simple result: whether the user can access the service, what status it is in, and what message or action entry the client should display.

The advantage of this is that responsibilities are clear. The client is responsible for initiating purchases, displaying rights, and receiving the entitlement payload returned by the server; the server is responsible for verifying receipts, merging notifications, maintaining status, and recalculating permissions when the status changes. If you add new products, new offers or new billing status after subscribing to the business, you can also change the server logic first without waiting for the client to be released.

Detailed Content

Modeling states from subscription journeys

(01:21) The speech first dismantles the dichotomy of active/inactive. After a one-month subscription is purchased on May 1st, it may be renewed normally, or the automatic renewal may be cancelled, the subscription may be restored after failed deduction, the subscription may enter Billing Retry, or be restored within the Grace Period. Each path changes the state that the server should save and the experience that the client should give.

Key points:

  • The initial purchase will trigger the server-to-server notification of initial buy.
  • After the user turns off automatic renewal, the service can still be used in the current period, but it will be passed in the future.expires_dateandexpiration_intentShows active attrition.
  • Billing Retry indicates that Apple is still trying to collect payment and the client is suitable to guide the user to update App Store payment information.
  • Restoring within the Grace Period can maintain the continuity of the original billing date, and the app should continue to provide services and prompt the remaining time.

Feed the entitlement engine with receipts and notifications

(11:43) Apple calls this set of server-side logic the entitlement engine. Input includes receipts, server notifications, and user context held by the app itself. The output is a simplified JSON payload that updates the user database and can be safely returned to the device.

Key points:

  • App receipt is the source of fact for checking transaction data. The first step is to verify the authenticity of each receipt.
  • If the initial receipt has expired, the server should report to the App StoreverifyReceiptThe endpoint requests the latest receipt info.
  • Subscription data is scattered acrosslatest_receipt_infopending_renewal_infofields, the engine needs to combine them into actionable information.
  • If the subscription spans multiple apps or platforms, the server must also merge the status other than receipt to prevent users from being repeatedly sold or locked incorrectly.

Compress status into cohort and entitlement code

(15:35) The middle layer of the engine first defines subscriber cohorts, and then converges a bunch of receipt fields into business status. The example in the speech assigns the status to a numerical value. A positive value means that the service can be unlocked, and a negative value means that the service should not be provided for the product; substate uses the decimal part to distinguish product contexts such as free trials and subscription offers.

Key points:

  • cohort allows the server to turn complex field combinations into stable business signals.
  • The entitlement code can be saved to the server or sent to the client as a simple signal.
  • The same positive value not only represents “unlocked”, but also represents a more detailed status, such as auto-renewal being turned off during the free trial period.
  • This coding method is just an example, the actual product can be extended with its own subscription tiers, promotion strategies and billing status.

Attach actions to different states

(17:48) When the response object already contains entitlement information, the server can attach actions based on the status. The speech listed several typical scenarios: when the user turns off automatic renewal, the offer is retained; during the grace period, the service continues to be unlocked and reminded to renew the payment; in the billing retry, limited access is provided and guided to repair the bill; expired users receive a win-back offer; users who pay monthly for continuous renewal see annual payment upgrade suggestions.

Key points:

  • The entitlement response is not just a boolean value, but can also carry a message, offer, or next action.
  • Grace Period and Billing Retry have similar goals of repairing payments, but have different service permissions.
  • Win-back push still requires a deep link to the appropriate payment page within the app.
  • Upgrade suggestions can be combined with the number of renewals and subscription group ID to recommend annual-paying products to loyal monthly-paying users.

Architecture iteration from stateless requests to persistence system

(19:55) Apple recommends making the entitlement engine a highly available service so that the latest permissions can be calculated immediately when status changes occur. The minimum implementation can first let the device send the receipt to the server for processing every time it makes a request. This version can support many subscription functions and can also be used as a fallback path when storage exceptions or notifications are missed.

Key points:

  • After the engine is placed on the server, errors in the permission logic can be tested using receipt or mock receipt data, and then directly deployed to fix them.
  • When only making stateless requests, the device must send a receipt every time; without persistent receipt data, it is difficult to support access from the web or other platforms.
  • After adding persistent storage, the server can save receipt data and entitlement info, and support web and off-platform access.
  • After adding the App Store Server Notifications endpoint, the server can be notified when the subscription status changes, reducing the need forverifyReceiptEndpoint polling.
  • If the client requests entitlement data, the speech recommends considering using JSON Web Signature to prove that the data comes from your own server.

Core Takeaways

  • Subscription Status Console: What it does: Display each user’s subscription state, substate, recent receipt fields, and server notification timeline for customer service, operations, and engineering teams. Why it’s worth doing: Session repeatedly emphasizes that status comes from multiple receipt fields and user behaviors. The console can reduce the cost of troubleshooting “why the user is locked”. How to start: press firstlatest_receipt_infopending_renewal_infoGenerate a read-only timeline with notification events, and then map the entitlement code to a status label that can be read by adults.
  • Payment Repair Portal: What to do: Show different payment repair prompts in Billing Retry and Grace Period. Why it’s worth doing: Billing Retry is suitable for guiding the update of payment information, and Grace Period also displays the remaining time of the service. How to start: Let the entitlement response carry the billing action, whether the service will continue to be open, and the remaining information of the grace period, and then deep link the client to the App Store account payment settings.
  • Retention offer after cancellation of renewal: What to do: Identify users who are still in the validity period but have turned off auto-renewal and display a retention offer or subsequent subscription offer. Why it’s worth doing: The retention example given in the speech uses auto-renewal status and current subscription products to achieve retention. How to start: Add a retention message to the active cohort with auto-renew off in the entitlement engine, and let the paywall only display in this state.
  • Annual payment upgrade recommendation for loyal users: What to do: Guide monthly paying users who have renewed their subscriptions for multiple periods to annual payment subscriptions. Why it’s worth doing: Session recommends using the number of renewals and subscription group ID to identify loyal users and then provide discounted upgrades. How to start: Aggregate the renewal count for the same subscription group on the server side, and add the annual upgrade action to the entitlement payload after reaching the threshold.
  • Cross-platform entitlement wrapper: What to do: Let iOS, web, and other platforms all request the same server-side entitlement endpoint. Why it’s worth doing: The speech pointed out that only after receipt data is persisted can web and off-platform access be supported, and the stored data can be used to maintain accuracy when notifications are missed. How to start: First implement the stateless interface for sending receipts from the device, and then gradually add receipt storage, notification endpoint and database synchronization process.

Comments

GitHub Issues · utterances