Highlight
Apple added Get Transaction Info endpoint to App Store Server API at WWDC23, added subscription status field and onlyFailures filter to Notifications V2, and officially abandoned verifyReceipt and Notifications V1, promoting developers to migrate to a more modern JWS signature data system.
Core Content
Use transactionId to directly query a single transaction
Previously, validating a transaction on the server required calling Get Transaction History and then digging through multiple pages of results to find matching records. If the user has a long transaction history, this process is slow and cumbersome. To make matters more troubling, completed consumption transactions will not appear in the response to Get Transaction History, making it impossible to verify consumption transactions.
(03:12) Apple has introduced a new Get Transaction Info endpoint. You only need to provide a transactionId to directly obtain the signature information of the transaction. All types of transaction IDs are supported, including completed consumption transactions.
The calling method is very simple:
GET https://api.storekit.itunes.apple.com/inApps/v1/transactions/{transactionId}
The response contains the signedTransactionInfo field, which can be decoded to view the complete information of the transaction.
(06:32) Another convenience update: Core endpoints that previously required originalTransactionId as path parameters (such as Get Transaction History, Get All Subscription Statuses) now support the use of any transactionId. You no longer need to use Get Transaction Info to convert the ID first, you can call it directly.
Subscription status is clear at a glance
(07:42) Tracking subscription status is a core requirement for subscription-based applications. Notifications V2 will send events when the subscription status changes, but some notification types cannot directly tell you the current status.
For example, when receiving a REFUND notification, you cannot directly determine whether the subscription has been revoked. If the user has a newer renewal transaction under the same originalTransactionId, the subscription status may still be Active. It is impossible to make a correct judgment based on notification data alone.
(10:22) Apple added a new status field in the data object of Notifications V2. This is an integer that directly represents one of the five core states of the subscription. Every notification related to an auto-renewing subscription will contain this field, and the server no longer needs to make additional API calls to confirm the status.
Get only failure notifications
(11:36) When the server fails, the App Store may not be able to successfully send notifications. The Get Notification History endpoint allows you to request V2 notifications from the past six months, which can be used to recover missed notifications.
But here’s the thing: Even if the server is running normally, you may occasionally miss individual notifications due to transient network issues. In this case, you don’t have a clear time window to query, and you can only look through a large number of received notifications to find any omissions.
(12:30) Apple added a new onlyFailures request field to Get Notification History. When enabled, the response will only include notifications that were not successfully delivered to your server, including notifications that are in the process of being retried.
Request example:
{
"onlyFailures": true
}
Each notification entry in the response contains a sendAttempts array recording the results of each send attempt. If subsequent retries are successful, the notification will no longer appear in the query results for onlyFailures.
verifyReceipt is officially obsolete
(14:44) Apple announced that the verifyReceipt endpoint and App Store Server Notifications V1 are officially deprecated. These two APIs will no longer receive updates for new features.
Migrating to the App Store Server API requires three steps:
- Generate a JWT to represent your app’s identity
- Save a transactionId for each user
- Call the core endpoint using transactionId
Migrating to Notifications V2 is easier:
- Prepare the server to parse the V2 format (using the same JWS transaction format as the Server API)
- Switch notification preferences from V1 to V2 in App Store Connect
- Test V2 notifications in a sandbox environment first
(19:35) Apple also released the App Store Server Library, an open source library that supports Swift, Java, Node.js, and Python to help developers more easily call APIs, verify signature data, and extract transactionIds from receipts to simplify migrations.
Detailed Content
Get Transaction Info endpoint details
(05:47) The new Get Transaction Info endpoint solves the pain point of server-side verification of individual transactions.
Request format:
GET /inApps/v1/transactions/{transactionId}
Authorization: Bearer {JWT}
Response format:
{
"signedTransactionInfo": "eyJhbGciOiJFUzI1Ni..."
}
Key points:
signedTransactionInfois the signed transaction data in JWS format- After decoding, complete transaction information can be obtained, including productId, purchaseDate, type, etc.
- Supports all transaction types: consumable, non-consumable, automatically renewing subscription, non-renewable subscription
- Supports completed and uncompleted transactions
Status field of Notifications V2
(10:30) The status field is an integer, corresponding to five subscription statuses:
| Value | Status | Meaning |
|---|---|---|
| 1 | Active | Subscription is active |
| 2 | Expired | Subscription has expired |
| 3 | Billing Retry | Billing retrying |
| 4 | Billing Grace Period | Billing Grace Period |
| 5 | Revoked | Subscription revoked |
This field appears in all notifications related to automatically renewing subscriptions. When receiving a REFUND notification, check status directly to see if content access needs to be disabled.
Usage scenarios of onlyFailures
(13:08)onlyFailures field solves two scenarios:
- Known server failure: Recover the server after it is down, and query the notifications missed during the failure.
- Unknown network problem: Occasionally missing individual notifications during daily operation, quickly locate missing items
{
"startDate": 1686000000000,
"endDate": 1686086400000,
"onlyFailures": true
}
The notificationHistory array in the response contains only failed notifications. Each entry contains:
signedPayload: Signature content of the original notificationsendAttempts: Send attempt records, up to 6 (1 initial send + 5 retries)
Migration path
(17:16) Migrate from verifyReceipt:
Old process:
Device -> receipt -> your server -> verifyReceipt -> Apple -> decoded receipt -> your server
New process:
Device -> transactionId -> your server -> App Store Server API -> signed transaction data
You no longer need to store base64 encoded receipts, just a transactionId.
Core Takeaways
-
Build a real-time subscription status dashboard
- What to build: Maintain a real-time subscription status dashboard on the server to support the customer service team to view user subscription status
- Why it’s worth doing: Notifications V2’s
statusfield makes status synchronization direct and reliable, no longer requiring complex inference logic - How to start: Set up the Notifications V2 receiving endpoint, parse the
statusfield in each notification, and update the user subscription status in the database
-
Implement intelligent notification recovery mechanism
- What to build: Integrate
onlyFailuresquery in the server health check process to automatically restore missed notifications - Why it’s worth doing: Network problems are inevitable,
onlyFailureschanges the missing recovery notification from “looking through history” to “precise positioning” - How to start: Call Get Notification History and pass in
onlyFailures: trueduring server startup or scheduled tasks to process the returned missing notifications
- What to build: Integrate
-
Simplified server-side transaction verification
- What to build: Use Get Transaction Info instead of Get Transaction History for single transaction verification
- Why it’s worth doing: The code is simpler, the response is faster, and it supports consumptive transaction verification
- How to start: Change the existing verification logic from “query history + search matching” to directly calling Get Transaction Info, passing in transactionId
-
Planning verifyReceipt migration
- What to build: Develop a migration plan from verifyReceipt to the App Store Server API
- Why it’s worth doing: verifyReceipt has been deprecated, and new functions will only be released in the JWS signature data system
- How to start: Use the App Store Server Library open source library to extract the transactionId from the receipt and gradually replace the verifyReceipt call
Related Sessions
- Explore testing in-app purchases — Learn how to test in-app purchases using StoreKit Testing, Sandbox, and TestFlight
- Meet the App Store Server Library — Apple’s official open source library, simplifying Server API calls and data verification
- What’s new in StoreKit 2 — New StoreKit 2 client features for use with the Server API
- Subscription Offers Best Practices — Design and implementation best practices for subscription offers
Comments
GitHub Issues · utterances